diff --git a/CODEOWNERS b/CODEOWNERS index 9cbda8244467..bceaafdbc07c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,8 +24,14 @@ /rust/ @github/codeql-rust /rust/extractor/ @github/codeql-rust @github/code-scanning-language-coverage /shared/ @github/codeql-shared-libraries-reviewers +/shared/cpp/ @github/code-scanning-language-coverage +/shared/yeast/ @github/code-scanning-language-coverage +/shared/yeast-macros/ @github/code-scanning-language-coverage +/shared/yeast-schema/ @github/code-scanning-language-coverage /swift/ @github/codeql-swift /swift/extractor/ @github/codeql-swift @github/code-scanning-language-coverage +/unified/extractor/ @github/code-scanning-language-coverage +/unified/swift-syntax-rs/ @github/code-scanning-language-coverage /misc/codegen/ @github/codeql-swift /java/kotlin-extractor/ @github/codeql-kotlin @github/code-scanning-language-coverage /java/ql/test-kotlin1/ @github/codeql-kotlin diff --git a/Cargo.lock b/Cargo.lock index 7a9f19667911..24479c721561 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,26 +140,6 @@ 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" @@ -270,15 +250,6 @@ 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" @@ -378,17 +349,6 @@ 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" @@ -491,9 +451,6 @@ dependencies = [ "serde_json", "tracing", "tracing-subscriber", - "tree-sitter", - "tree-sitter-embedded-template", - "tree-sitter-swift", "yeast", ] @@ -545,15 +502,6 @@ 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" @@ -807,12 +755,6 @@ 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" @@ -861,12 +803,6 @@ 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" @@ -951,18 +887,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "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", + "foldhash", ] [[package]] @@ -1167,15 +1092,6 @@ dependencies = [ "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" @@ -1305,16 +1221,6 @@ 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" @@ -1380,12 +1286,6 @@ 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" @@ -1432,16 +1332,6 @@ 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" @@ -1569,12 +1459,6 @@ 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" @@ -1633,35 +1517,6 @@ dependencies = [ "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]] name = "pin-project-lite" version = "0.2.16" @@ -1704,25 +1559,6 @@ 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" @@ -2426,15 +2262,6 @@ 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" @@ -2448,57 +2275,6 @@ 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" @@ -2804,18 +2580,6 @@ 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" @@ -2972,7 +2736,7 @@ dependencies = [ "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", - "toml_edit 0.22.27", + "toml_edit", ] [[package]] @@ -3008,15 +2772,6 @@ 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" @@ -3031,18 +2786,6 @@ dependencies = [ "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.1.2+spec-1.1.0" @@ -3064,12 +2807,6 @@ 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" @@ -3166,30 +2903,6 @@ 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" @@ -3236,15 +2949,6 @@ 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" @@ -3294,12 +2998,6 @@ 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" @@ -3694,9 +3392,6 @@ name = "winnow" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" -dependencies = [ - "memchr", -] [[package]] name = "wit-bindgen" diff --git a/Cargo.toml b/Cargo.toml index 9f3780bb1d77..21bde5432803 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "shared/yeast-schema", "ruby/extractor", "unified/extractor", - "unified/extractor/tree-sitter-swift", "unified/swift-syntax-rs", "rust/extractor", "rust/extractor/macros", diff --git a/MODULE.bazel b/MODULE.bazel index 24b1c757e37b..e8d49c11bcb4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,7 +19,7 @@ bazel_dep(name = "rules_cc", version = "0.2.17") bazel_dep(name = "rules_go", version = "0.60.0") bazel_dep(name = "rules_java", version = "9.6.1") bazel_dep(name = "rules_pkg", version = "1.2.0") -bazel_dep(name = "rules_nodejs", version = "6.7.3") +bazel_dep(name = "rules_nodejs", version = "6.7.5") bazel_dep(name = "rules_python", version = "1.9.0") bazel_dep(name = "rules_shell", version = "0.7.1") bazel_dep(name = "bazel_skylib", version = "1.9.0") @@ -109,7 +109,6 @@ 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", @@ -157,9 +156,7 @@ use_repo( "vendor_ts__tracing-subscriber-0.3.20", "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", @@ -322,17 +319,18 @@ go_sdk.download(version = "1.26.5") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//go/extractor:go.mod") -use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_tools") +use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_sys", "org_golang_x_tools") ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive") # go to https://github.com/GoogleChrome/ripunzip/releases to find latest version and corresponding sha256s ripunzip_archive( name = "ripunzip", - sha256_linux = "71482d7a7e4ea9176d5596161c49250c34b136b157c45f632b1111323fbfc0de", - sha256_macos_arm = "604194ab13f0aba3972995d995f11002b8fc285c8170401fcd46655065df20c9", - sha256_macos_intel = "65367b94fd579d93d46f2d2595cc4c9a60cfcf497e3c824f9d1a7b80fa8bd38a", - sha256_windows = "ac3874075def2b9e5074a3b5945005ab082cc6e689e1de658da8965bc23e643e", + sha256_linux_arm64 = "a282740ef376ff8dc0de3c589b7457598db15cc045b7daa688f15531612e0bbe", + sha256_linux_x64 = "71482d7a7e4ea9176d5596161c49250c34b136b157c45f632b1111323fbfc0de", + sha256_macos_arm64 = "604194ab13f0aba3972995d995f11002b8fc285c8170401fcd46655065df20c9", + sha256_macos_x64 = "65367b94fd579d93d46f2d2595cc4c9a60cfcf497e3c824f9d1a7b80fa8bd38a", + sha256_windows_x64 = "ac3874075def2b9e5074a3b5945005ab082cc6e689e1de658da8965bc23e643e", version = "2.0.4", ) diff --git a/actions/ql/integration-tests/query-suite/not_included_in_qls.expected b/actions/ql/integration-tests/query-suite/not_included_in_qls.expected index 6ed0a557462b..da088b688131 100644 --- a/actions/ql/integration-tests/query-suite/not_included_in_qls.expected +++ b/actions/ql/integration-tests/query-suite/not_included_in_qls.expected @@ -11,7 +11,6 @@ ql/actions/ql/src/experimental/Security/CWE-078/CommandInjectionMedium.ql ql/actions/ql/src/experimental/Security/CWE-088/ArgumentInjectionCritical.ql ql/actions/ql/src/experimental/Security/CWE-088/ArgumentInjectionMedium.ql ql/actions/ql/src/experimental/Security/CWE-200/SecretExfiltration.ql -ql/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql ql/actions/ql/src/experimental/Security/CWE-829/ArtifactPoisoningPathTraversal.ql ql/actions/ql/src/experimental/Security/CWE-829/UnversionedImmutableAction.ql ql/actions/ql/src/experimental/Security/CWE-918/RequestForgery.ql diff --git a/actions/ql/lib/CHANGELOG.md b/actions/ql/lib/CHANGELOG.md index 630b089310b9..ea32d9c07193 100644 --- a/actions/ql/lib/CHANGELOG.md +++ b/actions/ql/lib/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.5.0 + +### Breaking Changes + +* The `codeql.actions.security.SelfHostedQuery` module has been removed because runner labels do not reliably distinguish self-hosted runners from managed runners. + +### Minor Analysis Improvements + +* GitHub Actions analysis now recognizes untrusted data in `github.event.merge_group` for workflows triggered by the `merge_group` event. + ## 0.4.40 ### Minor Analysis Improvements diff --git a/actions/ql/lib/change-notes/released/0.5.0.md b/actions/ql/lib/change-notes/released/0.5.0.md new file mode 100644 index 000000000000..3e89301899bd --- /dev/null +++ b/actions/ql/lib/change-notes/released/0.5.0.md @@ -0,0 +1,9 @@ +## 0.5.0 + +### Breaking Changes + +* The `codeql.actions.security.SelfHostedQuery` module has been removed because runner labels do not reliably distinguish self-hosted runners from managed runners. + +### Minor Analysis Improvements + +* GitHub Actions analysis now recognizes untrusted data in `github.event.merge_group` for workflows triggered by the `merge_group` event. diff --git a/actions/ql/lib/codeql-pack.release.yml b/actions/ql/lib/codeql-pack.release.yml index 8f5be10acbe6..30e271c5361c 100644 --- a/actions/ql/lib/codeql-pack.release.yml +++ b/actions/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.40 +lastReleaseVersion: 0.5.0 diff --git a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll index 18cc4322c81b..8b0a2a33eb55 100644 --- a/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll +++ b/actions/ql/lib/codeql/actions/dataflow/FlowSources.qll @@ -52,29 +52,43 @@ class GitHubCtxSource extends RemoteFlowSource { override string getEventName() { result = event } } +bindingset[expression] +pragma[inline_late] +private predicate untrustedEventProperty(Expression expression, string kind) { + exists(string regexp | + untrustedEventPropertiesDataModel(regexp, kind) and + kind != "json" and + normalizeExpr(expression.getExpression()).regexpMatch("(?i)\\s*" + wrapRegexp(regexp) + ".*") + ) +} + +bindingset[expression, event] +pragma[inline_late] +private predicate expressionContainsEventContext(Expression expression, string event) { + exists(string contextPrefix | + contextTriggerDataModel(event, contextPrefix) and + normalizeExpr(expression.getExpression()).matches("%" + contextPrefix + "%") + ) +} + class GitHubEventCtxSource extends RemoteFlowSource { string flag; string context; string event; GitHubEventCtxSource() { - exists(Expression e, string regexp | + exists(Expression e | this.asExpr() = e and context = e.getExpression() and ( // the context is available for the job trigger events event = e.getATriggerEvent().getName() and - exists(string context_prefix | - contextTriggerDataModel(event, context_prefix) and - normalizeExpr(context).matches("%" + context_prefix + "%") - ) + expressionContainsEventContext(e, event) or not exists(e.getATriggerEvent()) and event = "unknown" ) and - untrustedEventPropertiesDataModel(regexp, flag) and - not flag = "json" and - normalizeExpr(context).regexpMatch("(?i)\\s*" + wrapRegexp(regexp) + ".*") + untrustedEventProperty(e, flag) ) } @@ -177,32 +191,41 @@ class GitHubEventPathSource extends RemoteFlowSource, CommandSource { override Run getEnclosingRun() { result = run } } +bindingset[expression, event] +pragma[inline_late] +private predicate jsonSourceForEvent(Expression expression, string event) { + exists(string context, string regexp, string contextPrefix | + context = expression.getExpression() and + untrustedEventPropertiesDataModel(regexp, _) and + contextTriggerDataModel(event, contextPrefix) and + normalizeExpr(context).matches("%" + contextPrefix + "%") and + normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp(regexp) + ".*") + ) + or + exists(string context | + context = expression.getExpression() and + untrustedEventPropertiesDataModel(_, _) and + contextTriggerDataModel(event, _) and + normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp("\\bgithub.event\\b") + ".*") + ) +} + class GitHubEventJsonSource extends RemoteFlowSource { string flag; string event; GitHubEventJsonSource() { - exists(Expression e, string context, string regexp | + exists(Expression e | this.asExpr() = e and - context = e.getExpression() and - untrustedEventPropertiesDataModel(regexp, _) and ( // only contexts for the triggering events are considered tainted. // eg: for `pull_request`, we only consider `github.event.pull_request` event = e.getEnclosingWorkflow().getATriggerEvent().getName() and - exists(string context_prefix | - contextTriggerDataModel(event, context_prefix) and - normalizeExpr(context).matches("%" + context_prefix + "%") - ) and - normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp(regexp) + ".*") - or - // github.event is tainted for all triggers - event = e.getEnclosingWorkflow().getATriggerEvent().getName() and - contextTriggerDataModel(e.getEnclosingWorkflow().getATriggerEvent().getName(), _) and - normalizeExpr(context).regexpMatch("(?i).*" + wrapJsonRegexp("\\bgithub.event\\b") + ".*") + jsonSourceForEvent(e, event) or not exists(e.getATriggerEvent()) and - event = "unknown" + event = "unknown" and + untrustedEventPropertiesDataModel(_, _) ) and flag = "json" ) diff --git a/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll b/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll index e5c5a3655101..41529c489ff0 100644 --- a/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CachePoisoningQuery.qll @@ -5,8 +5,8 @@ string defaultBranchTriggerEvent() { [ "check_run", "check_suite", "delete", "discussion", "discussion_comment", "fork", "gollum", "issue_comment", "issues", "label", "milestone", "project", "project_card", "project_column", - "public", "pull_request_comment", "pull_request_target", "repository_dispatch", "schedule", - "watch", "workflow_run" + "public", "pull_request_comment", "pull_request_target", "repository_dispatch", + "registry_package", "page_build", "schedule", "watch", "workflow_dispatch", "workflow_run" ] } @@ -42,6 +42,27 @@ predicate runsOnDefaultBranch(Event e) { ) } +private string defaultBranchCacheWriteEvent() { + result = + [ + "push", "workflow_dispatch", "repository_dispatch", "delete", "registry_package", + "page_build", "schedule" + ] +} + +private predicate eventHasDefaultBranchCacheWriteAccess(Event event) { + runsOnDefaultBranch(event) and event.getName() = defaultBranchCacheWriteEvent() +} + +/** + * Holds if `job` can write to the cache scope of the default branch for `event`. + * Reusable workflow jobs inherit their caller's trigger event. + */ +predicate hasDefaultBranchCacheWriteAccess(LocalJob job, Event event) { + job.getATriggerEvent() = event and + eventHasDefaultBranchCacheWriteAccess(event) +} + abstract class CacheWritingStep extends Step { abstract string getPath(); } diff --git a/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll index 3d5b8852b850..2afa68244091 100644 --- a/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll @@ -29,22 +29,10 @@ Event getRelevantCachePoisoningEventForSink(DataFlow::Node sink) { exists(LocalJob job | job = sink.asExpr().getEnclosingJob() and job.getATriggerEvent() = result and - // job can be triggered by an external user - result.isExternallyTriggerable() and // excluding privileged workflows since they can be exploited in easier circumstances // which is covered by `actions/code-injection/critical` not job.isPrivilegedExternallyTriggerable(result) and - ( - // the workflow runs in the context of the default branch - runsOnDefaultBranch(result) - or - // the workflow caller runs in the context of the default branch - result.getName() = "workflow_call" and - exists(ExternalJob caller | - caller.getCallee() = job.getLocation().getFile().getRelativePath() and - runsOnDefaultBranch(caller.getATriggerEvent()) - ) - ) + hasDefaultBranchCacheWriteAccess(job, result) ) } diff --git a/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll index 40810477d927..9c3d7363c0aa 100644 --- a/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll @@ -151,7 +151,7 @@ Event getRelevantNonArtifactEventInPrivilegedContext(DataFlow::Node sink) { private module EnvVarInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource and - not source.(RemoteFlowSource).getSourceType() = ["branch", "username"] + not source.(RemoteFlowSource).getSourceType() = ["branch", "label", "username"] } predicate isSink(DataFlow::Node sink) { sink instanceof EnvVarInjectionSink } diff --git a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll index 22b4879df126..57f0e31a25b4 100644 --- a/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll +++ b/actions/ql/lib/codeql/actions/security/OutputClobberingQuery.qll @@ -111,6 +111,43 @@ class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink { } } +private string jqSafeOptionRegexp() { + result = "-[acCMeRnSs]+" + or + result = + "--(ascii-output|color-output|compact-output|exit-status|monochrome-output|null-input|" + + "raw-input|slurp|sort-keys|unbuffered)" +} + +private string jqSimpleFilterRegexp() { + result = "\\." + or + result = "\\.[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*|\\[[0-9]+\\])*" +} + +private string jqSimpleFilterArgumentRegexp() { + result = jqSimpleFilterRegexp() + or + result = "'" + jqSimpleFilterRegexp() + "'" + or + result = "\"" + jqSimpleFilterRegexp() + "\"" +} + +private string jqLiteralInputRegexp() { + result = "[A-Za-z0-9_./][A-Za-z0-9_./-]*" + or + result = "\\$GITHUB_EVENT_PATH" + or + result = "\\$\\{GITHUB_EVENT_PATH\\}" +} + +bindingset[command] +private predicate jqProducesJsonEncodedOutput(string command) { + command + .regexpMatch("jq(\\s+" + jqSafeOptionRegexp() + ")*\\s+" + jqSimpleFilterArgumentRegexp() + + "(\\s+" + jqSafeOptionRegexp() + ")*(\\s+" + jqLiteralInputRegexp() + ")*") +} + /** * - id: clob1 * run: | @@ -159,13 +196,17 @@ class WorkflowCommandClobberingFromFileReadSink extends OutputClobberingSink { clobbering_cmd.regexpMatch(["ls", Bash::fileReadCommand()] + "\\s.*") and ( // - run: echo "foo=$(= 0 + ) or // A file content is printed to stdout // - run: cat pr-id.txt clobbering_stmt.indexOf(clobbering_cmd) = 0 ) - ) + ) and + not jqProducesJsonEncodedOutput(clobbering_cmd) ) } } diff --git a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll b/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll deleted file mode 100644 index 3a65771c1745..000000000000 --- a/actions/ql/lib/codeql/actions/security/SelfHostedQuery.qll +++ /dev/null @@ -1,47 +0,0 @@ -import actions - -bindingset[runner] -predicate isGithubHostedRunner(string runner) { - // The list of github hosted repos: - // https://github.com/actions/runner-images/blob/main/README.md#available-images - // https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#standard-github-hosted-runners-for-public-repositories - runner.toLowerCase().regexpMatch("^ubuntu-([0-9.]+|latest|slim)(-arm)?$") or - runner.toLowerCase().regexpMatch("^macos-([0-9]+|latest)(-x?large|-intel)?$") or - runner.toLowerCase().regexpMatch("^windows-([0-9.]+|latest)(-vs[0-9.]+)?(-arm)?$") -} - -bindingset[runner] -predicate is3rdPartyHostedRunner(string runner) { - runner.toLowerCase().regexpMatch("^(buildjet|warp)-[a-z0-9-]+$") -} - -/** - * This predicate uses data available in the workflow file to identify self-hosted runners. - * It does not know if the repository is public or private. - * It is a best-effort approach to identify self-hosted runners. - */ -predicate staticallyIdentifiedSelfHostedRunner(Job job) { - exists(string label | - job.getATriggerEvent().getName() = - [ - "issue_comment", "pull_request", "pull_request_review", "pull_request_review_comment", - "pull_request_target", "workflow_run" - ] and - label = job.getARunsOnLabel() and - not isGithubHostedRunner(label) and - not is3rdPartyHostedRunner(label) - ) -} - -/** - * This predicate uses data available in the job log files to identify self-hosted runners. - * It is a best-effort approach to identify self-hosted runners. - */ -predicate dynamicallyIdentifiedSelfHostedRunner(Job job) { - exists(string runner_info | - repositoryDataModel("public", _) and - workflowDataModel(job.getEnclosingWorkflow().getLocation().getFile().getRelativePath(), _, - job.getId(), _, _, runner_info) and - runner_info.indexOf("self-hosted:true") > 0 - ) -} diff --git a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll index 9668fce2ae00..bd8ec6f035e9 100644 --- a/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll +++ b/actions/ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll @@ -382,3 +382,50 @@ class GhSHACheckout extends SHACheckoutStep instanceof Run { override string getPath() { result = this.(Run).getWorkingDirectory() } } + +private predicate isRunCheckoutReference( + PRHeadCheckoutStep checkout, Expression reference, string variable +) { + reference = checkout.(Run).getInScopeEnvVarExpr(variable) and + ( + checkout instanceof SHACheckoutStep and containsHeadSHA(reference.getExpression()) + or + checkout instanceof MutableRefCheckoutStep and + ( + containsHeadRef(reference.getExpression()) or + containsPullRequestNumber(reference.getExpression()) + ) + ) and + exists(string command | + checkout.(Run).getScript().getACommand() = command and + exists(command.regexpFind(variable, _, _)) + ) +} + +/** Gets the expression that controls the untrusted checkout, if one can be identified. */ +AstNode getCheckoutReference(PRHeadCheckoutStep checkout) { + exists(UsesStep uses | uses = checkout | + result = uses.getArgumentExpr("ref") + or + not exists(uses.getArgumentExpr("ref")) and result = uses.getArgumentExpr("repository") + ) + or + isRunCheckoutReference(checkout, result, _) + or + checkout instanceof Run and + result = checkout and + not isRunCheckoutReference(checkout, _, _) +} + +/** Gets a display label for the expression that controls the untrusted checkout. */ +string getCheckoutReferenceText(AstNode reference) { + result = reference.(Expression).toString() + or + not reference instanceof Expression and result = "the checkout command" +} + +/** Adds checkout-reference provenance before the checkout step in path queries. */ +predicate checkoutReferenceEdge(AstNode predecessor, AstNode successor) { + predecessor = getCheckoutReference(successor) and + not predecessor = successor +} diff --git a/actions/ql/lib/ext/config/context_event_map.yml b/actions/ql/lib/ext/config/context_event_map.yml index 541ac8b9a8f6..311ea7cf5481 100644 --- a/actions/ql/lib/ext/config/context_event_map.yml +++ b/actions/ql/lib/ext/config/context_event_map.yml @@ -19,6 +19,7 @@ extensions: - ["gollum", "github.event.changes"] - ["pull_request_comment", "github.event.comment"] - ["pull_request_comment", "github.event.pull_request"] + - ["merge_group", "github.event.merge_group"] - ["pull_request_comment", "github.head_ref"] - ["pull_request_comment", "github.event.changes"] - ["pull_request_review", "github.event.pull_request"] diff --git a/actions/ql/lib/ext/config/externally_triggereable_events.yml b/actions/ql/lib/ext/config/externally_triggereable_events.yml index ae47c684095d..2a73f4f0a6db 100644 --- a/actions/ql/lib/ext/config/externally_triggereable_events.yml +++ b/actions/ql/lib/ext/config/externally_triggereable_events.yml @@ -17,4 +17,4 @@ extensions: - ["workflow_run"] # depending on branch filter - ["workflow_call"] # depending on caller - ["workflow_dispatch"] - - ["scheduled"] + - ["schedule"] diff --git a/actions/ql/lib/qlpack.yml b/actions/ql/lib/qlpack.yml index f581f735dd6a..859c7eb4a6f4 100644 --- a/actions/ql/lib/qlpack.yml +++ b/actions/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-all -version: 0.4.40 +version: 0.5.0 library: true warnOnImplicitThis: true dependencies: diff --git a/actions/ql/src/CHANGELOG.md b/actions/ql/src/CHANGELOG.md index bc013b962f80..84f8321799d8 100644 --- a/actions/ql/src/CHANGELOG.md +++ b/actions/ql/src/CHANGELOG.md @@ -1,3 +1,22 @@ +## 0.6.33 + +### Query Metadata Changes + +* The name and alert message of the `actions/cache-poisoning/code-injection` query have been reworded for clarity. + +### Minor Analysis Improvements + +* The `actions/output-clobbering/high` query no longer reports simple `jq` path filters when their output remains JSON-encoded. Raw-output modes, complex filters, and unrecognized options remain reportable. +* GitHub Actions queries now correctly classify the `schedule` event when determining whether a workflow is externally triggerable. +* The `actions/envvar-injection/critical` query now requires the untrusted source and privileged context to originate from the same trigger event. The environment variable injection queries also no longer treat pull request head labels as injection-capable because they cannot contain newlines. +* The `actions/cache-poisoning/code-injection`, `actions/cache-poisoning/direct-cache`, and `actions/cache-poisoning/poisonable-step` queries now account for read-only cache access on low-trust triggers that run in the default branch scope. Results are retained for triggers that GitHub allows to write to that cache scope. + +### Bug Fixes + +* The `actions/output-clobbering/high` query now provides messages tailored to the affected output channel and includes expanded documentation and recommendations. +* The `actions/cache-poisoning/poisonable-step` and `actions/untrusted-checkout/critical` queries now start paths at the expressions that control untrusted checkouts and link their alert messages to those expressions. +* Fixed a performance issue in the `actions/output-clobbering/high` query caused by using unescaped source-code input in a regular expression. + ## 0.6.32 No user-facing changes. diff --git a/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql b/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql index 6f0d9729d6d3..d6118075fa13 100644 --- a/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql +++ b/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql @@ -19,9 +19,16 @@ import codeql.actions.dataflow.FlowSources import EnvVarInjectionFlow::PathGraph import codeql.actions.security.ControlChecks +bindingset[source, event] +pragma[inline_late] +private predicate hasSameEventName(RemoteFlowSource source, Event event) { + source.getEventName() = event.getName() +} + from EnvVarInjectionFlow::PathNode source, EnvVarInjectionFlow::PathNode sink, Event event where EnvVarInjectionFlow::flowPath(source, sink) and + hasSameEventName(source.getNode(), event) and // exclude paths to file read sinks from non-artifact sources ( // source is text diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md index f75028a27e61..0ef3199e0fd9 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md @@ -34,48 +34,55 @@ Due to the above design, if something is cached in the context of the default br ## Example +GitHub gives workflows triggered by low-trust events, such as `issue_comment`, +`pull_request_target`, and `workflow_run`, read-only access to the default branch cache scope. +This query therefore reports only workflows whose trigger can write to that scope. + ### Incorrect Usage -The following workflow is vulnerable to code injection in a non-privileged job but in the context of the default branch. +The following workflow interpolates a commit message directly into a script on a push to the +default branch. A commit message originating from a merged contribution may contain shell syntax, +which can expose the cache write token and allow the default branch cache to be poisoned. ```yaml name: Vulnerable Workflow on: - issue_comment: - types: [created] + push: + branches: [main] jobs: - pr-comment: + build: permissions: {} runs-on: ubuntu-latest steps: - run: | - echo ${{ github.event.comment.body }} + echo ${{ github.event.head_commit.message }} ``` ### Correct Usage -The following workflow is not vulnerable to code injections even if it runs in the context of the default branch. +The following workflow passes the commit message through an environment variable, so the shell +does not interpret its contents as code. ```yaml name: Secure Workflow on: - issue_comment: - types: [created] + push: + branches: [main] jobs: - pr-comment: + build: permissions: {} runs-on: ubuntu-latest steps: - env: - BODY: ${{ github.event.comment.body }} + MESSAGE: ${{ github.event.head_commit.message }} run: | - echo "$BODY" + echo "$MESSAGE" ``` ## References - Adnan Khan's Blog: [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/). -- GitHub Docs: [GitHub Actions Caching Documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows). +- GitHub Docs: [Cache access for low-trust workflow triggers](https://docs.github.com/actions/reference/workflows-and-actions/dependency-caching#cache-access-for-low-trust-workflow-triggers). - Scribe Security Blog: [Cache Poisoning in GitHub Actions](https://scribesecurity.com/blog/github-cache-poisoning/). diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql index 2fe792aba1e6..c6d7ea9ccec3 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql @@ -1,5 +1,5 @@ /** - * @name Cache Poisoning via low-privileged code injection + * @name Cache Poisoning via code injection * @description The cache can be poisoned by untrusted code, leading to a cache poisoning attack. * @kind path-problem * @problem.severity error @@ -22,10 +22,11 @@ from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink, Event where CodeInjectionFlow::flowPath(source, sink) and event = getRelevantCachePoisoningEventForSink(sink.getNode()) and + source.getNode().(RemoteFlowSource).getEventName() = event.getName() and // the checkout is not controlled by an access check not exists(ControlCheck check | check.protects(source.getNode().asExpr(), event, "code-injection") ) select sink.getNode(), source, sink, - "Unprivileged code injection in $@, which may lead to cache poisoning ($@).", sink, + "Code injection in $@ may allow poisoning the default-branch cache (event trigger: $@).", sink, sink.getNode().asExpr().(Expression).getRawExpression(), event, event.getName() diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md index 849b771a8ff0..a22c41ad3e3a 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md @@ -34,35 +34,39 @@ Due to the above design, if something is cached in the context of the default br ## Example +GitHub gives workflows triggered by low-trust events, such as `issue_comment`, +`pull_request_target`, and `workflow_run`, read-only access to the default branch cache scope. +This query therefore reports only workflows whose trigger can write to that scope. + ### Incorrect Usage -The following workflow is caching an attacker-controlled file (`large_file`) in the context of the default branch. +The following write-capable manually dispatched workflow accepts a revision without validation, +fetches files from it, and saves those files in the default branch cache. This is unsafe if an +untrusted integration or automation can influence the dispatch input. ```yaml name: Vulnerable Workflow on: - issue_comment: - types: [created] + workflow_dispatch: + inputs: + head_sha: + required: true jobs: - pr-comment: + cache: permissions: read-all runs-on: ubuntu-latest steps: - - uses: xt0rted/pull-request-comment-branch@v2 - id: comment-branch - - uses: actions/checkout@v3 - with: - ref: ${{ steps.comment-branch.outputs.head_sha }} - - name: Set up Python 3.10 - uses: actions/setup-python@v5 - - name: Cache pip dependencies + - env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" + - name: Cache fetched files uses: actions/cache@v4 - id: cache-pip with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- + path: . + key: dispatched-${{ github.event.inputs.head_sha }} ``` ### Correct Usage @@ -91,36 +95,8 @@ jobs: restore-keys: ${{ runner.os }}-pip- ``` -Note, that the example above doesn't allow using secrets if the Pull Request originates from a fork. In case secrets are needed, `pull_request_target` with labels as `safe to test` can be used, but the code in Pull Request must be manually reviewed before applying the label. - -```yaml -name: Secure Workflow -on: - pull_request_target: - types: [labeled] - -jobs: - pr-comment: - if: contains(github.event.pull_request.labels.*.name, 'safe to test') - permissions: read-all - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha}} - - name: Set up Python 3.10 - uses: actions/setup-python@v5 - - name: Cache pip dependencies - uses: actions/cache@v4 - id: cache-pip - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- -``` - ## References - Adnan Khan's Blog: [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/). -- GitHub Docs: [GitHub Actions Caching Documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows). +- GitHub Docs: [Cache access for low-trust workflow triggers](https://docs.github.com/actions/reference/workflows-and-actions/dependency-caching#cache-access-for-low-trust-workflow-triggers). - Scribe Security Blog: [Cache Poisoning in GitHub Actions](https://scribesecurity.com/blog/github-cache-poisoning/). diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql index 85a0f53df1dc..b410f92b68a1 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaDirectCache.ql @@ -40,17 +40,7 @@ where job.getATriggerEvent() = event and // job can be triggered by an external user event.isExternallyTriggerable() and - ( - // the workflow runs in the context of the default branch - runsOnDefaultBranch(event) - or - // the workflow's caller runs in the context of the default branch - event.getName() = "workflow_call" and - exists(ExternalJob caller | - caller.getCallee() = job.getLocation().getFile().getRelativePath() and - runsOnDefaultBranch(caller.getATriggerEvent()) - ) - ) and + hasDefaultBranchCacheWriteAccess(job, event) and // the job writes to the cache // (No need to follow the checkout/download step since the cache is normally write after the job completes) job.getAStep() = step and diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md index fefd6d61a44d..e5fd868609c4 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md @@ -34,25 +34,35 @@ Due to the above design, if something is cached in the context of the default br ## Example +GitHub gives workflows triggered by low-trust events, such as `issue_comment`, +`pull_request_target`, and `workflow_run`, read-only access to the default branch cache scope. +This query therefore reports only workflows whose trigger can write to that scope. + ### Incorrect Usage -The following workflow runs untrusted code in a non-privileged job but in the context of the default branch. +The following write-capable manually dispatched workflow fetches an unvalidated revision and then +executes code from it. The executed code can use the cache token to poison the default branch cache +if an untrusted integration or automation can influence the dispatch input. ```yaml name: Vulnerable Workflow on: - pull_request_target: - branches: [main] -permissions: {} + workflow_dispatch: + inputs: + head_sha: + required: true jobs: test: + permissions: {} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} + - env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" - name: Run tests - run: ./run_tests.sh + run: npm install ``` ### Correct Usage @@ -79,5 +89,5 @@ jobs: ## References - Adnan Khan's Blog: [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/). -- GitHub Docs: [GitHub Actions Caching Documentation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows). +- GitHub Docs: [Cache access for low-trust workflow triggers](https://docs.github.com/actions/reference/workflows-and-actions/dependency-caching#cache-access-for-low-trust-workflow-triggers). - Scribe Security Blog: [Cache Poisoning in GitHub Actions](https://scribesecurity.com/blog/github-cache-poisoning/). diff --git a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql index 95adcfaf78ec..35dcb390e131 100644 --- a/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql +++ b/actions/ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.ql @@ -18,20 +18,30 @@ import codeql.actions.security.CachePoisoningQuery import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks -query predicate edges(Step a, Step b) { a.getNextStep() = b } +query predicate edges(AstNode predecessor, AstNode successor) { + predecessor.(Step).getNextStep() = successor + or + checkoutReferenceEdge(predecessor, successor) +} -from LocalJob job, Event event, Step source, Step step, string message, string path +from + LocalJob job, Event event, Step source, Step step, string message, string path, + AstNode untrustedInput, string untrustedInputText where // the job checkouts untrusted code from a pull request or downloads an untrusted artifact job.getAStep() = source and ( source instanceof PRHeadCheckoutStep and - message = "due to privilege checkout of untrusted code." and - path = source.(PRHeadCheckoutStep).getPath() + message = "due to privilege checkout of untrusted code from" and + path = source.(PRHeadCheckoutStep).getPath() and + untrustedInput = getCheckoutReference(source) and + untrustedInputText = getCheckoutReferenceText(untrustedInput) or source instanceof UntrustedArtifactDownloadStep and - message = "due to downloading an untrusted artifact." and - path = source.(UntrustedArtifactDownloadStep).getPath() + message = "due to downloading" and + path = source.(UntrustedArtifactDownloadStep).getPath() and + untrustedInput = source and + untrustedInputText = "an untrusted artifact" ) and // the checkout/download is not controlled by an access check not exists(ControlCheck check | @@ -40,23 +50,13 @@ where job.getATriggerEvent() = event and // job can be triggered by an external user event.isExternallyTriggerable() and - ( - // the workflow runs in the context of the default branch - runsOnDefaultBranch(event) - or - // the workflow's caller runs in the context of the default branch - event.getName() = "workflow_call" and - exists(ExternalJob caller | - caller.getCallee() = job.getLocation().getFile().getRelativePath() and - runsOnDefaultBranch(caller.getATriggerEvent()) - ) - ) and + hasDefaultBranchCacheWriteAccess(job, event) and // the job executes checked-out code // (The cache specific token can be leaked even for non-privileged workflows) source.getAFollowingStep() = step and step instanceof PoisonableStep and // excluding privileged workflows since they can be exploited in easier circumstances not job.isPrivileged() -select step, source, step, - "Potential cache poisoning in the context of the default branch " + message + " ($@).", event, - event.getName() +select step, untrustedInput, step, + "Potential cache poisoning in the context of the default branch " + message + " $@. ($@).", + untrustedInput, untrustedInputText, event, event.getName() diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql index e0af03ca3d02..4a05ef67117d 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql @@ -18,10 +18,18 @@ import codeql.actions.security.UntrustedCheckoutQuery import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks -query predicate edges(Step a, Step b) { a.getNextStep() = b } +query predicate edges(AstNode predecessor, AstNode successor) { + predecessor.(Step).getNextStep() = successor + or + checkoutReferenceEdge(predecessor, successor) +} -from PRHeadCheckoutStep checkout, PoisonableStep poisonable, Event event +from + PRHeadCheckoutStep checkout, PoisonableStep poisonable, Event event, AstNode checkoutReference, + string checkoutReferenceText where + checkoutReference = getCheckoutReference(checkout) and + checkoutReferenceText = getCheckoutReferenceText(checkoutReference) and // the checkout is followed by a known poisonable step checkout.getAFollowingStep() = poisonable and ( @@ -51,6 +59,6 @@ where event.getName() = checkoutTriggers() and not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) and not exists(ControlCheck check | check.protects(poisonable, event, "untrusted-checkout")) -select checkout, checkout, poisonable, - "Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@).", - event, event.getName() +select checkout, checkoutReference, poisonable, + "Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@).", + checkoutReference, checkoutReferenceText, event, event.getName() diff --git a/actions/ql/src/change-notes/released/0.6.33.md b/actions/ql/src/change-notes/released/0.6.33.md new file mode 100644 index 000000000000..86351b4c9158 --- /dev/null +++ b/actions/ql/src/change-notes/released/0.6.33.md @@ -0,0 +1,18 @@ +## 0.6.33 + +### Query Metadata Changes + +* The name and alert message of the `actions/cache-poisoning/code-injection` query have been reworded for clarity. + +### Minor Analysis Improvements + +* The `actions/output-clobbering/high` query no longer reports simple `jq` path filters when their output remains JSON-encoded. Raw-output modes, complex filters, and unrecognized options remain reportable. +* GitHub Actions queries now correctly classify the `schedule` event when determining whether a workflow is externally triggerable. +* The `actions/envvar-injection/critical` query now requires the untrusted source and privileged context to originate from the same trigger event. The environment variable injection queries also no longer treat pull request head labels as injection-capable because they cannot contain newlines. +* The `actions/cache-poisoning/code-injection`, `actions/cache-poisoning/direct-cache`, and `actions/cache-poisoning/poisonable-step` queries now account for read-only cache access on low-trust triggers that run in the default branch scope. Results are retained for triggers that GitHub allows to write to that cache scope. + +### Bug Fixes + +* The `actions/output-clobbering/high` query now provides messages tailored to the affected output channel and includes expanded documentation and recommendations. +* The `actions/cache-poisoning/poisonable-step` and `actions/untrusted-checkout/critical` queries now start paths at the expressions that control untrusted checkouts and link their alert messages to those expressions. +* Fixed a performance issue in the `actions/output-clobbering/high` query caused by using unescaped source-code input in a regular expression. diff --git a/actions/ql/src/codeql-pack.release.yml b/actions/ql/src/codeql-pack.release.yml index 6c5978280b02..ce257a8193e6 100644 --- a/actions/ql/src/codeql-pack.release.yml +++ b/actions/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.32 +lastReleaseVersion: 0.6.33 diff --git a/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md new file mode 100644 index 000000000000..cf8c086e097c --- /dev/null +++ b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.md @@ -0,0 +1,88 @@ +## Overview + +GitHub Actions steps communicate output values to the runner through a line-oriented command format. A step normally sets an output by appending a `name=value` record to the file referenced by `GITHUB_OUTPUT`. Multiline values use a delimiter-based form. Older workflows may instead emit `set-output` workflow commands to standard output. + +If attacker-controlled data is written to one of these command channels without validation, the data may be interpreted as command syntax rather than as a single value. An attacker can use newline characters, a matching multiline delimiter, or a forged workflow command to create additional outputs or overwrite output values that later steps expect to be trusted. + +The attacker-controlled data may come directly from an event, or indirectly from an untrusted checkout, downloaded artifact, file, or action output. Clobbered outputs can alter conditions and arguments in later steps. If a later step interpolates an injected output into a script, this issue may contribute to arbitrary code execution. + +## Recommendation + +Treat values from events, pull requests, artifacts, untrusted files, and third-party actions as untrusted. + +Before writing an untrusted value to `GITHUB_OUTPUT`, validate it against the narrow format required by the workflow. For example, require a pull request number to contain only decimal digits. For a single-line output, reject carriage-return and newline characters. Do not append an untrusted file directly to `GITHUB_OUTPUT`. + +Do not use the deprecated `set-output` workflow command. Migrate to `GITHUB_OUTPUT`, and avoid printing untrusted data while legacy workflow-command processing is enabled. + +For multiline values, use a random delimiter that cannot occur on a line by itself in the value. If the value is arbitrary, store it in a normal file instead of using the multiline command format, and pass only the validated file path as an output. + +Review the documentation and implementation of actions that consume untrusted inputs. Use only inputs that the action handles as data rather than as output-command syntax. + +## Example + +### Incorrect Usage + +The following step reads an attacker-controlled artifact file and writes its contents directly to `GITHUB_OUTPUT`. A newline in `pr-number.txt` can add another output record and overwrite `approved`. + +```yaml +- id: metadata + run: | + echo "approved=false" >> "$GITHUB_OUTPUT" + echo "pr_number=$(cat pr-number.txt)" >> "$GITHUB_OUTPUT" +``` + +For example, an attacker can provide a `pr-number.txt` artifact with the following contents: + +```text +123 +approved=true +``` + +The step appends the following records to `GITHUB_OUTPUT`: + +```text +approved=false +pr_number=123 +approved=true +``` + +The injected record replaces the expected `approved` output with the attacker-controlled value +`true`. + +Likewise, printing untrusted data to standard output can forge a legacy workflow command: + +```yaml +- id: metadata + env: + BODY: ${{ github.event.comment.body }} + run: | + echo "$BODY" + echo "::set-output name=approved::false" +``` + +### Correct Usage + +Validate the value before writing it to `GITHUB_OUTPUT`, and use a fixed output name with a single-line value: + +```yaml +- id: metadata + run: | + pr_number="$(cat pr-number.txt)" + if [[ ! "$pr_number" =~ ^[0-9]+$ ]]; then + echo "Invalid pull request number" >&2 + exit 1 + fi + printf 'pr_number=%s\n' "$pr_number" >> "$GITHUB_OUTPUT" +``` + +## References + +- GitHub Docs: [Workflow commands for GitHub Actions](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands). +- GitHub Docs: [Setting an output parameter](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#setting-an-output-parameter). +- GitHub Docs: [Multiline strings](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#multiline-strings). +- GitHub Changelog: [Deprecating `save-state` and `set-output` commands](https://github.blog/changelog/2022-10-10-github-actions-deprecating-save-state-and-set-output-commands/). +- GitHub Actions Toolkit: [`add-path` and `set-env` runner commands are processed via stdout](https://github.com/actions/toolkit/security/advisories/GHSA-mfwh-5m23-j46w). +- GitHub Security Lab: [New vulnerability patterns and mitigation strategies](https://securitylab.github.com/resources/github-actions-new-patterns-and-mitigations/). +- GitHub Security Lab: [Actions expression injection in Ant Design](https://securitylab.github.com/advisories/GHSL-2024-121_GHSL-2024-122_ant-design/). +- GitHub Security Lab: [Poisoned Pipeline Execution via code injection in SymPy](https://securitylab.github.com/advisories/GHSL-2024-322_Sympy/). +- Common Weakness Enumeration: [CWE-74](https://cwe.mitre.org/data/definitions/74.html). diff --git a/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql index 9c9c2e4d139a..a197ee2b244a 100644 --- a/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql +++ b/actions/ql/src/experimental/Security/CWE-074/OutputClobberingHigh.ql @@ -19,6 +19,42 @@ import codeql.actions.dataflow.FlowSources import OutputClobberingFlow::PathGraph import codeql.actions.security.ControlChecks +private predicate isEnvironmentFileSink(OutputClobberingFlow::PathNode sink) { + sink.getNode() instanceof OutputClobberingFromFileReadSink or + sink.getNode() instanceof OutputClobberingFromEnvVarSink +} + +private predicate isWorkflowCommandSink(OutputClobberingFlow::PathNode sink) { + sink.getNode() instanceof WorkflowCommandClobberingFromFileReadSink or + sink.getNode() instanceof WorkflowCommandClobberingFromEnvVarSink +} + +private string getMessage(OutputClobberingFlow::PathNode sink) { + isEnvironmentFileSink(sink) and + result = + "Attacker-controlled data may inject or overwrite step outputs written through " + + "`$GITHUB_OUTPUT` in $@." + or + not isEnvironmentFileSink(sink) and + isWorkflowCommandSink(sink) and + result = + "Attacker-controlled data printed to standard output may forge a `set-output` " + + "workflow command and overwrite step outputs in $@." + or + not isEnvironmentFileSink(sink) and + not isWorkflowCommandSink(sink) and + result = "Attacker-controlled data may inject or overwrite step outputs in $@." +} + +private string getSinkLabel(OutputClobberingFlow::PathNode sink) { + (isEnvironmentFileSink(sink) or isWorkflowCommandSink(sink)) and + result = "this step" + or + not isEnvironmentFileSink(sink) and + not isWorkflowCommandSink(sink) and + result = "this action" +} + from OutputClobberingFlow::PathNode source, OutputClobberingFlow::PathNode sink, Event event where OutputClobberingFlow::flowPath(source, sink) and @@ -40,5 +76,4 @@ where madSink(sink.getNode(), "output-clobbering") ) ) -select sink.getNode(), source, sink, "Potential clobbering of a step output in $@.", sink, - sink.getNode().toString() +select sink.getNode(), source, sink, getMessage(sink), sink, getSinkLabel(sink) diff --git a/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql b/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql deleted file mode 100644 index 9610302d1c2a..000000000000 --- a/actions/ql/src/experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Pull Request code execution on self-hosted runner - * @description Running untrusted code on a public repository's self-hosted runner can lead to the compromise of the runner machine - * @kind problem - * @problem.severity error - * @security-severity 9.0 - * @precision high - * @id actions/pr-on-self-hosted-runner - * @tags actions - * security - * experimental - * external/cwe/cwe-284 - */ - -import codeql.actions.security.SelfHostedQuery - -from Job job -where staticallyIdentifiedSelfHostedRunner(job) or dynamicallyIdentifiedSelfHostedRunner(job) -select job, "Job runs on self-hosted runner" diff --git a/actions/ql/src/qlpack.yml b/actions/ql/src/qlpack.yml index 6449c6f5a40a..648a6fb436fa 100644 --- a/actions/ql/src/qlpack.yml +++ b/actions/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/actions-queries -version: 0.6.32 +version: 0.6.33 library: false warnOnImplicitThis: true groups: [actions, queries] diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml new file mode 100644 index 000000000000..12f3016f5d07 --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/caller.yml @@ -0,0 +1,5 @@ +on: workflow_dispatch + +jobs: + call-reusable: + uses: ./.github/workflows/reusable.yml \ No newline at end of file diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml new file mode 100644 index 000000000000..f27aeb584fbd --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/.github/workflows/reusable.yml @@ -0,0 +1,7 @@ +on: workflow_call + +jobs: + build: + runs-on: ubuntu-latest + steps: + - run: echo build \ No newline at end of file diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/test.expected b/actions/ql/test/library-tests/reusable-workflow-callers/test.expected new file mode 100644 index 000000000000..4d2bad7a2bf1 --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/test.expected @@ -0,0 +1 @@ +| .github/workflows/reusable.yml:1:1:7:23 | on: workflow_call | .github/workflows/caller.yml:5:5:5:42 | Job: call-reusable | .github/workflows/reusable.yml:5:5:7:23 | Job: build | workflow_dispatch | diff --git a/actions/ql/test/library-tests/reusable-workflow-callers/test.ql b/actions/ql/test/library-tests/reusable-workflow-callers/test.ql new file mode 100644 index 000000000000..544db1647332 --- /dev/null +++ b/actions/ql/test/library-tests/reusable-workflow-callers/test.ql @@ -0,0 +1,9 @@ +import actions + +from ReusableWorkflow workflow, ExternalJob caller, LocalJob job, Event event +where + workflow.getACaller() = caller and + job.getEnclosingWorkflow() = workflow and + caller.getATriggerEvent() = event and + job.getATriggerEvent() = event +select workflow, caller, job, event.getName() diff --git a/actions/ql/test/output-clobbering.model.yml b/actions/ql/test/output-clobbering.model.yml new file mode 100644 index 000000000000..ef94ac69ac41 --- /dev/null +++ b/actions/ql/test/output-clobbering.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/actions-all + extensible: actionsSinkModel + data: + - ["actions/github-script", "*", "input.script", "output-clobbering", "manual"] diff --git a/actions/ql/test/qlpack.yml b/actions/ql/test/qlpack.yml index 139e8e57c62e..9c9e714fc67a 100644 --- a/actions/ql/test/qlpack.yml +++ b/actions/ql/test/qlpack.yml @@ -10,3 +10,5 @@ dependencies: extractor: actions tests: . warnOnImplicitThis: true +dataExtensions: + - output-clobbering.model.yml diff --git a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml index 614de61b0cb7..63298fdd57b2 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml +++ b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output2.yml @@ -60,3 +60,67 @@ jobs: CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }') echo "$CURRENT_VERSION" echo "::set-output name=OUTPUT::SAFE" + - id: clob5 + run: | + # NOT VULNERABLE: jq emits JSON-encoded strings by default + jq '.value' pr-number.json + - id: clob6 + run: | + # VULNERABLE: raw output can begin with a workflow command + jq -r '.value' pr-number.json + - id: clob7 + run: | + # VULNERABLE: long raw-output option after the filter + jq '.value' --raw-output pr-number.json + - id: clob8 + run: | + # VULNERABLE: combined short options include raw output + jq -Mcr '.value' pr-number.json + - id: clob9 + run: | + # NOT VULNERABLE: assigned jq output remains JSON encoded + VALUE=$(jq '.value' pr-number.json) + echo "$VALUE" + - id: clob10 + run: | + # VULNERABLE: assigned raw output can begin with a workflow command + VALUE=$(jq --raw-output '.value' pr-number.json) + echo "$VALUE" + - id: clob11 + run: | + # NOT VULNERABLE: combined options preserve JSON encoding + jq -Mc '.value' pr-number.json + - id: clob12 + run: | + # NOT VULNERABLE: safe long options may follow a simple filter + jq '.value' --compact-output pr-number.json + - id: clob13 + run: | + # VULNERABLE: join output emits strings without JSON encoding + jq -j '.value' pr-number.json + - id: clob14 + run: | + # VULNERABLE: the long join-output option also emits raw strings + jq '.value' --join-output pr-number.json + - id: clob15 + run: | + # VULNERABLE: raw-output0 emits strings without JSON encoding + jq '.value' --raw-output0 pr-number.json + - id: clob16 + run: | + # VULNERABLE: stderr emits its input without JSON encoding + jq '.value | stderr' pr-number.json + - id: clob17 + run: | + # VULNERABLE: halt_error emits its input without JSON encoding + jq '.value | halt_error(1)' pr-number.json + - id: clob18 + run: | + # VULNERABLE: the file name contains regex metacharacters + echo "VALUE=$(cat 'pr[number](final).txt')" + echo "::set-output name=OUTPUT::SAFE" + - id: clob19 + run: | + # VULNERABLE: echo is invoked through env + env echo "VALUE=$(cat 'pr[number](final).txt')" + echo "::set-output name=OUTPUT::SAFE" diff --git a/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml new file mode 100644 index 000000000000..15d31880422c --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-074/.github/workflows/output3.yml @@ -0,0 +1,10 @@ +on: + issue_comment: {} + +jobs: + modeled-action: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v7 + with: + script: ${{ github.event.comment.body }} diff --git a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected index af792f1ab65e..0b14b33d02e1 100644 --- a/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected +++ b/actions/ql/test/query-tests/Security/CWE-074/OutputClobberingHigh.expected @@ -7,6 +7,17 @@ edges | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | provenance | Config | | .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | +| .github/workflows/output2.yml:36:9:41:6 | Uses Step | .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | provenance | Config | nodes | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | semmle.label | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | @@ -21,13 +32,37 @@ nodes | .github/workflows/output2.yml:48:14:51:48 | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE\ncat pr-number\necho "::set-output name=OUTPUT::SAFE"\n | | .github/workflows/output2.yml:53:14:56:19 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | semmle.label | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\nls *.txt\n | | .github/workflows/output2.yml:58:14:62:48 | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE\nCURRENT_VERSION=$(cat gradle.properties \| sed -n '/^version=/ { s/^version=//;p }')\necho "$CURRENT_VERSION"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output2.yml:68:14:70:40 | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | semmle.label | # VULNERABLE: raw output can begin with a workflow command\njq -r '.value' pr-number.json\n | +| .github/workflows/output2.yml:72:14:74:50 | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | semmle.label | # VULNERABLE: long raw-output option after the filter\njq '.value' --raw-output pr-number.json\n | +| .github/workflows/output2.yml:76:14:78:42 | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | semmle.label | # VULNERABLE: combined short options include raw output\njq -Mcr '.value' pr-number.json\n | +| .github/workflows/output2.yml:85:14:88:24 | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | semmle.label | # VULNERABLE: assigned raw output can begin with a workflow command\nVALUE=$(jq --raw-output '.value' pr-number.json)\necho "$VALUE"\n | +| .github/workflows/output2.yml:98:14:100:40 | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | semmle.label | # VULNERABLE: join output emits strings without JSON encoding\njq -j '.value' pr-number.json\n | +| .github/workflows/output2.yml:102:14:104:51 | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | semmle.label | # VULNERABLE: the long join-output option also emits raw strings\njq '.value' --join-output pr-number.json\n | +| .github/workflows/output2.yml:106:14:108:51 | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | semmle.label | # VULNERABLE: raw-output0 emits strings without JSON encoding\njq '.value' --raw-output0 pr-number.json\n | +| .github/workflows/output2.yml:110:14:112:46 | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | semmle.label | # VULNERABLE: stderr emits its input without JSON encoding\njq '.value \| stderr' pr-number.json\n | +| .github/workflows/output2.yml:114:14:116:53 | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | semmle.label | # VULNERABLE: halt_error emits its input without JSON encoding\njq '.value \| halt_error(1)' pr-number.json\n | +| .github/workflows/output2.yml:118:14:121:48 | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE: the file name contains regex metacharacters\necho "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output2.yml:123:14:126:48 | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | semmle.label | # VULNERABLE: echo is invoked through env\nenv echo "VALUE=$(cat 'pr[number](final).txt')"\necho "::set-output name=OUTPUT::SAFE"\n | +| .github/workflows/output3.yml:10:20:10:51 | github.event.comment.body | semmle.label | github.event.comment.body | subpaths #select -| .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | -| .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:30:9:35:6 | Uses Step | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | Potential clobbering of a step output in $@. | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | -| .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | -| .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | .github/workflows/output2.yml:16:18:16:49 | github.event.comment.body | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | Potential clobbering of a step output in $@. | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | -| .github/workflows/output2.yml:42:14:46:48 | # VULNERABLE\nPR="$(> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | Attacker-controlled data may inject or overwrite step outputs written through `$GITHUB_OUTPUT` in $@. | .github/workflows/output1.yml:10:14:13:50 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$BODY" >> $GITHUB_OUTPUT\n | this step | +| .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | .github/workflows/output1.yml:30:9:35:6 | Uses Step | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | Attacker-controlled data may inject or overwrite step outputs written through `$GITHUB_OUTPUT` in $@. | .github/workflows/output1.yml:36:14:39:58 | # VULNERABLE\necho "OUTPUT_1=HARDCODED" >> $GITHUB_OUTPUT\necho "OUTPUT_2=$(> $GITHUB_OUTPUT\n | this step | +| .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | .github/workflows/output2.yml:9:18:9:49 | github.event.comment.body | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | Attacker-controlled data printed to standard output may forge a `set-output` workflow command and overwrite step outputs in $@. | .github/workflows/output2.yml:10:14:13:48 | # VULNERABLE\necho $BODY\necho "::set-output name=OUTPUT::SAFE"\n | this step | +| .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | .github/workflows/output2.yml:16:18:16:49 | github.event.comment.body | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | Attacker-controlled data printed to standard output may forge a `set-output` workflow command and overwrite step outputs in $@. | .github/workflows/output2.yml:17:14:20:21 | # VULNERABLE\necho "::set-output name=OUTPUT::SAFE"\necho $BODY\n | this step | +| .github/workflows/output2.yml:42:14:46:48 | # VULNERABLE\nPR="$(> $GITHUB_ENV + - name: Keep source and privilege events correlated + env: + BODY: ${{ github.event.pull_request.body }} + run: echo "BODY=$BODY" >> $GITHUB_ENV diff --git a/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml b/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml index 7b30ec8b7e42..9b12a7b05d29 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml +++ b/actions/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml @@ -66,6 +66,10 @@ jobs: ${TITLE} EOL echo REPO_NAME=$(cat issue.txt | sed 's/\r/\n/g' | grep -ioE '\s*[a-z0-9_-]+/[a-z0-9_-]+\s*$' | tr -d ' ') >> $GITHUB_ENV + - env: + LABEL: ${{ github.event.pull_request.head.label }} + run: | + echo "PR_LABEL=$LABEL" >> $GITHUB_ENV diff --git a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected index 9914ae91df12..ad79f6de12dd 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionCritical.expected @@ -29,6 +29,7 @@ edges | .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<> "$GITHUB_ENV"\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | provenance | Config | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | provenance | Config | nodes | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | semmle.label | Run Step | | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | semmle.label | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | @@ -91,6 +92,8 @@ nodes | .github/workflows/test16.yml:10:9:15:6 | Uses Step | semmle.label | Uses Step | | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | +| .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | semmle.label | echo "BODY=$BODY" >> $GITHUB_ENV | subpaths #select | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user ($@). | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | .github/workflows/artifactpoisoning51.yml:4:3:4:14 | workflow_run | workflow_run | diff --git a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected index 94e2af8ecaa7..9c1c5058f43a 100644 --- a/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected +++ b/actions/ql/test/query-tests/Security/CWE-077/EnvVarInjectionMedium.expected @@ -29,6 +29,7 @@ edges | .github/workflows/test12.yml:55:9:61:6 | Uses Step | .github/workflows/test12.yml:63:14:68:29 | {\n echo 'PRERELEASE_REPORT<> "$GITHUB_ENV"\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | provenance | Config | | .github/workflows/test16.yml:10:9:15:6 | Uses Step | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | provenance | Config | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | provenance | Config | nodes | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | semmle.label | Run Step | | .github/workflows/artifactpoisoning51.yml:19:14:20:57 | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | semmle.label | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV\n | @@ -91,5 +92,7 @@ nodes | .github/workflows/test16.yml:10:9:15:6 | Uses Step | semmle.label | Uses Step | | .github/workflows/test16.yml:15:14:17:63 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV\n | | .github/workflows/test16.yml:18:14:20:77 | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | semmle.label | # VULNERABLE\necho "PR_NUMBER=$(cat pr_number.txt \| tr ',' '\\n')" >> $GITHUB_ENV\n | +| .github/workflows/test18.yml:37:18:37:54 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | +| .github/workflows/test18.yml:38:14:38:45 | echo "BODY=$BODY" >> $GITHUB_ENV | semmle.label | echo "BODY=$BODY" >> $GITHUB_ENV | subpaths #select diff --git a/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml new file mode 100644 index 000000000000..02c9864bb7bf --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/merge_group_code_injection.yml @@ -0,0 +1,12 @@ +on: + merge_group: + types: [checks_requested] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Use merge group payload + run: echo '${{ toJSON(github.event) }}' + - name: Use merge group head ref + run: echo '${{ github.event.merge_group.head_ref }}' \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml new file mode 100644 index 000000000000..004a50f18e4d --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-094/.github/workflows/schedule_remote_code_injection.yml @@ -0,0 +1,19 @@ +on: + schedule: + - cron: "0 0 * * *" + +permissions: + contents: write + +jobs: + fetch-issues: + runs-on: ubuntu-latest + steps: + - name: Fetch open issues + id: issues + uses: octokit/request-action@v2.x + with: + route: GET /repos/foo/bar/issues?state=open + + - name: Write issues to file + run: echo '${{ steps.issues.outputs.data }}' > issues.json \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected index 9bf7e9aa56db..02f7f68c05f4 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected @@ -100,6 +100,7 @@ edges | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable-workflow.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | provenance | | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | provenance | | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | provenance | | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | provenance | | @@ -400,6 +401,8 @@ nodes | .github/workflows/level0.yml:44:20:44:49 | github.event.issue.body | semmle.label | github.event.issue.body | | .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | semmle.label | toJSON(github.event) | +| .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | semmle.label | github.event.merge_group.head_ref | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | | .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | @@ -460,6 +463,8 @@ nodes | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | semmle.label | Uses Step: issues | +| .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | semmle.label | steps.issues.outputs.data | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | semmle.label | steps.source.outputs.value | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | semmle.label | Uses Step: source [value] | @@ -777,6 +782,7 @@ subpaths | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | .github/workflows/reusable-workflow-caller-2.yml:4:3:4:21 | pull_request_target | pull_request_target | | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | ${{ env.log }} | .github/workflows/reusable-workflow-caller-2.yml:4:3:4:21 | pull_request_target | pull_request_target | | .github/workflows/reusable-workflow-2.yml:66:34:66:52 | env.prev_log | .github/workflows/reusable-workflow-2.yml:45:24:45:61 | github.event.changes.title.from | .github/workflows/reusable-workflow-2.yml:66:34:66:52 | env.prev_log | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/reusable-workflow-2.yml:66:34:66:52 | env.prev_log | ${{ env.prev_log }} | .github/workflows/reusable-workflow-caller-2.yml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | ${{ steps.issues.outputs.data }} | .github/workflows/schedule_remote_code_injection.yml:2:3:2:10 | schedule | schedule | | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | .github/workflows/self_needs.yml:16:20:16:57 | github.event['comment']['body'] | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | ${{ steps.source.outputs.value }} | .github/workflows/self_needs.yml:4:3:4:15 | issue_comment | issue_comment | | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | .github/workflows/self_needs.yml:16:20:16:57 | github.event['comment']['body'] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | ${{ needs.test1.outputs.job_output }} | .github/workflows/self_needs.yml:4:3:4:15 | issue_comment | issue_comment | | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | .github/workflows/simple2.yml:14:9:18:6 | Uses Step: source | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | Potential code injection in $@, which may be controlled by an external user ($@). | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | ${{ steps.step.outputs.value }} | .github/workflows/simple2.yml:3:6:3:24 | pull_request_target | pull_request_target | diff --git a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected index 4bbe7da0aaf3..231d41bc2518 100644 --- a/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected +++ b/actions/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected @@ -100,6 +100,7 @@ edges | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable-workflow.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | provenance | | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | provenance | | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | provenance | | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | provenance | | @@ -400,6 +401,8 @@ nodes | .github/workflows/level0.yml:44:20:44:49 | github.event.issue.body | semmle.label | github.event.issue.body | | .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | semmle.label | toJSON(github.event) | +| .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | semmle.label | github.event.merge_group.head_ref | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | | .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body | @@ -460,6 +463,8 @@ nodes | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-caller-3.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/schedule_remote_code_injection.yml:12:9:18:6 | Uses Step: issues | semmle.label | Uses Step: issues | +| .github/workflows/schedule_remote_code_injection.yml:19:21:19:52 | steps.issues.outputs.data | semmle.label | steps.issues.outputs.data | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | semmle.label | steps.source.outputs.value | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | semmle.label | Uses Step: source [value] | @@ -718,6 +723,8 @@ subpaths | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job2.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | .github/workflows/inter-job4.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} | +| .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/merge_group_code_injection.yml:10:21:10:47 | toJSON(github.event) | ${{ toJSON(github.event) }} | +| .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/merge_group_code_injection.yml:12:21:12:60 | github.event.merge_group.head_ref | ${{ github.event.merge_group.head_ref }} | | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | ${{ github.event.pull_request.body }} | | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | ${{ github.event.commits[11].message }} | | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | ${{ github.event.commits[11].author.email }} | diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml deleted file mode 100644 index 37eb2bddb58c..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test1.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: test - -on: - pull_request: - -jobs: - test1: - runs-on: [self-hosted, X64, Linux, 16c32g] - steps: - - run: cmd - test2: - runs-on: - group: my-group - labels: [self-hosted, label-1] - steps: - - run: cmd - test3: - runs-on: - - 'self-hosted' - - 'linux' - - 'x64' - - 'metal' - steps: - - run: echo "foo" - test4: - runs-on: self-hosted-azure - steps: - - run: cmd - test5: - strategy: - fail-fast: false - matrix: - platform: - - name: Linux - os: ubuntu-latest - shell: bash - - name: macOS - os: macos-latest - shell: bash - - name: Windows - os: windows-latest - shell: cmd - node-version: - - 16.14.0 - - 16.x - - 18.0.0 - - 18.x - - 20.x - runs-on: ${{ matrix.platform.os }} - steps: - - run: cmd - test6: - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - runs-on: ${{ matrix.os }} - steps: - - run: cmd - test7: - strategy: - matrix: - os: [self-hosted, ubuntu-latest] - runs-on: ${{ matrix.os }} - steps: - - run: cmd - test8: - strategy: - matrix: - settings: - - host: - - 'self-hosted' - - 'macos' - - 'arm64' - target: 'x86_64-apple-darwin' - runs-on: ${{ matrix.settings.host }} - steps: - - run: cmd - test9: - strategy: - matrix: - os: ${{ github.repository }} - runs-on: ${{ matrix.os }} - steps: - - run: cmd - test10: - strategy: - matrix: - os: ${{ github.repository }} - foo: - - bar: ${{ github.repository }} - baz: "asdf" - runs-on: ${{ matrix.foo.bar }} - steps: - - run: cmd diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml deleted file mode 100644 index 243bac925994..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test2.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: test - -on: - push: - -jobs: - test1: - runs-on: [self-hosted, foo] - steps: - - run: cmd - test2: - runs-on: - group: my-group - labels: [self-hosted, foo] - steps: - - run: cmd - test3: - runs-on: - - 'self-hosted' - - 'foo' - steps: - - run: cmd - test4: - runs-on: self-hosted-azure - steps: - - run: cmd diff --git a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml b/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml deleted file mode 100644 index b1fe9fa0caa6..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: test - -on: - pull_request: - -jobs: - test: - strategy: - fail-fast: false - matrix: - os: - - ubuntu-latest - - ubuntu-24.04 - - ubuntu-24.04-arm - - ubuntu-22.04 - - ubuntu-22.04-arm - - ubuntu-26.04 - - ubuntu-26.04-arm - - ubuntu-slim - - macos-26 - - macos-26-xlarge - - macos-26-intel - - macos-26-large - - macos-latest-large - - macos-15-large - - macos-15 - - macos-15-intel - - macos-latest - - macos-15 - - macos-15-xlarge - - macos-14-large - - macos-14 - - macos-14-xlarge - - windows-2025-vs2026 - - windows-latest - - windows-2025 - - windows-2022 - - windows-11 - - windows-11-arm - - windows-11-vs2026-arm - runs-on: ${{ matrix.os }} - steps: - - run: cmd diff --git a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected b/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected deleted file mode 100644 index 306bed9baec1..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.expected +++ /dev/null @@ -1,8 +0,0 @@ -| .github/workflows/test1.yml:8:5:11:2 | Job: test1 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:12:5:17:2 | Job: test2 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:18:5:25:2 | Job: test3 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:26:5:29:2 | Job: test4 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:60:5:66:2 | Job: test7 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:67:5:78:2 | Job: test8 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:79:5:85:2 | Job: test9 | Job runs on self-hosted runner | -| .github/workflows/test1.yml:86:5:94:15 | Job: test10 | Job runs on self-hosted runner | diff --git a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref b/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref deleted file mode 100644 index dc99068b3035..000000000000 --- a/actions/ql/test/query-tests/Security/CWE-284/CodeExecutionOnSelfHostedRunner.qlref +++ /dev/null @@ -1,2 +0,0 @@ -experimental/Security/CWE-284/CodeExecutionOnSelfHostedRunner.ql - diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml new file mode 100644 index 000000000000..b9fbe2d2d0b4 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_push.yml @@ -0,0 +1,10 @@ +on: + push: + branches: [main] + +jobs: + injection: + permissions: {} + runs-on: ubuntu-latest + steps: + - run: echo "${{ github.event.head_commit.message }}" \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml new file mode 100644 index 000000000000..99a474f99508 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow.yml @@ -0,0 +1,45 @@ +on: + workflow_call: + inputs: + head_sha: + required: false + type: string + +jobs: + direct-cache: + if: github.event_name == 'workflow_dispatch' + permissions: {} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - env: + HEAD_SHA: ${{ inputs.head_sha }} + run: | + [[ "$HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || exit 1 + git fetch origin "$HEAD_SHA" + git checkout --detach "$HEAD_SHA" + - uses: actions/cache@v4 + with: + path: .npm + key: reusable-direct-cache + + poisonable-step: + if: github.event_name == 'workflow_dispatch' + permissions: {} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - env: + HEAD_SHA: ${{ inputs.head_sha }} + run: | + [[ "$HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || exit 1 + git fetch origin "$HEAD_SHA" + git checkout --detach "$HEAD_SHA" + - run: npm install + + code-injection: + if: github.event_name == 'push' + permissions: {} + runs-on: ubuntu-latest + steps: + - run: echo "${{ github.event.head_commit.message }}" \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml new file mode 100644 index 000000000000..9f0f5841f89e --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_reusable_workflow_caller.yml @@ -0,0 +1,16 @@ +on: + push: + branches: [main] + workflow_dispatch: + inputs: + head_sha: + description: Commit SHA to test + required: true + type: string + +jobs: + reusable: + permissions: {} + uses: ./.github/workflows/cache_write_capable_reusable_workflow.yml + with: + head_sha: ${{ github.event.inputs.head_sha }} \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml new file mode 100644 index 000000000000..02bea71cfc61 --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch.yml @@ -0,0 +1,23 @@ +on: workflow_dispatch + +jobs: + cache: + permissions: {} + runs-on: ubuntu-latest + steps: + - id: pr + env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + jq -cn --arg sha "$HEAD_SHA" '{head: {sha: $sha}}' | + sed 's/^/json=/' >> "$GITHUB_OUTPUT" + - env: + HEAD_SHA: ${{ fromJSON(steps.pr.outputs.json).head.sha }} + run: | + git fetch origin "$HEAD_SHA" + git checkout "$HEAD_SHA" + - run: npm install + - uses: actions/cache@v4 + with: + path: .npm + key: workflow-dispatch diff --git a/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch_validated.yml b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch_validated.yml new file mode 100644 index 000000000000..0af4ad59ba4f --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-349/.github/workflows/cache_write_capable_workflow_dispatch_validated.yml @@ -0,0 +1,25 @@ +on: + workflow_dispatch: + inputs: + head_sha: + description: Commit SHA to test + required: true + type: string + +jobs: + cache: + permissions: {} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - env: + HEAD_SHA: ${{ github.event.inputs.head_sha }} + run: | + [[ "$HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || exit 1 + git fetch origin "$HEAD_SHA" + git checkout --detach "$HEAD_SHA" + - run: npm install + - uses: actions/cache@v4 + with: + path: .npm + key: workflow-dispatch \ No newline at end of file diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected index 9cfac091f675..86b2e48c25e0 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaCodeInjection.expected @@ -1,10 +1,13 @@ edges | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:21:16:70 | steps.modified_files.outputs.files_modified | provenance | | nodes +| .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | +| .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | semmle.label | github.event.comment.body | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | semmle.label | Uses Step: modified_files | | .github/workflows/code_injection2.yml:16:21:16:70 | steps.modified_files.outputs.files_modified | semmle.label | steps.modified_files.outputs.files_modified | | .github/workflows/neg_code_injection1.yml:11:17:11:48 | github.event.comment.body | semmle.label | github.event.comment.body | subpaths #select -| .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | Unprivileged code injection in $@, which may lead to cache poisoning ($@). | .github/workflows/code_injection1.yml:11:17:11:48 | github.event.comment.body | ${{ github.event.comment.body }} | .github/workflows/code_injection1.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | Code injection in $@ may allow poisoning the default-branch cache (event trigger: $@). | .github/workflows/cache_write_capable_push.yml:10:21:10:59 | github.event.head_commit.message | ${{ github.event.head_commit.message }} | .github/workflows/cache_write_capable_push.yml:2:3:2:6 | push | push | +| .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | Code injection in $@ may allow poisoning the default-branch cache (event trigger: $@). | .github/workflows/cache_write_capable_reusable_workflow.yml:45:21:45:59 | github.event.head_commit.message | ${{ github.event.head_commit.message }} | .github/workflows/cache_write_capable_reusable_workflow_caller.yml:2:3:2:6 | push | push | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected index 4cc8536b5943..7c7fc96dae52 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaDirectCache.expected @@ -1,4 +1,14 @@ edges +| .github/workflows/cache_write_capable_reusable_workflow.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:31:9:32:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:14:6 | Run Step: pr | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:20:9:23:33 | Uses Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:21:9:22:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:22:9:25:32 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | @@ -44,9 +54,6 @@ edges | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | .github/workflows/direct_cache2.yml:11:9:14:6 | Uses Step | .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache2.yml:3:5:3:23 | pull_request_target | pull_request_target | -| .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache3.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache4.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache4.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache5.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache5.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/direct_cache6.yml:20:9:26:46 | Uses Step: cache-pip | .github/workflows/direct_cache6.yml:13:9:16:6 | Uses Step | .github/workflows/direct_cache6.yml:20:9:26:46 | Uses Step: cache-pip | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/direct_cache6.yml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_reusable_workflow_caller.yml:4:3:4:19 | workflow_dispatch | workflow_dispatch | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:20:9:23:33 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:20:9:23:33 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:1:5:1:21 | workflow_dispatch | workflow_dispatch | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:22:9:25:32 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:22:9:25:32 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:2:3:2:19 | workflow_dispatch | workflow_dispatch | diff --git a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected index 6b1a3e873134..59ad18242986 100644 --- a/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected +++ b/actions/ql/test/query-tests/Security/CWE-349/CachePoisoningViaPoisonableStep.expected @@ -1,22 +1,44 @@ edges +| .github/workflows/cache_write_capable_reusable_workflow.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:21:9:26:2 | Uses Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:16:22:16:43 | inputs.head_sha | .github/workflows/cache_write_capable_reusable_workflow.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:31:9:32:6 | Uses Step | .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | +| .github/workflows/cache_write_capable_reusable_workflow.yml:33:22:33:43 | inputs.head_sha | .github/workflows/cache_write_capable_reusable_workflow.yml:32:9:38:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:8:9:14:6 | Run Step: pr | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:15:22:15:68 | fromJSON(steps.pr.outputs.json).head.sha | .github/workflows/cache_write_capable_workflow_dispatch.yml:14:9:19:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:20:9:23:33 | Uses Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:14:9:15:6 | Uses Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:15:9:21:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:21:9:22:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:16:22:16:56 | github.event.inputs.head_sha | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:15:9:21:6 | Run Step | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:22:9:25:32 | Uses Step | | .github/workflows/code_injection2.yml:12:9:16:6 | Uses Step: modified_files | .github/workflows/code_injection2.yml:16:9:16:71 | Run Step | | .github/workflows/direct_cache1.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | +| .github/workflows/direct_cache1.yml:16:17:16:60 | steps.comment-branch.outputs.head_sha | .github/workflows/direct_cache1.yml:13:9:18:6 | Uses Step | | .github/workflows/direct_cache1.yml:18:9:22:6 | Uses Step | .github/workflows/direct_cache1.yml:22:9:23:21 | Run Step | | .github/workflows/direct_cache2.yml:11:9:14:6 | Uses Step | .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | +| .github/workflows/direct_cache2.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache2.yml:11:9:14:6 | Uses Step | | .github/workflows/direct_cache2.yml:14:9:18:6 | Uses Step | .github/workflows/direct_cache2.yml:18:9:19:21 | Run Step | | .github/workflows/direct_cache3.yml:11:9:14:6 | Uses Step: comment-branch | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | +| .github/workflows/direct_cache3.yml:17:17:17:60 | steps.comment-branch.outputs.head_sha | .github/workflows/direct_cache3.yml:14:9:19:6 | Uses Step | | .github/workflows/direct_cache3.yml:19:9:23:6 | Uses Step | .github/workflows/direct_cache3.yml:23:9:24:21 | Run Step | | .github/workflows/direct_cache4.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | +| .github/workflows/direct_cache4.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache4.yml:14:9:17:6 | Uses Step | | .github/workflows/direct_cache4.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache4.yml:21:9:22:21 | Run Step | | .github/workflows/direct_cache5.yml:14:9:17:6 | Uses Step | .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | +| .github/workflows/direct_cache5.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache5.yml:14:9:17:6 | Uses Step | | .github/workflows/direct_cache5.yml:17:9:21:6 | Uses Step | .github/workflows/direct_cache5.yml:21:9:22:21 | Run Step | | .github/workflows/direct_cache6.yml:13:9:16:6 | Uses Step | .github/workflows/direct_cache6.yml:16:9:20:6 | Uses Step | +| .github/workflows/direct_cache6.yml:15:17:15:57 | github.event.pull_request.head.sha | .github/workflows/direct_cache6.yml:13:9:16:6 | Uses Step | | .github/workflows/direct_cache6.yml:16:9:20:6 | Uses Step | .github/workflows/direct_cache6.yml:20:9:26:46 | Uses Step: cache-pip | | .github/workflows/neg_direct_cache1.yml:14:9:17:6 | Uses Step | .github/workflows/neg_direct_cache1.yml:17:9:21:6 | Uses Step | +| .github/workflows/neg_direct_cache1.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/neg_direct_cache1.yml:14:9:17:6 | Uses Step | | .github/workflows/neg_direct_cache1.yml:17:9:21:6 | Uses Step | .github/workflows/neg_direct_cache1.yml:21:9:22:21 | Run Step | | .github/workflows/neg_direct_cache2.yml:14:9:17:6 | Uses Step | .github/workflows/neg_direct_cache2.yml:17:9:21:6 | Uses Step | +| .github/workflows/neg_direct_cache2.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/neg_direct_cache2.yml:14:9:17:6 | Uses Step | | .github/workflows/neg_direct_cache2.yml:17:9:21:6 | Uses Step | .github/workflows/neg_direct_cache2.yml:21:9:22:21 | Run Step | | .github/workflows/neg_direct_cache3.yml:13:9:14:6 | Uses Step | .github/workflows/neg_direct_cache3.yml:14:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache3.yml:14:9:18:6 | Uses Step | .github/workflows/neg_direct_cache3.yml:18:9:25:6 | Uses Step: cache-pip | @@ -24,30 +46,36 @@ edges | .github/workflows/neg_direct_cache3.yml:25:9:30:6 | Uses Step | .github/workflows/neg_direct_cache3.yml:30:9:35:36 | Uses Step | | .github/workflows/neg_direct_cache4.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/neg_direct_cache4.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache4.yml:13:9:18:6 | Uses Step | .github/workflows/neg_direct_cache4.yml:18:9:22:6 | Uses Step | +| .github/workflows/neg_direct_cache4.yml:16:17:16:60 | steps.comment-branch.outputs.head_sha | .github/workflows/neg_direct_cache4.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache4.yml:18:9:22:6 | Uses Step | .github/workflows/neg_direct_cache4.yml:22:9:23:21 | Run Step | | .github/workflows/neg_direct_cache5.yml:10:9:13:6 | Uses Step: comment-branch | .github/workflows/neg_direct_cache5.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache5.yml:13:9:18:6 | Uses Step | .github/workflows/neg_direct_cache5.yml:18:9:22:6 | Uses Step | +| .github/workflows/neg_direct_cache5.yml:16:17:16:60 | steps.comment-branch.outputs.head_sha | .github/workflows/neg_direct_cache5.yml:13:9:18:6 | Uses Step | | .github/workflows/neg_direct_cache5.yml:18:9:22:6 | Uses Step | .github/workflows/neg_direct_cache5.yml:22:9:23:21 | Run Step | | .github/workflows/neg_poisonable_step1.yml:11:9:14:6 | Uses Step: comment-branch | .github/workflows/neg_poisonable_step1.yml:14:9:19:6 | Uses Step | | .github/workflows/neg_poisonable_step1.yml:14:9:19:6 | Uses Step | .github/workflows/neg_poisonable_step1.yml:19:9:20:30 | Run Step | +| .github/workflows/neg_poisonable_step1.yml:17:17:17:60 | steps.comment-branch.outputs.head_sha | .github/workflows/neg_poisonable_step1.yml:14:9:19:6 | Uses Step | | .github/workflows/neg_poisonable_step2.yml:13:9:16:6 | Uses Step | .github/workflows/neg_poisonable_step2.yml:16:9:17:54 | Run Step | | .github/workflows/poisonable_step1.yml:10:9:12:6 | Uses Step: comment-branch | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | +| .github/workflows/poisonable_step1.yml:14:17:14:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | | .github/workflows/poisonable_step1.yml:21:9:23:6 | Uses Step: comment-branch | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | +| .github/workflows/poisonable_step1.yml:25:17:25:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | | .github/workflows/poisonable_step1.yml:32:9:34:6 | Uses Step: comment-branch | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | +| .github/workflows/poisonable_step1.yml:36:17:36:60 | steps.comment-branch.outputs.head_sha | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:20:9:22:6 | Uses Step | +| .github/workflows/poisonable_step2.yml:18:17:18:57 | github.event.pull_request.head.ref | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | | .github/workflows/poisonable_step2.yml:20:9:22:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | +| .github/workflows/poisonable_step3.yml:16:15:16:55 | github.event.pull_request.head.ref | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | +| .github/workflows/poisonable_step4.yml:16:17:16:57 | github.event.pull_request.head.sha | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | +| .github/workflows/poisonable_step5.yml:20:17:20:57 | github.event.pull_request.head.ref | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | | .github/workflows/poisonable_step5.yml:22:9:24:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | #select -| .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | .github/workflows/poisonable_step1.yml:12:9:15:6 | Uses Step | .github/workflows/poisonable_step1.yml:15:9:17:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | .github/workflows/poisonable_step1.yml:23:9:26:6 | Uses Step | .github/workflows/poisonable_step1.yml:26:9:28:2 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | .github/workflows/poisonable_step1.yml:34:9:37:6 | Uses Step | .github/workflows/poisonable_step1.yml:37:9:37:75 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step1.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | .github/workflows/poisonable_step2.yml:15:9:20:6 | Uses Step | .github/workflows/poisonable_step2.yml:22:9:26:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step2.yml:5:3:5:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | .github/workflows/poisonable_step3.yml:13:7:19:4 | Uses Step | .github/workflows/poisonable_step3.yml:19:7:19:32 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step3.yml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | .github/workflows/poisonable_step4.yml:13:9:18:6 | Uses Step | .github/workflows/poisonable_step4.yml:18:9:18:19 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step4.yml:3:3:3:21 | pull_request_target | pull_request_target | -| .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | .github/workflows/poisonable_step5.yml:17:9:22:6 | Uses Step | .github/workflows/poisonable_step5.yml:24:9:28:31 | Uses Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code. ($@). | .github/workflows/poisonable_step5.yml:3:3:3:21 | pull_request_target | pull_request_target | +| .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | .github/workflows/cache_write_capable_reusable_workflow.yml:33:22:33:43 | inputs.head_sha | .github/workflows/cache_write_capable_reusable_workflow.yml:38:9:40:2 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/cache_write_capable_reusable_workflow.yml:33:22:33:43 | inputs.head_sha | inputs.head_sha | .github/workflows/cache_write_capable_reusable_workflow_caller.yml:4:3:4:19 | workflow_dispatch | workflow_dispatch | +| .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:22:15:68 | fromJSON(steps.pr.outputs.json).head.sha | .github/workflows/cache_write_capable_workflow_dispatch.yml:19:9:20:6 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/cache_write_capable_workflow_dispatch.yml:15:22:15:68 | fromJSON(steps.pr.outputs.json).head.sha | fromJSON(steps.pr.outputs.json).head.sha | .github/workflows/cache_write_capable_workflow_dispatch.yml:1:5:1:21 | workflow_dispatch | workflow_dispatch | +| .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:21:9:22:6 | Run Step | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:16:22:16:56 | github.event.inputs.head_sha | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:21:9:22:6 | Run Step | Potential cache poisoning in the context of the default branch due to privilege checkout of untrusted code from $@. ($@). | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:16:22:16:56 | github.event.inputs.head_sha | github.event.inputs.head_sha | .github/workflows/cache_write_capable_workflow_dispatch_validated.yml:2:3:2:19 | workflow_dispatch | workflow_dispatch | diff --git a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected index b6c349bd64fe..910d5742e572 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected @@ -1,5 +1,6 @@ edges | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:11:7:12:18 | Run Step | +| .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | | .github/actions/dangerous-git-checkout/action.yml:11:7:12:18 | Run Step | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | | .github/actions/download-artifact-2/action.yaml:6:7:25:4 | Uses Step | .github/actions/download-artifact-2/action.yaml:25:7:29:4 | Run Step | | .github/actions/download-artifact-2/action.yaml:25:7:29:4 | Run Step | .github/actions/download-artifact-2/action.yaml:29:7:32:18 | Run Step | @@ -10,6 +11,7 @@ edges | .github/actions/download-artifact/action.yaml:29:7:32:18 | Run Step | .github/workflows/resolve-args.yml:22:9:36:13 | Run Step: resolve-step | | .github/actions/unpinned-tag/action.yml:5:7:6:4 | Uses Step | .github/actions/unpinned-tag/action.yml:6:7:6:61 | Uses Step | | .github/workflows/actor_trusted_checkout.yml:9:7:14:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:14:7:15:4 | Uses Step | +| .github/workflows/actor_trusted_checkout.yml:12:15:12:55 | github.event.pull_request.head.sha | .github/workflows/actor_trusted_checkout.yml:9:7:14:4 | Uses Step | | .github/workflows/actor_trusted_checkout.yml:14:7:15:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:15:7:19:4 | Run Step | | .github/workflows/actor_trusted_checkout.yml:15:7:19:4 | Run Step | .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | | .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:23:7:26:21 | Uses Step | @@ -35,6 +37,7 @@ edges | .github/workflows/artifactpoisoning53.yml:15:9:18:6 | Run Step | .github/workflows/artifactpoisoning53.yml:18:9:23:29 | Run Step | | .github/workflows/artifactpoisoning71.yml:9:9:16:6 | Uses Step | .github/workflows/artifactpoisoning71.yml:16:9:18:40 | Run Step | | .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:14:9:16:6 | Run Step | +| .github/workflows/artifactpoisoning81.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | | .github/workflows/artifactpoisoning81.yml:14:9:16:6 | Run Step | .github/workflows/artifactpoisoning81.yml:16:9:22:2 | Uses Step | | .github/workflows/artifactpoisoning81.yml:28:9:31:6 | Uses Step | .github/workflows/artifactpoisoning81.yml:31:9:31:28 | Run Step | | .github/workflows/artifactpoisoning82.yml:11:9:14:6 | Uses Step | .github/workflows/artifactpoisoning82.yml:14:9:16:6 | Run Step | @@ -64,12 +67,14 @@ edges | .github/workflows/artifactpoisoning97.yml:13:9:19:6 | Uses Step | .github/workflows/artifactpoisoning97.yml:19:9:19:25 | Run Step | | .github/workflows/artifactpoisoning101.yml:10:9:16:6 | Uses Step | .github/workflows/artifactpoisoning101.yml:16:9:19:59 | Run Step: pr_number | | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:27:9:32:6 | Uses Step | +| .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | | .github/workflows/auto_ci.yml:27:9:32:6 | Uses Step | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | .github/workflows/auto_ci.yml:37:9:40:6 | Run Step | | .github/workflows/auto_ci.yml:37:9:40:6 | Run Step | .github/workflows/auto_ci.yml:40:9:44:6 | Run Step | | .github/workflows/auto_ci.yml:40:9:44:6 | Run Step | .github/workflows/auto_ci.yml:44:9:48:6 | Run Step | | .github/workflows/auto_ci.yml:44:9:48:6 | Run Step | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:74:9:79:6 | Uses Step | +| .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | | .github/workflows/auto_ci.yml:74:9:79:6 | Uses Step | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | .github/workflows/auto_ci.yml:93:9:96:6 | Uses Step | @@ -85,47 +90,72 @@ edges | .github/workflows/dependabot1.yml:31:9:34:6 | Run Step | .github/workflows/dependabot1.yml:34:9:36:2 | Run Step | | .github/workflows/dependabot1.yml:39:9:43:6 | Uses Step | .github/workflows/dependabot1.yml:43:9:45:29 | Uses Step | | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | .github/workflows/dependabot2.yml:38:9:42:6 | Run Step: nvm | +| .github/workflows/dependabot2.yml:35:17:35:57 | github.event.pull_request.head.ref | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | | .github/workflows/dependabot2.yml:38:9:42:6 | Run Step: nvm | .github/workflows/dependabot2.yml:42:9:47:6 | Uses Step | | .github/workflows/dependabot2.yml:42:9:47:6 | Uses Step | .github/workflows/dependabot2.yml:47:9:52:6 | Run Step | | .github/workflows/dependabot2.yml:47:9:52:6 | Run Step | .github/workflows/dependabot2.yml:52:9:58:6 | Run Step | | .github/workflows/dependabot2.yml:52:9:58:6 | Run Step | .github/workflows/dependabot2.yml:58:9:61:6 | Run Step | | .github/workflows/dependabot2.yml:58:9:61:6 | Run Step | .github/workflows/dependabot2.yml:61:9:68:19 | Run Step | | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:20:9:25:6 | Uses Step | +| .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | | .github/workflows/dependabot3.yml:20:9:25:6 | Uses Step | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | .github/workflows/dependabot3.yml:48:9:52:57 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml:11:9:19:6 | Uses Step: checkAccess | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build_nested_branching.yml:19:9:25:2 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:14:9:19:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:19:9:25:6 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:19:9:25:6 | Run Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/formal.yml:25:9:70:20 | Run Step | | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:18:11:21:8 | Uses Step | +| .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | | .github/workflows/gitcheckout.yml:18:11:21:8 | Uses Step | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | | .github/workflows/issue_comment_3rd_party_action.yml:12:9:16:6 | Uses Step: comment-branch | .github/workflows/issue_comment_3rd_party_action.yml:16:9:22:2 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:20:17:20:60 | steps.comment-branch.outputs.head_sha | .github/workflows/issue_comment_3rd_party_action.yml:16:9:22:2 | Uses Step | | .github/workflows/issue_comment_3rd_party_action.yml:25:9:30:6 | Uses Step: comment-branch | .github/workflows/issue_comment_3rd_party_action.yml:30:9:36:2 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:34:17:34:60 | steps.comment-branch.outputs.head_ref | .github/workflows/issue_comment_3rd_party_action.yml:30:9:36:2 | Uses Step | | .github/workflows/issue_comment_3rd_party_action.yml:39:9:45:6 | Uses Step: refs | .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | | .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | .github/workflows/issue_comment_3rd_party_action.yml:49:9:52:25 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:47:17:47:50 | steps.refs.outputs.head_ref | .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | +| .github/workflows/issue_comment_3rd_party_action.yml:51:17:51:50 | steps.refs.outputs.head_sha | .github/workflows/issue_comment_3rd_party_action.yml:49:9:52:25 | Uses Step | +| .github/workflows/issue_comment_direct.yml:15:17:15:76 | github.event.pull_request.head.ref \|\| github.head_ref | .github/workflows/issue_comment_direct.yml:12:9:16:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:22:27:22:58 | github.event.issue.number | .github/workflows/issue_comment_direct.yml:20:9:24:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:30:17:30:79 | format('refs/pull/{0}/merge', github.event.issue.number) | .github/workflows/issue_comment_direct.yml:28:9:32:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:38:17:38:149 | (github.event_name == 'pull_request_review_comment') && format('refs/pull/{0}/merge', github.event.pull_request.number) \|\| '' | .github/workflows/issue_comment_direct.yml:35:9:40:2 | Uses Step | +| .github/workflows/issue_comment_direct.yml:46:17:46:126 | github.event_name == 'issue_comment' && format('refs/pull/{0}/merge', github.event.issue.number) \|\| '' | .github/workflows/issue_comment_direct.yml:43:9:46:126 | Uses Step | | .github/workflows/issue_comment_heuristic.yml:11:9:24:6 | Uses Step: get-pr-info | .github/workflows/issue_comment_heuristic.yml:24:9:28:6 | Run Step: get-sha | | .github/workflows/issue_comment_heuristic.yml:24:9:28:6 | Run Step: get-sha | .github/workflows/issue_comment_heuristic.yml:28:9:33:2 | Uses Step | +| .github/workflows/issue_comment_heuristic.yml:31:17:31:48 | steps.get-sha.outputs.sha | .github/workflows/issue_comment_heuristic.yml:28:9:33:2 | Uses Step | | .github/workflows/issue_comment_heuristic.yml:37:7:48:4 | Run Step: vars | .github/workflows/issue_comment_heuristic.yml:48:7:50:46 | Uses Step | +| .github/workflows/issue_comment_heuristic.yml:50:15:50:46 | steps.vars.outputs.branch | .github/workflows/issue_comment_heuristic.yml:48:7:50:46 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:12:9:19:6 | Uses Step: fetch_issue | .github/workflows/issue_comment_octokit2.yml:19:9:26:6 | Uses Step: fetch_pr | | .github/workflows/issue_comment_octokit2.yml:19:9:26:6 | Uses Step: fetch_pr | .github/workflows/issue_comment_octokit2.yml:26:9:27:6 | name: C ... ildcard | | .github/workflows/issue_comment_octokit2.yml:26:9:27:6 | name: C ... ildcard | .github/workflows/issue_comment_octokit2.yml:27:9:31:6 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:27:9:31:6 | Uses Step | .github/workflows/issue_comment_octokit2.yml:31:9:33:6 | Uses Step | +| .github/workflows/issue_comment_octokit2.yml:29:17:29:69 | fromJson(steps.fetch_pr.outputs.data).head.ref | .github/workflows/issue_comment_octokit2.yml:27:9:31:6 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:31:9:33:6 | Uses Step | .github/workflows/issue_comment_octokit2.yml:33:9:37:6 | Uses Step | | .github/workflows/issue_comment_octokit2.yml:33:9:37:6 | Uses Step | .github/workflows/issue_comment_octokit2.yml:37:9:38:37 | Uses Step | | .github/workflows/issue_comment_octokit.yml:12:9:19:6 | Uses Step: fetch_issue | .github/workflows/issue_comment_octokit.yml:19:9:26:6 | Uses Step: fetch_pr | | .github/workflows/issue_comment_octokit.yml:19:9:26:6 | Uses Step: fetch_pr | .github/workflows/issue_comment_octokit.yml:26:9:30:6 | Uses Step | | .github/workflows/issue_comment_octokit.yml:26:9:30:6 | Uses Step | .github/workflows/issue_comment_octokit.yml:30:9:35:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:28:17:28:69 | fromJson(steps.fetch_pr.outputs.data).head.ref | .github/workflows/issue_comment_octokit.yml:26:9:30:6 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:32:17:32:69 | fromJson(steps.fetch_pr.outputs.data).head.sha | .github/workflows/issue_comment_octokit.yml:30:9:35:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:38:9:52:6 | Uses Step: get-pr-info | .github/workflows/issue_comment_octokit.yml:52:9:57:6 | Run Step: get-sha | | .github/workflows/issue_comment_octokit.yml:52:9:57:6 | Run Step: get-sha | .github/workflows/issue_comment_octokit.yml:57:9:62:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:60:17:60:48 | steps.get-sha.outputs.sha | .github/workflows/issue_comment_octokit.yml:57:9:62:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:66:9:79:6 | Uses Step: sha | .github/workflows/issue_comment_octokit.yml:79:9:83:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:81:17:81:47 | steps.sha.outputs.result | .github/workflows/issue_comment_octokit.yml:79:9:83:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:87:9:95:6 | Uses Step: sha | .github/workflows/issue_comment_octokit.yml:95:9:100:2 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:98:17:98:47 | steps.sha.outputs.result | .github/workflows/issue_comment_octokit.yml:95:9:100:2 | Uses Step | | .github/workflows/issue_comment_octokit.yml:103:9:109:6 | Uses Step: request | .github/workflows/issue_comment_octokit.yml:109:9:114:66 | Uses Step | +| .github/workflows/issue_comment_octokit.yml:114:17:114:66 | fromJson(steps.request.outputs.data).head.ref | .github/workflows/issue_comment_octokit.yml:109:9:114:66 | Uses Step | | .github/workflows/label_trusted_checkout1.yml:11:7:15:4 | Uses Step | .github/workflows/label_trusted_checkout1.yml:15:7:16:4 | Uses Step | +| .github/workflows/label_trusted_checkout1.yml:13:15:13:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout1.yml:11:7:15:4 | Uses Step | | .github/workflows/label_trusted_checkout1.yml:15:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout1.yml:16:7:20:4 | Run Step | | .github/workflows/label_trusted_checkout1.yml:16:7:20:4 | Run Step | .github/workflows/label_trusted_checkout1.yml:20:7:24:4 | Uses Step | | .github/workflows/label_trusted_checkout1.yml:20:7:24:4 | Uses Step | .github/workflows/label_trusted_checkout1.yml:24:7:27:21 | Uses Step | | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:16:7:17:4 | Uses Step | +| .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | | .github/workflows/label_trusted_checkout2.yml:16:7:17:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | .github/workflows/label_trusted_checkout2.yml:21:7:25:4 | Uses Step | | .github/workflows/label_trusted_checkout2.yml:21:7:25:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:25:7:28:21 | Uses Step | @@ -134,17 +164,22 @@ edges | .github/workflows/level0.yml:62:9:65:6 | Uses Step | .github/workflows/level0.yml:65:9:86:2 | Uses Step | | .github/workflows/level0.yml:96:9:99:6 | Uses Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:103:9:107:6 | Uses Step | +| .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:99:9:103:6 | Uses Step | | .github/workflows/level0.yml:103:9:107:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | | .github/workflows/level0.yml:122:9:125:6 | Uses Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:129:9:133:6 | Uses Step | +| .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:125:9:129:6 | Uses Step | | .github/workflows/level0.yml:129:9:133:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | | .github/workflows/mend.yml:13:9:22:6 | Run Step: set_ref | .github/workflows/mend.yml:22:9:29:6 | Uses Step | | .github/workflows/mend.yml:22:9:29:6 | Uses Step | .github/workflows/mend.yml:29:9:33:28 | Uses Step | +| .github/workflows/mend.yml:27:17:27:48 | steps.set_ref.outputs.ref | .github/workflows/mend.yml:22:9:29:6 | Uses Step | | .github/workflows/poc2.yml:28:9:37:6 | Uses Step: branch-deploy | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | +| .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | .github/workflows/poc2.yml:47:9:52:6 | Run Step | | .github/workflows/poc2.yml:47:9:52:6 | Run Step | .github/workflows/poc2.yml:52:9:58:24 | Run Step | | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | .github/workflows/poc3.yml:25:7:31:4 | Uses Step | +| .github/workflows/poc3.yml:22:15:22:55 | github.event.pull_request.head.ref | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | | .github/workflows/poc3.yml:25:7:31:4 | Uses Step | .github/workflows/poc3.yml:31:7:33:4 | Uses Step | | .github/workflows/poc3.yml:31:7:33:4 | Uses Step | .github/workflows/poc3.yml:33:7:38:4 | Uses Step | | .github/workflows/poc3.yml:33:7:38:4 | Uses Step | .github/workflows/poc3.yml:38:7:40:4 | Run Step | @@ -153,26 +188,32 @@ edges | .github/workflows/poc3.yml:41:7:42:4 | Run Step | .github/workflows/poc3.yml:42:7:43:4 | Run Step | | .github/workflows/poc3.yml:42:7:43:4 | Run Step | .github/workflows/poc3.yml:43:7:48:2 | Uses Step | | .github/workflows/poc.yml:30:9:36:6 | Uses Step | .github/workflows/poc.yml:36:9:38:6 | Uses Step | +| .github/workflows/poc.yml:34:17:34:57 | github.event.pull_request.head.ref | .github/workflows/poc.yml:30:9:36:6 | Uses Step | | .github/workflows/poc.yml:36:9:38:6 | Uses Step | .github/workflows/poc.yml:38:9:43:6 | Uses Step | | .github/workflows/poc.yml:38:9:43:6 | Uses Step | .github/workflows/poc.yml:43:9:47:2 | Uses Step | | .github/workflows/pr-workflow.yml:57:9:60:6 | Uses Step | .github/workflows/pr-workflow.yml:60:9:70:6 | Uses Step | | .github/workflows/pr-workflow.yml:60:9:70:6 | Uses Step | .github/workflows/pr-workflow.yml:70:9:78:6 | Uses Step | | .github/workflows/pr-workflow.yml:70:9:78:6 | Uses Step | .github/workflows/pr-workflow.yml:78:9:81:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:103:9:109:6 | Uses Step | .github/workflows/pr-workflow.yml:109:9:124:6 | Uses Step | +| .github/workflows/pr-workflow.yml:105:17:105:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:103:9:109:6 | Uses Step | | .github/workflows/pr-workflow.yml:109:9:124:6 | Uses Step | .github/workflows/pr-workflow.yml:124:9:126:2 | Run Step | | .github/workflows/pr-workflow.yml:139:9:144:6 | Uses Step | .github/workflows/pr-workflow.yml:144:9:147:6 | Uses Step | +| .github/workflows/pr-workflow.yml:142:17:142:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:139:9:144:6 | Uses Step | | .github/workflows/pr-workflow.yml:144:9:147:6 | Uses Step | .github/workflows/pr-workflow.yml:147:9:148:6 | Uses Step | | .github/workflows/pr-workflow.yml:147:9:148:6 | Uses Step | .github/workflows/pr-workflow.yml:148:9:154:6 | Uses Step | | .github/workflows/pr-workflow.yml:148:9:154:6 | Uses Step | .github/workflows/pr-workflow.yml:154:9:158:6 | Run Step | | .github/workflows/pr-workflow.yml:154:9:158:6 | Run Step | .github/workflows/pr-workflow.yml:158:9:196:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:209:9:216:6 | Uses Step | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | +| .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | .github/workflows/pr-workflow.yml:227:9:230:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:243:9:250:6 | Uses Step | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | +| .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | .github/workflows/pr-workflow.yml:261:9:265:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:277:9:284:6 | Uses Step | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | +| .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | .github/workflows/pr-workflow.yml:295:9:298:2 | Run Step: ok | | .github/workflows/pr-workflow.yml:309:9:314:6 | Run Step | .github/workflows/pr-workflow.yml:314:9:318:6 | Run Step | | .github/workflows/pr-workflow.yml:314:9:318:6 | Run Step | .github/workflows/pr-workflow.yml:318:9:323:2 | Run Step | @@ -182,26 +223,33 @@ edges | .github/workflows/pr-workflow.yml:351:9:355:6 | Run Step | .github/workflows/pr-workflow.yml:355:9:369:2 | Uses Step | | .github/workflows/pr-workflow.yml:380:9:386:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | +| .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | | .github/workflows/pr-workflow.yml:444:9:449:6 | Uses Step | .github/workflows/pr-workflow.yml:449:9:452:6 | Uses Step | +| .github/workflows/pr-workflow.yml:447:17:447:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:444:9:449:6 | Uses Step | | .github/workflows/pr-workflow.yml:449:9:452:6 | Uses Step | .github/workflows/pr-workflow.yml:452:9:453:6 | Uses Step | | .github/workflows/pr-workflow.yml:452:9:453:6 | Uses Step | .github/workflows/pr-workflow.yml:453:9:459:6 | Uses Step | | .github/workflows/pr-workflow.yml:453:9:459:6 | Uses Step | .github/workflows/pr-workflow.yml:459:9:462:6 | Run Step | | .github/workflows/pr-workflow.yml:459:9:462:6 | Run Step | .github/workflows/pr-workflow.yml:462:9:463:48 | Run Step: ok | | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | .github/workflows/priv_pull_request_checkout.yml:20:9:23:52 | Run Step | +| .github/workflows/priv_pull_request_checkout.yml:17:17:17:38 | github.head_ref | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | | .github/workflows/resolve-args.yml:19:9:20:6 | Uses Step | .github/workflows/resolve-args.yml:20:9:22:6 | Uses Step | | .github/workflows/resolve-args.yml:20:9:22:6 | Uses Step | .github/actions/download-artifact/action.yaml:6:7:25:4 | Uses Step | | .github/workflows/resolve-args.yml:20:9:22:6 | Uses Step | .github/workflows/resolve-args.yml:22:9:36:13 | Run Step: resolve-step | | .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | +| .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | | .github/workflows/test1.yml:18:9:21:6 | Uses Step | .github/workflows/test1.yml:21:9:24:6 | Run Step | | .github/workflows/test1.yml:21:9:24:6 | Run Step | .github/workflows/test1.yml:24:9:25:39 | Run Step | | .github/workflows/test2.yml:13:9:16:6 | Uses Step | .github/workflows/test2.yml:16:9:20:52 | Uses Step | +| .github/workflows/test2.yml:15:17:15:57 | github.event.pull_request.head.sha | .github/workflows/test2.yml:13:9:16:6 | Uses Step | | .github/workflows/test3.yml:28:9:33:6 | Uses Step | .github/workflows/test3.yml:33:9:35:6 | Run Step | +| .github/workflows/test3.yml:31:17:31:57 | github.event.pull_request.head.ref | .github/workflows/test3.yml:28:9:33:6 | Uses Step | | .github/workflows/test3.yml:33:9:35:6 | Run Step | .github/workflows/test3.yml:35:9:41:63 | Uses Step | | .github/workflows/test4.yml:18:7:25:4 | Uses Step | .github/workflows/test4.yml:25:7:31:4 | Uses Step | +| .github/workflows/test4.yml:22:15:22:55 | github.event.pull_request.head.ref | .github/workflows/test4.yml:18:7:25:4 | Uses Step | | .github/workflows/test4.yml:25:7:31:4 | Uses Step | .github/workflows/test4.yml:31:7:33:4 | Uses Step | | .github/workflows/test4.yml:31:7:33:4 | Uses Step | .github/workflows/test4.yml:33:7:38:4 | Uses Step | | .github/workflows/test4.yml:33:7:38:4 | Uses Step | .github/workflows/test4.yml:38:7:40:4 | Run Step | @@ -212,12 +260,16 @@ edges | .github/workflows/test4.yml:43:7:47:4 | Uses Step | .github/workflows/test4.yml:47:7:47:28 | Run Step | | .github/workflows/test5.yml:13:9:28:6 | Uses Step: issue | .github/workflows/test5.yml:28:9:32:6 | Uses Step | | .github/workflows/test5.yml:28:9:32:6 | Uses Step | .github/workflows/test5.yml:32:9:34:2 | Run Step | +| .github/workflows/test5.yml:31:17:31:63 | fromJson(steps.issue.outputs.result).sha | .github/workflows/test5.yml:28:9:32:6 | Uses Step | | .github/workflows/test5.yml:39:9:54:6 | Uses Step: issue | .github/workflows/test5.yml:54:9:58:6 | Uses Step | | .github/workflows/test5.yml:54:9:58:6 | Uses Step | .github/workflows/test5.yml:58:9:60:2 | Run Step | +| .github/workflows/test5.yml:57:17:57:63 | fromJson(steps.issue.outputs.result).ref | .github/workflows/test5.yml:54:9:58:6 | Uses Step | | .github/workflows/test5.yml:64:9:68:6 | Uses Step | .github/workflows/test5.yml:68:9:68:43 | Run Step | +| .github/workflows/test5.yml:67:27:67:52 | github.event.number | .github/workflows/test5.yml:64:9:68:6 | Uses Step | | .github/workflows/test6.yml:19:9:39:6 | Uses Step | .github/workflows/test6.yml:39:9:43:6 | Run Step | | .github/workflows/test6.yml:39:9:43:6 | Run Step | .github/workflows/test6.yml:43:9:45:52 | Run Step | | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:24:9:27:6 | Uses Step | +| .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:19:9:24:6 | Uses Step | | .github/workflows/test7.yml:24:9:27:6 | Uses Step | .github/workflows/test7.yml:27:9:33:6 | Uses Step | | .github/workflows/test7.yml:27:9:33:6 | Uses Step | .github/workflows/test7.yml:33:9:36:6 | Run Step | | .github/workflows/test7.yml:33:9:36:6 | Run Step | .github/workflows/test7.yml:36:9:39:6 | Run Step | @@ -226,16 +278,22 @@ edges | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | .github/workflows/test7.yml:59:9:60:6 | Run Step | | .github/workflows/test7.yml:59:9:60:6 | Run Step | .github/workflows/test7.yml:60:9:60:37 | Run Step | | .github/workflows/test8.yml:20:9:26:6 | Uses Step | .github/workflows/test8.yml:26:9:29:2 | Run Step | +| .github/workflows/test8.yml:23:17:23:57 | github.event.pull_request.head.sha | .github/workflows/test8.yml:20:9:26:6 | Uses Step | | .github/workflows/test9.yml:11:9:16:6 | Uses Step | .github/workflows/test9.yml:16:9:17:48 | Run Step | +| .github/workflows/test9.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/test9.yml:11:9:16:6 | Uses Step | | .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:25:9:30:2 | Run Step | +| .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:20:9:25:6 | Uses Step | | .github/workflows/test11.yml:30:7:45:4 | Run Step | .github/workflows/test11.yml:45:7:84:4 | Run Step: environment | | .github/workflows/test11.yml:45:7:84:4 | Run Step: environment | .github/workflows/test11.yml:84:7:90:4 | Uses Step | | .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:90:7:93:54 | Uses Step | +| .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | .github/workflows/test11.yml:84:7:90:4 | Uses Step | | .github/workflows/test12.yml:32:7:47:4 | Run Step | .github/workflows/test12.yml:47:7:86:4 | Run Step: environment | | .github/workflows/test12.yml:47:7:86:4 | Run Step: environment | .github/workflows/test12.yml:86:7:92:4 | Uses Step | | .github/workflows/test12.yml:86:7:92:4 | Uses Step | .github/workflows/test12.yml:92:7:95:54 | Uses Step | +| .github/workflows/test12.yml:90:15:90:55 | steps.environment.outputs.head_sha | .github/workflows/test12.yml:86:7:92:4 | Uses Step | | .github/workflows/test13.yml:14:7:20:4 | Uses Step | .github/workflows/test13.yml:20:7:25:4 | Uses Step | | .github/workflows/test13.yml:20:7:25:4 | Uses Step | .github/workflows/test13.yml:25:7:28:4 | Uses Step | +| .github/workflows/test13.yml:23:25:23:56 | github.event.issue.number | .github/workflows/test13.yml:20:7:25:4 | Uses Step | | .github/workflows/test13.yml:25:7:28:4 | Uses Step | .github/workflows/test13.yml:28:7:31:50 | Run Step | | .github/workflows/test14.yml:38:7:41:4 | Uses Step | .github/workflows/test14.yml:41:7:44:4 | Run Step | | .github/workflows/test14.yml:41:7:44:4 | Run Step | .github/workflows/test14.yml:44:7:58:4 | Run Step | @@ -244,6 +302,7 @@ edges | .github/workflows/test14.yml:94:7:101:4 | Uses Step | .github/workflows/test14.yml:101:7:105:4 | Uses Step | | .github/workflows/test14.yml:101:7:105:4 | Uses Step | .github/workflows/test14.yml:105:7:111:4 | Uses Step | | .github/workflows/test14.yml:105:7:111:4 | Uses Step | .github/workflows/test14.yml:111:7:135:4 | Run Step: environment | +| .github/workflows/test14.yml:109:15:109:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test14.yml:105:7:111:4 | Uses Step | | .github/workflows/test14.yml:111:7:135:4 | Run Step: environment | .github/workflows/test14.yml:135:7:141:4 | Run Step: email | | .github/workflows/test14.yml:135:7:141:4 | Run Step: email | .github/workflows/test14.yml:141:7:149:4 | Run Step: slack-id | | .github/workflows/test14.yml:141:7:149:4 | Run Step: slack-id | .github/workflows/test14.yml:149:7:169:4 | Uses Step: slack-initiate | @@ -256,9 +315,11 @@ edges | .github/workflows/test15.yml:38:7:56:4 | Run Step: environment | .github/workflows/test15.yml:56:7:60:4 | Uses Step: comment-branch | | .github/workflows/test15.yml:56:7:60:4 | Uses Step: comment-branch | .github/workflows/test15.yml:60:7:65:4 | Uses Step | | .github/workflows/test15.yml:60:7:65:4 | Uses Step | .github/workflows/test15.yml:65:7:68:4 | Uses Step | +| .github/workflows/test15.yml:63:15:63:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test15.yml:60:7:65:4 | Uses Step | | .github/workflows/test15.yml:65:7:68:4 | Uses Step | .github/workflows/test15.yml:68:7:83:2 | Run Step | | .github/workflows/test15.yml:106:7:110:4 | Uses Step: comment-branch | .github/workflows/test15.yml:110:7:115:4 | Uses Step | | .github/workflows/test15.yml:110:7:115:4 | Uses Step | .github/workflows/test15.yml:115:7:120:4 | Uses Step | +| .github/workflows/test15.yml:113:15:113:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test15.yml:110:7:115:4 | Uses Step | | .github/workflows/test15.yml:115:7:120:4 | Uses Step | .github/workflows/test15.yml:120:7:127:4 | Run Step | | .github/workflows/test15.yml:120:7:127:4 | Run Step | .github/workflows/test15.yml:127:7:131:4 | Run Step | | .github/workflows/test15.yml:127:7:131:4 | Run Step | .github/workflows/test15.yml:131:7:136:4 | Run Step | @@ -266,6 +327,7 @@ edges | .github/workflows/test15.yml:169:7:173:4 | Uses Step: comment-branch | .github/workflows/test15.yml:173:7:180:4 | Uses Step | | .github/workflows/test15.yml:173:7:180:4 | Uses Step | .github/workflows/test15.yml:180:7:185:4 | Uses Step | | .github/workflows/test15.yml:180:7:185:4 | Uses Step | .github/workflows/test15.yml:185:7:197:4 | Run Step: pipeline-info | +| .github/workflows/test15.yml:183:15:183:58 | steps.comment-branch.outputs.head_ref | .github/workflows/test15.yml:180:7:185:4 | Uses Step | | .github/workflows/test15.yml:185:7:197:4 | Run Step: pipeline-info | .github/workflows/test15.yml:197:7:203:4 | Run Step: email | | .github/workflows/test15.yml:197:7:203:4 | Run Step: email | .github/workflows/test15.yml:203:7:211:4 | Run Step: slack-id | | .github/workflows/test15.yml:203:7:211:4 | Run Step: slack-id | .github/workflows/test15.yml:211:7:231:4 | Uses Step: slack-initiate | @@ -286,6 +348,7 @@ edges | .github/workflows/test16.yml:169:9:176:6 | Uses Step: get_token | .github/workflows/test16.yml:176:9:188:2 | Uses Step | | .github/workflows/test16.yml:218:9:221:6 | Uses Step | .github/workflows/test16.yml:221:9:226:6 | Uses Step | | .github/workflows/test16.yml:221:9:226:6 | Uses Step | .github/workflows/test16.yml:226:9:236:6 | Uses Step: get_token | +| .github/workflows/test16.yml:223:17:223:63 | github.event.workflow_run.head_commit.id | .github/workflows/test16.yml:221:9:226:6 | Uses Step | | .github/workflows/test16.yml:226:9:236:6 | Uses Step: get_token | .github/workflows/test16.yml:236:9:248:6 | Uses Step | | .github/workflows/test16.yml:236:9:248:6 | Uses Step | .github/workflows/test16.yml:248:9:270:6 | Run Step | | .github/workflows/test16.yml:248:9:270:6 | Run Step | .github/workflows/test16.yml:270:9:273:6 | Run Step | @@ -293,21 +356,29 @@ edges | .github/workflows/test16.yml:273:9:277:6 | Run Step: zips | .github/workflows/test16.yml:277:9:281:6 | Run Step: tests | | .github/workflows/test16.yml:277:9:281:6 | Run Step: tests | .github/workflows/test16.yml:281:9:294:54 | Uses Step | | .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:19:15:23:58 | Uses Step | +| .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | .github/workflows/test17.yml:12:15:19:12 | Uses Step | | .github/workflows/test18.yml:12:15:33:12 | Uses Step | .github/workflows/test18.yml:33:15:36:12 | Run Step | | .github/workflows/test18.yml:33:15:36:12 | Run Step | .github/workflows/test18.yml:36:15:40:58 | Uses Step | | .github/workflows/test19.yml:16:7:21:4 | Uses Step | .github/workflows/test19.yml:21:7:22:14 | Run Step | +| .github/workflows/test19.yml:20:15:20:55 | github.event.pull_request.head.ref | .github/workflows/test19.yml:16:7:21:4 | Uses Step | | .github/workflows/test20.yml:16:7:21:4 | Uses Step | .github/workflows/test20.yml:21:7:22:14 | Run Step | +| .github/workflows/test20.yml:20:15:20:55 | github.event.pull_request.head.sha | .github/workflows/test20.yml:16:7:21:4 | Uses Step | | .github/workflows/test21.yml:18:9:25:6 | Uses Step | .github/workflows/test21.yml:25:9:27:36 | Run Step | +| .github/workflows/test21.yml:23:17:23:52 | github.head_ref \|\| github.ref | .github/workflows/test21.yml:18:9:25:6 | Uses Step | | .github/workflows/test22.yml:57:15:62:12 | Uses Step | .github/workflows/test22.yml:62:15:62:45 | Run Step | | .github/workflows/test23.yml:38:9:43:6 | Uses Step | .github/workflows/test23.yml:43:9:46:16 | Run Step | +| .github/workflows/test23.yml:41:17:41:62 | needs.resolve-required-data.outputs.ref | .github/workflows/test23.yml:38:9:43:6 | Uses Step | | .github/workflows/test24.yml:7:9:10:6 | Uses Step | .github/workflows/test24.yml:10:9:16:6 | Run Step | | .github/workflows/test24.yml:10:9:16:6 | Run Step | .github/workflows/test24.yml:16:9:20:57 | Run Step | | .github/workflows/test25.yml:17:9:22:6 | Uses Step | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | | .github/workflows/test25.yml:22:9:32:6 | Uses Step: downloadBuildScan | .github/workflows/test25.yml:32:9:35:6 | Run Step | | .github/workflows/test25.yml:32:9:35:6 | Run Step | .github/workflows/test25.yml:35:9:42:53 | Run Step | | .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:21:9:22:16 | Run Step | +| .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | .github/workflows/test27.yml:18:9:21:6 | Uses Step | | .github/workflows/test28.yml:17:9:20:6 | Uses Step | .github/workflows/test28.yml:20:9:20:22 | Run Step | +| .github/workflows/test28.yml:19:17:19:38 | github.head_ref | .github/workflows/test28.yml:17:9:20:6 | Uses Step | | .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:14:7:21:11 | Uses Step | +| .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | .github/workflows/test29.yml:8:7:14:4 | Uses Step | | .github/workflows/test.yml:13:9:14:6 | Uses Step | .github/workflows/test.yml:14:9:25:6 | Run Step | | .github/workflows/test.yml:14:9:25:6 | Run Step | .github/workflows/test.yml:25:9:33:6 | Run Step | | .github/workflows/test.yml:25:9:33:6 | Run Step | .github/workflows/test.yml:33:9:37:34 | Run Step | @@ -324,74 +395,90 @@ edges | .github/workflows/untrusted_checkout3.yml:12:9:13:6 | Uses Step | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | | .github/workflows/untrusted_checkout4.yml:11:7:29:4 | Uses Step: get-pr | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | +| .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:11:9:15:6 | Uses Step | +| .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | | .github/workflows/untrusted_checkout.yml:11:9:15:6 | Uses Step | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:26:9:30:6 | Uses Step | +| .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | | .github/workflows/untrusted_checkout.yml:26:9:30:6 | Uses Step | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | | .github/workflows/untrusted_checkout_5.yml:11:9:14:6 | Uses Step | .github/workflows/untrusted_checkout_5.yml:14:9:17:6 | Uses Step | +| .github/workflows/untrusted_checkout_5.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_5.yml:11:9:14:6 | Uses Step | | .github/workflows/untrusted_checkout_5.yml:14:9:17:6 | Uses Step | .github/workflows/untrusted_checkout_5.yml:17:9:21:6 | Uses Step | +| .github/workflows/untrusted_checkout_5.yml:16:17:16:31 | env.HEAD | .github/workflows/untrusted_checkout_5.yml:14:9:17:6 | Uses Step | | .github/workflows/untrusted_checkout_5.yml:17:9:21:6 | Uses Step | .github/workflows/untrusted_checkout_5.yml:21:9:23:23 | Run Step | | .github/workflows/untrusted_checkout_6.yml:11:9:14:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | +| .github/workflows/untrusted_checkout_6.yml:13:17:13:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_6.yml:11:9:14:6 | Uses Step | | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:17:9:21:6 | Uses Step | +| .github/workflows/untrusted_checkout_6.yml:16:17:16:31 | env.HEAD | .github/workflows/untrusted_checkout_6.yml:14:9:17:6 | Uses Step | | .github/workflows/untrusted_checkout_6.yml:17:9:21:6 | Uses Step | .github/workflows/untrusted_checkout_6.yml:21:9:23:23 | Run Step | | .github/workflows/untrusted_checkout_no_needs.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_no_needs.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | +| .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permission_check_reusable.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permissions_check.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permissions_check.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_permissions_check.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:31:9:32:2 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:26:9:31:6 | Uses Step | | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | +| .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:16:9:22:2 | Run Step | | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:30:9:38:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_two_callers_both_protected.yml:38:9:44:2 | Run Step | | .github/workflows/workflow_run_untrusted_checkout.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout.yml:16:9:18:31 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout.yml:13:9:16:6 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout.yml:16:9:18:31 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_2.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_2.yml:16:9:18:31 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_2.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout_2.yml:13:9:16:6 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_2.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout_2.yml:16:9:18:31 | Uses Step | | .github/workflows/workflow_run_untrusted_checkout_3.yml:13:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_3.yml:16:9:18:31 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_3.yml:15:17:15:57 | github.event.workflow_run.head.sha | .github/workflows/workflow_run_untrusted_checkout_3.yml:13:9:16:6 | Uses Step | +| .github/workflows/workflow_run_untrusted_checkout_3.yml:18:17:18:31 | env.HEAD | .github/workflows/workflow_run_untrusted_checkout_3.yml:16:9:18:31 | Uses Step | #select -| .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout3.yml:4:3:4:14 | workflow_run | workflow_run | -| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | -| .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | -| .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_caller3.yaml:4:3:4:21 | pull_request_target | pull_request_target | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:33:9:36:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:36:9:39:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:59:9:60:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:60:9:60:37 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | -| .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:25:9:30:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test10.yml:8:3:8:21 | pull_request_target | pull_request_target | -| .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test11.yml:5:3:5:15 | issue_comment | issue_comment | -| .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test17.yml:3:5:3:16 | workflow_run | workflow_run | -| .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:21:9:22:16 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test26.yml:4:3:4:14 | workflow_run | workflow_run | -| .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:14:7:21:11 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test29.yml:1:5:1:23 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | -| .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | -| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout3.yml:13:9:13:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/actions/dangerous-git-checkout/action.yml:9:15:9:55 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout3.yml:4:3:4:14 | workflow_run | workflow_run | +| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:32:9:37:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:20:9:27:6 | Uses Step | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:48:9:52:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:24:17:24:57 | github.event.pull_request.head.ref | github.event.pull_request.head.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:79:9:84:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/auto_ci.yml:67:9:74:6 | Uses Step | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:84:9:93:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/auto_ci.yml:71:17:71:95 | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | github.event.pull_request.head.ref \|\| github.event.pull_request.base.ref | .github/workflows/auto_ci.yml:6:3:6:21 | pull_request_target | pull_request_target | +| .github/workflows/dependabot3.yml:15:9:20:6 | Uses Step | .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:25:9:48:6 | Run Step: set-milestone | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/dependabot3.yml:18:17:18:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/dependabot3.yml:3:5:3:23 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | inputs.COMMIT_SHA | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | inputs.COMMIT_SHA | .github/workflows/untrusted_checkout_permission_check_reusable_branching_nested.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:11:9:14:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:14:9:17:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml:13:17:13:40 | inputs.COMMIT_SHA | inputs.COMMIT_SHA | .github/workflows/untrusted_checkout_permission_check_reusable_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:23:9:26:6 | Uses Step | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:26:9:29:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/external/TestOrg/TestRepo/.github/workflows/reusable.yml:25:17:25:36 | inputs.branch | inputs.branch | .github/workflows/reusable_caller1.yaml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/gitcheckout.yml:17:27:17:48 | github.head_ref | github.head_ref | .github/workflows/gitcheckout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/label_trusted_checkout2.yml:12:7:16:4 | Uses Step | .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:17:7:21:4 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/label_trusted_checkout2.yml:14:15:14:55 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/label_trusted_checkout2.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:107:9:112:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:102:17:102:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | .github/workflows/level0.yml:133:9:135:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/level0.yml:128:17:128:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/level0.yml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/poc2.yml:40:17:40:54 | steps.branch-deploy.outputs.ref | steps.branch-deploy.outputs.ref | .github/workflows/poc2.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:220:17:220:64 | inputs.github_event_pull_request_head_sha | inputs.github_event_pull_request_head_sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:250:9:256:6 | Uses Step | .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:256:9:261:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:254:17:254:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:284:9:290:6 | Uses Step | .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:290:9:295:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:288:17:288:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:391:9:395:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:395:9:404:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:404:9:414:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:414:9:423:6 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/pr-workflow.yml:386:9:391:6 | Uses Step | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow.yml:423:9:432:2 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow.yml:389:17:389:78 | inputs.github_event_pull_request_head_sha \|\| github.sha | inputs.github_event_pull_request_head_sha \|\| github.sha | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target | +| .github/workflows/reusable_local.yml:23:9:26:6 | Uses Step | .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | .github/workflows/reusable_local.yml:26:9:29:7 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/reusable_local.yml:25:17:25:36 | inputs.branch | inputs.branch | .github/workflows/reusable_caller3.yaml:4:3:4:21 | pull_request_target | pull_request_target | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:33:9:36:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:36:9:39:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:49:9:59:6 | Run Step: benchmark-pr | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:59:9:60:6 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | .github/workflows/test7.yml:60:9:60:37 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test7.yml:22:27:22:58 | github.event.issue.number | github.event.issue.number | .github/workflows/test7.yml:4:3:4:15 | issue_comment | issue_comment | +| .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:25:9:30:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test10.yml:23:17:23:79 | github.event.after \|\| github.event.pull_request.head.sha | github.event.after \|\| github.event.pull_request.head.sha | .github/workflows/test10.yml:8:3:8:21 | pull_request_target | pull_request_target | +| .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test11.yml:88:15:88:55 | steps.environment.outputs.head_sha | steps.environment.outputs.head_sha | .github/workflows/test11.yml:5:3:5:15 | issue_comment | issue_comment | +| .github/workflows/test17.yml:12:15:19:12 | Uses Step | .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test17.yml:16:25:16:68 | github.event.workflow_run.head_branch | github.event.workflow_run.head_branch | .github/workflows/test17.yml:3:5:3:16 | workflow_run | workflow_run | +| .github/workflows/test27.yml:18:9:21:6 | Uses Step | .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | .github/workflows/test27.yml:21:9:22:16 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test27.yml:20:17:20:37 | inputs.git_ref | inputs.git_ref | .github/workflows/test26.yml:4:3:4:14 | workflow_run | workflow_run | +| .github/workflows/test29.yml:8:7:14:4 | Uses Step | .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | .github/workflows/test29.yml:14:7:21:11 | Uses Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test29.yml:11:15:11:55 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/test29.yml:1:5:1:23 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:35:7:41:4 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:41:7:47:4 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout4.yml:29:7:35:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:47:7:51:46 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout4.yml:33:15:33:67 | fromJSON(steps.get-pr.outputs.result).head.ref | fromJSON(steps.get-pr.outputs.result).head.ref | .github/workflows/untrusted_checkout4.yml:2:3:2:15 | issue_comment | issue_comment | +| .github/workflows/untrusted_checkout.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:15:9:18:2 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:10:17:10:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout.yml:23:9:26:6 | Uses Step | .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | .github/workflows/untrusted_checkout.yml:30:9:32:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout.yml:25:17:25:31 | env.HEAD | env.HEAD | .github/workflows/untrusted_checkout.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_no_needs.yml:26:9:31:6 | Uses Step | .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:31:9:31:23 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_no_needs.yml:29:17:29:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_no_needs.yml:2:3:2:21 | pull_request_target | pull_request_target | +| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code from $@ in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:39:17:39:57 | github.event.pull_request.head.sha | github.event.pull_request.head.sha | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target | diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index f5f7d195fa61..04ad4bba646b 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 12.0.2 + +### Minor Analysis Improvements + +* Added flow source models for `RegQueryValue` and related functions from the `winreg.h` Windows header. + ## 12.0.1 No user-facing changes. diff --git a/cpp/ql/lib/change-notes/released/12.0.2.md b/cpp/ql/lib/change-notes/released/12.0.2.md new file mode 100644 index 000000000000..cecfb536211f --- /dev/null +++ b/cpp/ql/lib/change-notes/released/12.0.2.md @@ -0,0 +1,5 @@ +## 12.0.2 + +### Minor Analysis Improvements + +* Added flow source models for `RegQueryValue` and related functions from the `winreg.h` Windows header. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index 95ce69d8d492..500fb3b8051e 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 12.0.1 +lastReleaseVersion: 12.0.2 diff --git a/cpp/ql/lib/ext/Windows.model.yml b/cpp/ql/lib/ext/Windows.model.yml index 6794e9a86641..c83e902cbc2c 100644 --- a/cpp/ql/lib/ext/Windows.model.yml +++ b/cpp/ql/lib/ext/Windows.model.yml @@ -34,6 +34,19 @@ extensions: - ["", "", False, "HttpReceiveHttpRequest", "", "", "Argument[*3]", "remote", "manual"] - ["", "", False, "HttpReceiveRequestEntityBody", "", "", "Argument[*3]", "remote", "manual"] - ["", "", False, "HttpReceiveClientCertificate", "", "", "Argument[*3]", "remote", "manual"] + # winreg.h + - ["", "", False, "RegQueryValueA", "", "", "Argument[*2]", "windows-registry", "manual"] + - ["", "", False, "RegQueryValueExA", "", "", "Argument[*4]", "windows-registry", "manual"] + - ["", "", False, "RegQueryValueW", "", "", "Argument[*2]", "windows-registry", "manual"] + - ["", "", False, "RegQueryValueExW", "", "", "Argument[*4]", "windows-registry", "manual"] + - ["", "", False, "RegGetValueA", "", "", "Argument[*5]", "windows-registry", "manual"] + - ["", "", False, "RegGetValueW", "", "", "Argument[*5]", "windows-registry", "manual"] + # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] + - ["", "", False, "RegQueryMultipleValuesA", "", "", "Argument[*3]", "windows-registry", "manual"] + # TODO: Once we support access paths at sources we should also mark Argument[*1].Field[*ve_valueptr] + - ["", "", False, "RegQueryMultipleValuesW", "", "", "Argument[*3]", "windows-registry", "manual"] + - ["", "", False, "RegEnumValueA", "", "", "Argument[*2,*6]", "windows-registry", "manual"] + - ["", "", False, "RegEnumValueW", "", "", "Argument[*2,*6]", "windows-registry", "manual"] - addsTo: pack: codeql/cpp-all extensible: summaryModel @@ -58,4 +71,13 @@ extensions: # winternl.h - ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"] # winhttp.h - - ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"] \ No newline at end of file + - ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"] + # combaseapi.h + - ["", "", False, "IIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "StringFromIID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] + - ["", "", False, "ProgIDFromCLSID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] + - ["", "", False, "CLSIDFromProgID", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "CLSIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "StringFromCLSID", "", "", "Argument[*0]", "Argument[**1]", "taint", "manual"] + - ["", "", False, "GUIDFromString", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] + - ["", "", False, "StringFromGUID2", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"] \ No newline at end of file diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 3f588d959579..fd32327163ba 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 12.0.1 +version: 12.0.2 groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll index 33695fdd51ab..1d085f458dec 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/FlowSources.qll @@ -20,6 +20,9 @@ abstract class RemoteFlowSource extends FlowSource { } /** A data flow source of local user input. */ abstract class LocalFlowSource extends FlowSource { } +/** A data flow source that represents the access of a value from the Windows registry. */ +abstract class WindowsRegistrySource extends LocalFlowSource { } + /** * A remote data flow source that is defined through a `RemoteFlowSourceFunction` model. */ @@ -101,6 +104,12 @@ private class ExternalLocalFlowSource extends LocalFlowSource { override string getSourceType() { result = "external" } } +private class ExternalWindowsRegistrySource extends WindowsRegistrySource { + ExternalWindowsRegistrySource() { sourceNode(this, "windows-registry") } + + override string getSourceType() { result = "a value from the Windows registry" } +} + /** A remote data flow sink. */ abstract class RemoteFlowSink extends DataFlow::Node { /** Gets a string that describes the type of this flow sink. */ diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index 945a605d7e3d..bc3adffadcdc 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.8.1 + +No user-facing changes. + ## 1.8.0 ### Query Metadata Changes diff --git a/cpp/ql/src/change-notes/released/1.8.1.md b/cpp/ql/src/change-notes/released/1.8.1.md new file mode 100644 index 000000000000..0b1a7cdad10a --- /dev/null +++ b/cpp/ql/src/change-notes/released/1.8.1.md @@ -0,0 +1,3 @@ +## 1.8.1 + +No user-facing changes. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index dc8a37cc443d..28a7c123ae84 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.8.0 +lastReleaseVersion: 1.8.1 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 57b8e535aeba..8495d389e7fb 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 1.8.0 +version: 1.8.1 groups: - cpp - queries diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 641804364501..24ba3b2aa686 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -17,104 +17,122 @@ models | 16 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual | | 17 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual | | 18 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual | -| 19 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | -| 20 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | -| 21 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | -| 22 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | -| 23 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | -| 24 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | -| 25 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | -| 26 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | -| 27 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | -| 28 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | -| 29 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | -| 30 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | -| 31 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | -| 32 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | -| 33 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | -| 34 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 35 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | -| 36 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 37 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 38 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 39 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 40 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 41 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | -| 42 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 43 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | -| 44 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 45 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | -| 46 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | -| 47 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | -| 48 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | -| 49 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 50 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | -| 51 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | -| 52 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 53 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 54 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 55 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 56 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 57 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 58 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 59 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 60 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 61 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 62 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 63 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 64 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 65 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 19 | Source: ; ; false; RegEnumValueA; ; ; Argument[*2,*6]; windows-registry; manual | +| 20 | Source: ; ; false; RegEnumValueW; ; ; Argument[*2,*6]; windows-registry; manual | +| 21 | Source: ; ; false; RegGetValueA; ; ; Argument[*5]; windows-registry; manual | +| 22 | Source: ; ; false; RegGetValueW; ; ; Argument[*5]; windows-registry; manual | +| 23 | Source: ; ; false; RegQueryMultipleValuesA; ; ; Argument[*3]; windows-registry; manual | +| 24 | Source: ; ; false; RegQueryMultipleValuesW; ; ; Argument[*3]; windows-registry; manual | +| 25 | Source: ; ; false; RegQueryValueA; ; ; Argument[*2]; windows-registry; manual | +| 26 | Source: ; ; false; RegQueryValueExA; ; ; Argument[*4]; windows-registry; manual | +| 27 | Source: ; ; false; RegQueryValueExW; ; ; Argument[*4]; windows-registry; manual | +| 28 | Source: ; ; false; RegQueryValueW; ; ; Argument[*2]; windows-registry; manual | +| 29 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual | +| 30 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual | +| 31 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual | +| 32 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual | +| 33 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual | +| 34 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual | +| 35 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual | +| 36 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual | +| 37 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual | +| 38 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual | +| 39 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual | +| 40 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual | +| 41 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual | +| 42 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual | +| 43 | Summary: ; ; false; CLSIDFromProgID; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 44 | Summary: ; ; false; CLSIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 45 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual | +| 46 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 47 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | +| 48 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 49 | Summary: ; ; false; GUIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 50 | Summary: ; ; false; IIDFromString; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 51 | Summary: ; ; false; ProgIDFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 52 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | +| 53 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 54 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 55 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 56 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual | +| 57 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 58 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual | +| 59 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 60 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual | +| 61 | Summary: ; ; false; StringFromCLSID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 62 | Summary: ; ; false; StringFromGUID2; ; ; Argument[*0]; Argument[*1]; taint; manual | +| 63 | Summary: ; ; false; StringFromIID; ; ; Argument[*0]; Argument[**1]; taint; manual | +| 64 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual | +| 65 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 66 | Summary: ; ; false; callWithNonTypeTemplate; (const T &); ; Argument[*0]; ReturnValue; value; manual | +| 67 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 68 | Summary: ; ; false; read_field_from_struct; ; ; Argument[*0].Field[MyNamespace::MyStructInNamespace::myField]; ReturnValue; value; manual | +| 69 | Summary: ; ; false; read_field_from_struct_2; ; ; Argument[*0].Field[MyGlobalStruct::myField]; ReturnValue; value; manual | +| 70 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 71 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 72 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 73 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 74 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 75 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 76 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 77 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 78 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 79 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 80 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 81 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 82 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 83 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 | -| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:42 | +| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:42 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:65 | -| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:83 | +| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:39 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:61 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:79 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:62 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:80 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:63 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:81 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | -| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:28 | +| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:38 | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | | | azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | | -| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:27 | +| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:37 | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | -| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 | +| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:36 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:63 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:81 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:64 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:82 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | -| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:30 | +| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:40 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | | | azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | | -| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:31 | +| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:41 | | azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | -| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | | @@ -122,13 +140,13 @@ edges | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:32:41:32:41 | x | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:53 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:71 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:52 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:70 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:54 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:72 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -138,73 +156,73 @@ edges | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | -| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:25 | -| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:49 | +| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:35 | +| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | MaD:67 | | test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | | test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | | test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | | test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | -| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | | test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | -| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:47 | -| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:47 | -| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:47 | -| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:47 | -| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:97:26:97:26 | x | test.cpp:68:22:68:22 | y | provenance | MaD:65 | +| test.cpp:101:26:101:26 | x | test.cpp:74:22:74:22 | y | provenance | MaD:65 | +| test.cpp:103:63:103:63 | x | test.cpp:82:22:82:22 | y | provenance | MaD:65 | +| test.cpp:104:62:104:62 | x | test.cpp:88:22:88:22 | y | provenance | MaD:65 | +| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | | | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | -| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:48 | -| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:66 | +| test.cpp:133:10:133:18 | call to ymlSource | test.cpp:133:10:133:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:1 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:59 | -| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:77 | +| test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:1 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:60 | -| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:78 | +| test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:1 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:60 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:78 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:58 | -| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:76 | +| test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:35 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:1 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:58 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:76 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | -| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:35 | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | | | test.cpp:187:10:187:31 | call to read_field_from_struct | test.cpp:188:10:188:10 | x | provenance | Sink:MaD:1 | -| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:50 | +| test.cpp:187:33:187:34 | *& ... [myField] | test.cpp:187:10:187:31 | call to read_field_from_struct | provenance | MaD:68 | | test.cpp:199:2:199:2 | *s [post update] [myField] | test.cpp:200:35:200:36 | *& ... [myField] | provenance | | | test.cpp:199:2:199:24 | ... = ... | test.cpp:199:2:199:2 | *s [post update] [myField] | provenance | | -| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:199:14:199:22 | call to ymlSource | test.cpp:199:2:199:24 | ... = ... | provenance | Src:MaD:35 | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | | | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:1 | -| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:51 | +| test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:69 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:57 | -| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:25 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:75 | +| test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:35 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:1 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:56 | -| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:25 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:55 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:74 | +| test.cpp:222:10:222:20 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:35 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:73 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:1 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | @@ -212,7 +230,7 @@ edges | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | | | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | | -| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:33 | +| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:45 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 | | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 | @@ -232,11 +250,11 @@ edges | windows.cpp:189:21:189:26 | ReadFile output argument | windows.cpp:190:5:190:56 | *... = ... | provenance | Src:MaD:17 | | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | windows.cpp:192:53:192:63 | *& ... [*hEvent] | provenance | | | windows.cpp:190:5:190:56 | *... = ... | windows.cpp:190:5:190:14 | *overlapped [post update] [*hEvent] | provenance | | -| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:37 | +| windows.cpp:192:53:192:63 | *& ... [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | MaD:52 | | windows.cpp:198:21:198:26 | ReadFile output argument | windows.cpp:199:5:199:57 | ... = ... | provenance | Src:MaD:17 | | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | windows.cpp:201:53:201:63 | *& ... [hEvent] | provenance | | | windows.cpp:199:5:199:57 | ... = ... | windows.cpp:199:5:199:14 | *overlapped [post update] [hEvent] | provenance | | -| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:37 | +| windows.cpp:201:53:201:63 | *& ... [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | MaD:52 | | windows.cpp:209:84:209:89 | NtReadFile output argument | windows.cpp:211:10:211:16 | * ... | provenance | Src:MaD:16 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:286:23:286:35 | *call to MapViewOfFile | provenance | Src:MaD:12 | | windows.cpp:286:23:286:35 | *call to MapViewOfFile | windows.cpp:287:20:287:52 | *pMapView | provenance | | @@ -273,9 +291,9 @@ edges | windows.cpp:431:3:431:3 | *s [post update] [x] | windows.cpp:464:7:464:8 | *& ... [x] | provenance | | | windows.cpp:431:3:431:16 | ... = ... | windows.cpp:431:3:431:3 | *s [post update] [x] | provenance | | | windows.cpp:431:9:431:14 | call to source | windows.cpp:431:3:431:16 | ... = ... | provenance | | -| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:36 | -| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:34 | -| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:35 | +| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | MaD:48 | +| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | MaD:46 | +| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | MaD:47 | | windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:537:40:537:41 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:542:38:542:39 | *& ... | provenance | | @@ -284,39 +302,39 @@ edges | windows.cpp:533:11:533:16 | call to source | windows.cpp:568:32:568:33 | *& ... | provenance | | | windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | | | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | | -| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:42 | +| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:57 | | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | | -| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:38 | +| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:53 | | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | | -| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:39 | +| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:54 | | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | | -| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:40 | +| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:55 | | windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | | | windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | | | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | | -| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:43 | +| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:58 | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | | | windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | | | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | | -| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:41 | +| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:56 | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | | | windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | | | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | | -| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:44 | +| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:59 | | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | | -| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:45 | -| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:23 | -| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:24 | -| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:19 | -| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:21 | -| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:22 | -| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:20 | +| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:60 | +| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:33 | +| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:34 | +| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:29 | +| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:31 | +| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:32 | +| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:30 | | windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | | | windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | | -| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:46 | +| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:64 | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | | | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | | @@ -337,6 +355,50 @@ edges | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:937:15:937:48 | *& ... | provenance | Src:MaD:6 | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | windows.cpp:941:10:941:31 | * ... | provenance | Src:MaD:6 | | windows.cpp:937:15:937:48 | *& ... | windows.cpp:939:10:939:11 | * ... | provenance | | +| windows.cpp:1009:35:1009:38 | RegQueryValueA output argument | windows.cpp:1011:10:1011:14 | * ... | provenance | Src:MaD:25 | +| windows.cpp:1016:36:1016:39 | RegQueryValueW output argument | windows.cpp:1018:10:1018:14 | * ... | provenance | Src:MaD:28 | +| windows.cpp:1024:53:1024:56 | RegQueryValueExA output argument | windows.cpp:1026:10:1026:14 | * ... | provenance | Src:MaD:26 | +| windows.cpp:1032:54:1032:57 | RegQueryValueExW output argument | windows.cpp:1034:10:1034:14 | * ... | provenance | Src:MaD:27 | +| windows.cpp:1040:46:1040:49 | RegQueryMultipleValuesA output argument | windows.cpp:1042:10:1042:14 | * ... | provenance | Src:MaD:23 | +| windows.cpp:1048:46:1048:49 | RegQueryMultipleValuesW output argument | windows.cpp:1050:10:1050:14 | * ... | provenance | Src:MaD:24 | +| windows.cpp:1056:53:1056:56 | RegGetValueA output argument | windows.cpp:1058:10:1058:14 | * ... | provenance | Src:MaD:21 | +| windows.cpp:1065:55:1065:58 | RegGetValueW output argument | windows.cpp:1067:10:1067:14 | * ... | provenance | Src:MaD:22 | +| windows.cpp:1075:28:1075:36 | RegEnumValueA output argument | windows.cpp:1079:10:1079:19 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | windows.cpp:1077:10:1077:14 | * ... | provenance | Src:MaD:19 | +| windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | windows.cpp:1091:10:1091:19 | * ... | provenance | Src:MaD:20 | +| windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | windows.cpp:1089:10:1089:14 | * ... | provenance | Src:MaD:20 | +| windows.cpp:1122:5:1122:27 | ... = ... | windows.cpp:1124:19:1124:21 | *str | provenance | | +| windows.cpp:1122:14:1122:27 | call to source | windows.cpp:1122:5:1122:27 | ... = ... | provenance | | +| windows.cpp:1124:19:1124:21 | *str | windows.cpp:1124:24:1124:27 | IIDFromString output argument | provenance | MaD:50 | +| windows.cpp:1124:24:1124:27 | IIDFromString output argument | windows.cpp:1125:10:1125:12 | iid | provenance | | +| windows.cpp:1128:15:1128:20 | call to source | windows.cpp:1128:15:1128:20 | call to source | provenance | | +| windows.cpp:1128:15:1128:20 | call to source | windows.cpp:1130:19:1130:21 | *iid | provenance | | +| windows.cpp:1130:19:1130:21 | *iid | windows.cpp:1130:24:1130:27 | StringFromIID output argument | provenance | MaD:63 | +| windows.cpp:1130:24:1130:27 | StringFromIID output argument | windows.cpp:1132:10:1132:13 | * ... | provenance | | +| windows.cpp:1135:19:1135:24 | call to source | windows.cpp:1135:19:1135:24 | call to source | provenance | | +| windows.cpp:1135:19:1135:24 | call to source | windows.cpp:1137:21:1137:25 | *clsid | provenance | | +| windows.cpp:1137:21:1137:25 | *clsid | windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | provenance | MaD:51 | +| windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | windows.cpp:1139:10:1139:13 | * ... | provenance | | +| windows.cpp:1143:5:1143:30 | ... = ... | windows.cpp:1145:21:1145:26 | *progID | provenance | | +| windows.cpp:1143:17:1143:30 | call to source | windows.cpp:1143:5:1143:30 | ... = ... | provenance | | +| windows.cpp:1145:21:1145:26 | *progID | windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | provenance | MaD:43 | +| windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | windows.cpp:1146:10:1146:14 | clsid | provenance | | +| windows.cpp:1150:5:1150:27 | ... = ... | windows.cpp:1152:21:1152:23 | *str | provenance | | +| windows.cpp:1150:14:1150:27 | call to source | windows.cpp:1150:5:1150:27 | ... = ... | provenance | | +| windows.cpp:1152:21:1152:23 | *str | windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | provenance | MaD:44 | +| windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | windows.cpp:1153:10:1153:14 | clsid | provenance | | +| windows.cpp:1156:19:1156:24 | call to source | windows.cpp:1156:19:1156:24 | call to source | provenance | | +| windows.cpp:1156:19:1156:24 | call to source | windows.cpp:1158:21:1158:25 | *clsid | provenance | | +| windows.cpp:1158:21:1158:25 | *clsid | windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | provenance | MaD:61 | +| windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | windows.cpp:1160:10:1160:13 | * ... | provenance | | +| windows.cpp:1164:5:1164:27 | ... = ... | windows.cpp:1166:20:1166:22 | *str | provenance | | +| windows.cpp:1164:14:1164:27 | call to source | windows.cpp:1164:5:1164:27 | ... = ... | provenance | | +| windows.cpp:1166:20:1166:22 | *str | windows.cpp:1166:25:1166:29 | GUIDFromString output argument | provenance | MaD:49 | +| windows.cpp:1166:25:1166:29 | GUIDFromString output argument | windows.cpp:1167:10:1167:13 | guid | provenance | | +| windows.cpp:1170:17:1170:22 | call to source | windows.cpp:1170:17:1170:22 | call to source | provenance | | +| windows.cpp:1170:17:1170:22 | call to source | windows.cpp:1172:21:1172:24 | *guid | provenance | | +| windows.cpp:1172:21:1172:24 | *guid | windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | provenance | MaD:62 | +| windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | windows.cpp:1174:10:1174:13 | * ... | provenance | | nodes | asio_streams.cpp:87:34:87:44 | read_until output argument | semmle.label | read_until output argument | | asio_streams.cpp:91:7:91:17 | recv_buffer | semmle.label | recv_buffer | @@ -653,6 +715,70 @@ nodes | windows.cpp:937:15:937:48 | *& ... | semmle.label | *& ... | | windows.cpp:939:10:939:11 | * ... | semmle.label | * ... | | windows.cpp:941:10:941:31 | * ... | semmle.label | * ... | +| windows.cpp:1009:35:1009:38 | RegQueryValueA output argument | semmle.label | RegQueryValueA output argument | +| windows.cpp:1011:10:1011:14 | * ... | semmle.label | * ... | +| windows.cpp:1016:36:1016:39 | RegQueryValueW output argument | semmle.label | RegQueryValueW output argument | +| windows.cpp:1018:10:1018:14 | * ... | semmle.label | * ... | +| windows.cpp:1024:53:1024:56 | RegQueryValueExA output argument | semmle.label | RegQueryValueExA output argument | +| windows.cpp:1026:10:1026:14 | * ... | semmle.label | * ... | +| windows.cpp:1032:54:1032:57 | RegQueryValueExW output argument | semmle.label | RegQueryValueExW output argument | +| windows.cpp:1034:10:1034:14 | * ... | semmle.label | * ... | +| windows.cpp:1040:46:1040:49 | RegQueryMultipleValuesA output argument | semmle.label | RegQueryMultipleValuesA output argument | +| windows.cpp:1042:10:1042:14 | * ... | semmle.label | * ... | +| windows.cpp:1048:46:1048:49 | RegQueryMultipleValuesW output argument | semmle.label | RegQueryMultipleValuesW output argument | +| windows.cpp:1050:10:1050:14 | * ... | semmle.label | * ... | +| windows.cpp:1056:53:1056:56 | RegGetValueA output argument | semmle.label | RegGetValueA output argument | +| windows.cpp:1058:10:1058:14 | * ... | semmle.label | * ... | +| windows.cpp:1065:55:1065:58 | RegGetValueW output argument | semmle.label | RegGetValueW output argument | +| windows.cpp:1067:10:1067:14 | * ... | semmle.label | * ... | +| windows.cpp:1075:28:1075:36 | RegEnumValueA output argument | semmle.label | RegEnumValueA output argument | +| windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | semmle.label | RegEnumValueA output argument | +| windows.cpp:1077:10:1077:14 | * ... | semmle.label | * ... | +| windows.cpp:1079:10:1079:19 | * ... | semmle.label | * ... | +| windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | +| windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | semmle.label | RegEnumValueW output argument | +| windows.cpp:1089:10:1089:14 | * ... | semmle.label | * ... | +| windows.cpp:1091:10:1091:19 | * ... | semmle.label | * ... | +| windows.cpp:1122:5:1122:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1122:14:1122:27 | call to source | semmle.label | call to source | +| windows.cpp:1124:19:1124:21 | *str | semmle.label | *str | +| windows.cpp:1124:24:1124:27 | IIDFromString output argument | semmle.label | IIDFromString output argument | +| windows.cpp:1125:10:1125:12 | iid | semmle.label | iid | +| windows.cpp:1128:15:1128:20 | call to source | semmle.label | call to source | +| windows.cpp:1128:15:1128:20 | call to source | semmle.label | call to source | +| windows.cpp:1130:19:1130:21 | *iid | semmle.label | *iid | +| windows.cpp:1130:24:1130:27 | StringFromIID output argument | semmle.label | StringFromIID output argument | +| windows.cpp:1132:10:1132:13 | * ... | semmle.label | * ... | +| windows.cpp:1135:19:1135:24 | call to source | semmle.label | call to source | +| windows.cpp:1135:19:1135:24 | call to source | semmle.label | call to source | +| windows.cpp:1137:21:1137:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | semmle.label | ProgIDFromCLSID output argument | +| windows.cpp:1139:10:1139:13 | * ... | semmle.label | * ... | +| windows.cpp:1143:5:1143:30 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1143:17:1143:30 | call to source | semmle.label | call to source | +| windows.cpp:1145:21:1145:26 | *progID | semmle.label | *progID | +| windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | semmle.label | CLSIDFromProgID output argument | +| windows.cpp:1146:10:1146:14 | clsid | semmle.label | clsid | +| windows.cpp:1150:5:1150:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1150:14:1150:27 | call to source | semmle.label | call to source | +| windows.cpp:1152:21:1152:23 | *str | semmle.label | *str | +| windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | semmle.label | CLSIDFromString output argument | +| windows.cpp:1153:10:1153:14 | clsid | semmle.label | clsid | +| windows.cpp:1156:19:1156:24 | call to source | semmle.label | call to source | +| windows.cpp:1156:19:1156:24 | call to source | semmle.label | call to source | +| windows.cpp:1158:21:1158:25 | *clsid | semmle.label | *clsid | +| windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | semmle.label | StringFromCLSID output argument | +| windows.cpp:1160:10:1160:13 | * ... | semmle.label | * ... | +| windows.cpp:1164:5:1164:27 | ... = ... | semmle.label | ... = ... | +| windows.cpp:1164:14:1164:27 | call to source | semmle.label | call to source | +| windows.cpp:1166:20:1166:22 | *str | semmle.label | *str | +| windows.cpp:1166:25:1166:29 | GUIDFromString output argument | semmle.label | GUIDFromString output argument | +| windows.cpp:1167:10:1167:13 | guid | semmle.label | guid | +| windows.cpp:1170:17:1170:22 | call to source | semmle.label | call to source | +| windows.cpp:1170:17:1170:22 | call to source | semmle.label | call to source | +| windows.cpp:1172:21:1172:24 | *guid | semmle.label | *guid | +| windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | semmle.label | StringFromGUID2 output argument | +| windows.cpp:1174:10:1174:13 | * ... | semmle.label | * ... | subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index 6585c88dc6dd..3556bd9d51dd 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -43,3 +43,15 @@ | windows.cpp:900:64:900:77 | HttpReceiveHttpRequest output argument | remote | | windows.cpp:929:70:929:75 | HttpReceiveRequestEntityBody output argument | remote | | windows.cpp:936:70:936:78 | HttpReceiveClientCertificate output argument | remote | +| windows.cpp:1009:35:1009:38 | RegQueryValueA output argument | windows-registry | +| windows.cpp:1016:36:1016:39 | RegQueryValueW output argument | windows-registry | +| windows.cpp:1024:53:1024:56 | RegQueryValueExA output argument | windows-registry | +| windows.cpp:1032:54:1032:57 | RegQueryValueExW output argument | windows-registry | +| windows.cpp:1040:46:1040:49 | RegQueryMultipleValuesA output argument | windows-registry | +| windows.cpp:1048:46:1048:49 | RegQueryMultipleValuesW output argument | windows-registry | +| windows.cpp:1056:53:1056:56 | RegGetValueA output argument | windows-registry | +| windows.cpp:1065:55:1065:58 | RegGetValueW output argument | windows-registry | +| windows.cpp:1075:28:1075:36 | RegEnumValueA output argument | windows-registry | +| windows.cpp:1075:71:1075:74 | RegEnumValueA output argument | windows-registry | +| windows.cpp:1087:28:1087:36 | RegEnumValueW output argument | windows-registry | +| windows.cpp:1087:71:1087:74 | RegEnumValueW output argument | windows-registry | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index 61b05459ade1..0fe13460cfbf 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -10,3 +10,11 @@ | test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body | | windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | | windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | +| windows.cpp:1124:19:1124:21 | *str | windows.cpp:1124:24:1124:27 | IIDFromString output argument | +| windows.cpp:1130:19:1130:21 | *iid | windows.cpp:1130:24:1130:27 | StringFromIID output argument | +| windows.cpp:1137:21:1137:25 | *clsid | windows.cpp:1137:28:1137:31 | ProgIDFromCLSID output argument | +| windows.cpp:1145:21:1145:26 | *progID | windows.cpp:1145:29:1145:34 | CLSIDFromProgID output argument | +| windows.cpp:1152:21:1152:23 | *str | windows.cpp:1152:26:1152:31 | CLSIDFromString output argument | +| windows.cpp:1158:21:1158:25 | *clsid | windows.cpp:1158:28:1158:31 | StringFromCLSID output argument | +| windows.cpp:1166:20:1166:22 | *str | windows.cpp:1166:25:1166:29 | GUIDFromString output argument | +| windows.cpp:1172:21:1172:24 | *guid | windows.cpp:1172:27:1172:29 | StringFromGUID2 output argument | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp index f098f7344e43..5c5877e06b0a 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/windows.cpp @@ -940,4 +940,237 @@ void test_http_server_api(HANDLE hRequestQueue) { sink(certInfo.pCertEncoded); sink(*certInfo.pCertEncoded); // $ ir } +} + +using HKEY = void*; +using BYTE = unsigned char; +using LPBYTE = BYTE*; +using PLONG = LONG*; + +typedef struct value_entA { + LPSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; +} VALENTA, *PVALENTA; + +typedef struct value_entW { + LPWSTR ve_valuename; + DWORD ve_valuelen; + DWORD_PTR ve_valueptr; + DWORD ve_type; +} VALENTW, *PVALENTW; + +LONG RegQueryValueA(HKEY hKey, LPCSTR lpSubKey, LPSTR lpData, PLONG lpcbData); +LONG RegQueryValueW(HKEY hKey, LPCWSTR lpSubKey, LPWSTR lpData, PLONG lpcbData); + +LONG RegQueryValueExA( + HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, + LPDWORD lpcbData +); + +LONG RegQueryValueExW( + HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, + LPDWORD lpcbData +); + +LONG RegGetValueA( + HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValue, DWORD flags, LPDWORD lpType, PVOID lpData, + LPDWORD lpcbData +); + +LONG RegGetValueW( + HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD flags, LPDWORD lpType, PVOID lpData, + LPDWORD lpcbData +); + +LONG RegQueryMultipleValuesA( + HKEY hKey, PVALENTA valList, DWORD numVals, LPSTR valueBuffer, LPDWORD totalSize +); + +LONG RegQueryMultipleValuesW( + HKEY hKey, PVALENTW valList, DWORD numVals, LPWSTR valueBuffer, LPDWORD totalSize +); + +LONG RegEnumValueA( + HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName, LPDWORD lpReserved, + LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData +); + +LONG RegEnumValueW( + HKEY hKey, DWORD dwIndex, LPWSTR lpValueName, LPDWORD lpcchValueName, LPDWORD lpReserved, + LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData +); + +void test_registry_queries(HKEY hKey) { + { + char data[256]; + LONG dataSize = sizeof(data); + RegQueryValueA(hKey, "value", data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + wchar_t data[256]; + LONG dataSize = sizeof(data); + RegQueryValueW(hKey, L"value", data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegQueryValueExA(hKey, "value", nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegQueryValueExW(hKey, L"value", nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + VALENTA values[1]; + char data[256]; + DWORD dataSize = sizeof(data); + RegQueryMultipleValuesA(hKey, values, 1, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + VALENTW values[1]; + wchar_t data[256]; + DWORD dataSize = sizeof(data); + RegQueryMultipleValuesW(hKey, values, 1, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegGetValueA(hKey, "subkey", "value", 0, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + + { + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegGetValueW(hKey, L"subkey", L"value", 0, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + } + { + char valueName[256]; + DWORD valueNameSize = sizeof(valueName); + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegEnumValueA(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + sink(valueName); // clean + sink(*valueName); // $ ir + } + { + wchar_t valueName[256]; + DWORD valueNameSize = sizeof(valueName) / sizeof(*valueName); + BYTE data[256]; + DWORD dataSize = sizeof(data); + DWORD type; + RegEnumValueW(hKey, 0, valueName, &valueNameSize, nullptr, &type, data, &dataSize); + sink(data); // clean + sink(*data); // $ ir + sink(valueName); // clean + sink(*valueName); // $ ir + } +} + +using LPCOLESTR = const char*; +using LPOLESTR = char*; +using GUID = int; +using CLSID = GUID; +using IID = GUID; +using REFIID = const IID&; +using REFCLSID = const CLSID&; +using REFGUID = const GUID&; +using LPIID = IID*; +using LPCLSID = CLSID*; +using HRESULT = long; + +HRESULT IIDFromString(LPCOLESTR lpsz, LPIID lpiid); +HRESULT StringFromIID(REFIID rclsid, LPOLESTR* lplpsz); +HRESULT ProgIDFromCLSID(REFCLSID clsid, LPOLESTR* lplpszProgID); +HRESULT CLSIDFromProgID(LPCOLESTR lpszProgID, LPCLSID lpclsid); +HRESULT CLSIDFromString(LPCOLESTR lpsz, LPCLSID pclsid); +HRESULT StringFromCLSID(REFCLSID rclsid, LPOLESTR* lplpsz); +int GUIDFromString(LPCOLESTR psz, GUID* pguid); +int StringFromGUID2(REFGUID rguid, LPOLESTR lpsz, int cchMax); + +void sink(GUID); +void sink(GUID*); + +void test_com_string_conversions() { + { + char str[256]; + str[0] = (char)source(); + IID iid; + IIDFromString(str, &iid); + sink(iid); // $ ir + } + { + IID iid = source(); + LPOLESTR str = nullptr; + StringFromIID(iid, &str); + sink(str); + sink(*str); // $ ir + } + { + CLSID clsid = source(); + LPOLESTR str = nullptr; + ProgIDFromCLSID(clsid, &str); + sink(str); + sink(*str); // $ ir + } + { + char progID[256]; + progID[0] = (char)source(); + CLSID clsid; + CLSIDFromProgID(progID, &clsid); + sink(clsid); // $ ir + } + { + char str[256]; + str[0] = (char)source(); + CLSID clsid; + CLSIDFromString(str, &clsid); + sink(clsid); // $ ir + } + { + CLSID clsid = source(); + LPOLESTR str = nullptr; + StringFromCLSID(clsid, &str); + sink(str); + sink(*str); // $ ir + } + { + char str[256]; + str[0] = (char)source(); + GUID guid; + GUIDFromString(str, &guid); + sink(guid); // $ ir + } + { + GUID guid = source(); + char str[256]; + StringFromGUID2(guid, str, 256); + sink(str); + sink(*str); // $ ir + } } \ No newline at end of file diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index a8774769b98c..f1ee51f9d945 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.72 + +No user-facing changes. + ## 1.7.71 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md new file mode 100644 index 000000000000..9ff61fe3c5d3 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.7.72.md @@ -0,0 +1,3 @@ +## 1.7.72 + +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 9cb591428908..33d595a3ea10 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.71 +lastReleaseVersion: 1.7.72 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 5a0ebdc92e66..8333936d134a 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.71 +version: 1.7.72 groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index a8774769b98c..f1ee51f9d945 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.7.72 + +No user-facing changes. + ## 1.7.71 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md new file mode 100644 index 000000000000..9ff61fe3c5d3 --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.7.72.md @@ -0,0 +1,3 @@ +## 1.7.72 + +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 9cb591428908..33d595a3ea10 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.71 +lastReleaseVersion: 1.7.72 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index a0d3ba43b9e6..5379a3416f94 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.71 +version: 1.7.72 groups: - csharp - solorigate diff --git a/csharp/ql/integration-tests/windows/subst/file.expected b/csharp/ql/integration-tests/windows/subst/file.expected index 6421dce41212..d14faca364be 100644 --- a/csharp/ql/integration-tests/windows/subst/file.expected +++ b/csharp/ql/integration-tests/windows/subst/file.expected @@ -1,8 +1,8 @@ -| code/Program.cs:0:0:0:0 | code/Program.cs | | -| code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs:0:0:0:0 | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs | | -| code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs | | -| code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs | | -| code/obj/Debug/net9.0/dotnet_build.dll:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.dll | | +| code/Program.cs:0:0:0:0 | code/Program.cs | relative | +| code/dotnet_build.csproj:0:0:0:0 | code/dotnet_build.csproj | relative | +| code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs:0:0:0:0 | code/obj/Debug/net9.0/.NETCoreApp,Version=v9.0.AssemblyAttributes.cs | relative | +| code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.AssemblyInfo.cs | relative | +| code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.GlobalUsings.g.cs | relative | +| code/obj/Debug/net9.0/dotnet_build.dll:0:0:0:0 | code/obj/Debug/net9.0/dotnet_build.dll | relative | +| code/obj/dotnet_build.csproj.nuget.g.props:0:0:0:0 | code/obj/dotnet_build.csproj.nuget.g.props | relative | | file://:0:0:0:0 | | | -| file://Z:/dotnet_build.csproj:0:0:0:0 | Z:/dotnet_build.csproj | relative | -| file://Z:/obj/dotnet_build.csproj.nuget.g.props:0:0:0:0 | Z:/obj/dotnet_build.csproj.nuget.g.props | relative | diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index 3ea969a9e9a5..ccfde0f7f8fb 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.1.2 + +No user-facing changes. + ## 7.1.1 No user-facing changes. diff --git a/csharp/ql/lib/change-notes/released/7.1.2.md b/csharp/ql/lib/change-notes/released/7.1.2.md new file mode 100644 index 000000000000..d55cf91e2492 --- /dev/null +++ b/csharp/ql/lib/change-notes/released/7.1.2.md @@ -0,0 +1,3 @@ +## 7.1.2 + +No user-facing changes. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 8e970df6cae3..547681cc4408 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.1.1 +lastReleaseVersion: 7.1.2 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index f2f4925dbf5b..62d2c3a2ea30 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 7.1.1 +version: 7.1.2 groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index f3aee337480f..6fab89a5cac1 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.9.1 + +No user-facing changes. + ## 1.9.0 ### Query Metadata Changes diff --git a/csharp/ql/src/change-notes/released/1.9.1.md b/csharp/ql/src/change-notes/released/1.9.1.md new file mode 100644 index 000000000000..bc5c4bd30411 --- /dev/null +++ b/csharp/ql/src/change-notes/released/1.9.1.md @@ -0,0 +1,3 @@ +## 1.9.1 + +No user-facing changes. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index df17dc3a3662..29c886b15136 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.9.0 +lastReleaseVersion: 1.9.1 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index abd86552bb07..647d273d52bc 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 1.9.0 +version: 1.9.1 groups: - csharp - queries diff --git a/defs.bzl b/defs.bzl index d6748d831761..d4c5ea5e2623 100644 --- a/defs.bzl +++ b/defs.bzl @@ -1,5 +1,8 @@ -codeql_platform = select({ - "@platforms//os:linux": "linux64", - "@platforms//os:macos": "osx64", - "@platforms//os:windows": "win64", -}) +load("//misc/bazel:os.bzl", "codeql_platform_select") + +codeql_platform = codeql_platform_select( + linux64 = "linux64", + linux_arm64 = "linux-arm64", + osx64 = "osx64", + win64 = "win64", +) diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst index 77ea678f5468..7ede0d0aff3a 100644 --- a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst @@ -549,6 +549,7 @@ A type can be defined by adding ``typeModel`` tuples for that type. Additionally - The name of an NPM package matches imports of that package. For example, the type ``express`` matches the expression ``require("express")``. If the package name includes dots, it must be surrounded by single quotes, such as in ``'lodash.escape'``. - The type ``global`` identifies the global object, also known as ``window``. In JavaScript, global variables are properties of the global object, so global variables can be identified using this type. (This type also matches imports of the NPM package named ``global``, which is a package that happens to export the global object.) - A qualified type name of form ``.`` identifies expressions of type ```` from ````. For example, ``mysql.Connection`` identifies expression of type ``Connection`` from the ``mysql`` package. Note that this only works if type annotations are present in the codebase, or if sufficient ``typeModel`` tuples have been provided for that type. +- A string of form ``file:`` identifies expressions that are imported from a file at the given path. The path is relative to the root of the codebase, must use forward slashes as path separator, must include the file extension, and is case-sensitive. For example, ``file:src/utils.js`` identifies expressions such as ``require('./utils')`` inside ``src/``, or ``require('../src/utils')`` inside another top-level folder. Access paths ------------ diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst new file mode 100644 index 000000000000..845988894f0a --- /dev/null +++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst @@ -0,0 +1,79 @@ +.. _codeql-cli-2.26.2: + +========================== +CodeQL 2.26.2 (2026-07-23) +========================== + +.. contents:: Contents + :depth: 2 + :local: + :backlinks: none + +This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog `__, `relevant GitHub Changelog updates `__, `changes in the CodeQL extension for Visual Studio Code `__, and the `CodeQL Action changelog `__. + +Security Coverage +----------------- + +CodeQL 2.26.2 runs a total of 497 security queries when configured with the Default suite (covering 170 CWE). The Extended suite enables an additional 131 queries (covering 32 more CWE). + +CodeQL CLI +---------- + +Breaking Changes +~~~~~~~~~~~~~~~~ + +* Removed support for parsing :code:`[[`\ -style links in alert messages. This was an undocumented legacy feature that allowed query authors to embed links inline in select clause message strings using :code:`[["text"|"url"]]` syntax. Queries should use :code:`$@` placeholder pairs instead. + +Query Packs +----------- + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +C# +"" + +* :code:`System.Web.HttpRequest.RawUrl` is no longer treated as a sanitizer for :code:`cs/web/unvalidated-url-redirection`, since it contains the un-normalized request line. This may lead to more results. + +Query Metadata Changes +~~~~~~~~~~~~~~~~~~~~~~ + +C/C++ +""""" + +* Added the tag :code:`external/cwe/cwe-762` to :code:`cpp/new-free-mismatch`, and removed the tag :code:`external/cwe/cwe-401`. This better matches the behavior of the query. + +C# +"" + +* The query :code:`cs/useless-assignment-to-local` has been removed from the :code:`code-quality` suite, but it remains in the :code:`code-quality-extended` suite. + +Language Libraries +------------------ + +Major Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Swift +""""" + +* Upgraded to allow analysis of Swift 6.3.3. + +Minor Analysis Improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Golang +"""""" + +* The function :code:`Rel` in :code:`path/filepath` was incorrectly considered a sanitizer for :code:`go/path-injection` and :code:`go/zipslip`. This has now been fixed, which may lead to more results for those queries. + +Java/Kotlin +""""""""""" + +* Kotlin versions up to 2.4.10 are now supported. +* :code:`java.io.File.getName()` is no longer treated as a complete sanitizer for :code:`java/path-injection`, since it does not remove a :code:`..` path component (for example :code:`new File("..").getName()` returns :code:`".."`). It is now only recognized as a sanitizer when combined with a subsequent check for :code:`..` components, which may result in new alerts. + +GitHub Actions +"""""""""""""" + +* Altered the logic of :code:`EnvironmentCheck` to make sure it is a check that protects only for non-toctou. This change will result in more results being found by the queries: :code:`actions/untrusted-checkout-toctou/high` and :code:`actions/untrusted-checkout-toctou/critical`. diff --git a/docs/codeql/codeql-overview/codeql-changelog/index.rst b/docs/codeql/codeql-overview/codeql-changelog/index.rst index 837fa757368d..a0a2e1832d83 100644 --- a/docs/codeql/codeql-overview/codeql-changelog/index.rst +++ b/docs/codeql/codeql-overview/codeql-changelog/index.rst @@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here = 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + return path + } + + resolved, ok := resolveDrive(path[:3]) + if !ok { + return path + } + return resolved + path[2:] +} + +// Given a drive root like "X:\" (or "X:/"), returns the path that drive is +// "subst"ed to. Returns false if the drive is not "subst"ed or an error occurred. +func resolveDrive(driveRoot string) (string, bool) { + if !available { + return "", false + } + driveBytes, err := windows.ByteSliceFromString(driveRoot) + if err != nil { + return "", false + } + ret, _, _ := procResolve.Call(uintptr(unsafe.Pointer(&driveBytes[0]))) + if ret == 0 { + return "", false + } + result := windows.BytePtrToString((*byte)(unsafe.Pointer(ret))) + if procFree != nil { + procFree.Call(ret) + } + return result, true +} diff --git a/go/ql/consistency-queries/CHANGELOG.md b/go/ql/consistency-queries/CHANGELOG.md index d75ab9a9e2d7..3a3948e7bf27 100644 --- a/go/ql/consistency-queries/CHANGELOG.md +++ b/go/ql/consistency-queries/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/go/ql/consistency-queries/change-notes/released/1.0.55.md b/go/ql/consistency-queries/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/go/ql/consistency-queries/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/go/ql/consistency-queries/codeql-pack.release.yml b/go/ql/consistency-queries/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/go/ql/consistency-queries/codeql-pack.release.yml +++ b/go/ql/consistency-queries/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/go/ql/consistency-queries/qlpack.yml b/go/ql/consistency-queries/qlpack.yml index 3f52b158fc70..3ade0367079d 100644 --- a/go/ql/consistency-queries/qlpack.yml +++ b/go/ql/consistency-queries/qlpack.yml @@ -1,5 +1,5 @@ name: codeql-go-consistency-queries -version: 1.0.54 +version: 1.0.55 groups: - go - queries diff --git a/go/ql/integration-tests/subst/file.expected b/go/ql/integration-tests/subst/file.expected index b86b34681e44..96cce26cff5e 100644 --- a/go/ql/integration-tests/subst/file.expected +++ b/go/ql/integration-tests/subst/file.expected @@ -1 +1 @@ -| file://Z:/main.go:0:0:0:0 | Z:/main.go | relative | +| code/main.go:0:0:0:0 | code/main.go | relative | diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 4b594f8f7405..14c075851e29 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.2.3 + +No user-facing changes. + ## 7.2.2 ### Minor Analysis Improvements diff --git a/go/ql/lib/change-notes/released/7.2.3.md b/go/ql/lib/change-notes/released/7.2.3.md new file mode 100644 index 000000000000..ba04214fb88d --- /dev/null +++ b/go/ql/lib/change-notes/released/7.2.3.md @@ -0,0 +1,3 @@ +## 7.2.3 + +No user-facing changes. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index fa4a7164fb7b..7d0dee6395ee 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.2.2 +lastReleaseVersion: 7.2.3 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index ba1129203eed..d11fb5937d3b 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 7.2.2 +version: 7.2.3 groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index 6d012f9d2a4d..9dfd046bec53 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.8 + +No user-facing changes. + ## 1.6.7 No user-facing changes. diff --git a/go/ql/src/change-notes/released/1.6.8.md b/go/ql/src/change-notes/released/1.6.8.md new file mode 100644 index 000000000000..0a5d9b06c55e --- /dev/null +++ b/go/ql/src/change-notes/released/1.6.8.md @@ -0,0 +1,3 @@ +## 1.6.8 + +No user-facing changes. diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index 0b49adeac7da..fbc11aa62b75 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.7 +lastReleaseVersion: 1.6.8 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 1800db532cb4..61ae6f2fe439 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 1.6.7 +version: 1.6.8 groups: - go - queries diff --git a/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java b/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java index 79ce2d8d8d3d..19bdc786c5e2 100644 --- a/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java +++ b/java/kotlin-extractor/src/main/java/com/semmle/util/files/FileUtil.java @@ -1237,13 +1237,14 @@ public static String relativePathLink (File f, File base) /** * Try to convert a file into a canonical file. Handles the possible IO exception by just making - * the path absolute. + * the path absolute. Also resolves subst drives on Windows. */ public static File tryMakeCanonical (File f) { try { - return f.getCanonicalFile(); - } + // getCanonicalFile does not canonicalize subst drives on Windows, so do this separately. This + // is a no-op on non-Windows platforms. + return SubstResolver.resolve(f.getCanonicalFile()); } catch (IOException ignored) { Exceptions.ignore(ignored, "Can't log error: Could be too verbose."); return new File(simplifyPath(f)); diff --git a/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java new file mode 100644 index 000000000000..017d4fb8399f --- /dev/null +++ b/java/kotlin-extractor/src/main/java/com/semmle/util/files/SubstResolver.java @@ -0,0 +1,87 @@ +package com.semmle.util.files; + +import com.semmle.util.exception.Exceptions; +import java.io.File; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * Resolves Windows {@code subst}ed drive letters to their underlying paths. On non-Windows + * platforms, or when the native library failed to load, resolving will be a no-op. + */ +public class SubstResolver { + private static final boolean available; + + static { + boolean loaded = false; + // Cheap check to see that we are on Windows. Avoids static initialization of {@code Env}. + if (File.separatorChar == '\\') { + String dist = System.getenv("CODEQL_DIST"); + if (dist != null && !dist.isEmpty()) { + try { + Path library = Paths.get(dist).resolve("tools") + .resolve("win64").resolve("canonicalize.dll").toAbsolutePath(); + System.load(library.toString()); + loaded = true; + } catch (RuntimeException | UnsatisfiedLinkError ignored) { + Exceptions.ignore(ignored, "Fall back to resolution being a no-op."); + } + } + } + available = loaded; + } + + private SubstResolver() {} + + /** + * Given a drive root like {@code "X:\\"} (or {@code "X:/"}), returns the path that drive is + * {@code subst}ed to, or {@code null} if the drive root was not subst drive or if an internal + * error occurred. + */ + private static native String nativeResolveSubst(String driveRoot); + + /** + * If {@code f} is an absolute path starting with a {@code subst}ed drive letter, return an + * equivalent path with the drive letter replaced by its target. Otherwise return {@code f} + * unchanged. + */ + public static File resolve(File f) { + if (!available) { + return f; + } + String path = f.getPath(); + if (path.length() < 3 || path.charAt(1) != ':') { + return f; + } + char sep = path.charAt(2); + if (sep != '\\' && sep != '/') { + return f; + } + if (!isDriveLetter(path.charAt(0))) { + return f; + } + + String resolved; + try { + resolved = nativeResolveSubst(path.substring(0, 3)); + } catch (RuntimeException | UnsatisfiedLinkError ignored) { + Exceptions.ignore(ignored, "Fall back to resolution being a no-op."); + + return f; + } + if (resolved == null) { + return f; + } + + // Append the remainder of the original path. The native side strips away + // any trailing separator. + return new File(resolved + path.substring(2)); + } + + private static boolean isDriveLetter(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } +} diff --git a/java/ql/integration-tests/java/subst/file.expected b/java/ql/integration-tests/java/subst/file.expected index 467876a74450..02d4543cfcae 100644 --- a/java/ql/integration-tests/java/subst/file.expected +++ b/java/ql/integration-tests/java/subst/file.expected @@ -1,5 +1,5 @@ +| code/Test.class:0:0:0:0 | Test | relative | +| code/test1.java:0:0:0:0 | test1 | relative | +| code/test2.kt:0:0:0:0 | test2 | relative | | file://:0:0:0:0 | | | | file://:0:0:0:0 | | | -| file://Z:/Test.class:0:0:0:0 | Test | relative | -| file://Z:/test1.java:0:0:0:0 | test1 | relative | -| file://Z:/test2.kt:0:0:0:0 | test2 | relative | diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 83910f155a3c..2fd58088dab6 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 9.2.3 + +No user-facing changes. + ## 9.2.2 ### Minor Analysis Improvements diff --git a/java/ql/lib/change-notes/released/9.2.3.md b/java/ql/lib/change-notes/released/9.2.3.md new file mode 100644 index 000000000000..c0cdbd68de76 --- /dev/null +++ b/java/ql/lib/change-notes/released/9.2.3.md @@ -0,0 +1,3 @@ +## 9.2.3 + +No user-facing changes. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 41cfa549b0a6..39a6208d44d2 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 9.2.2 +lastReleaseVersion: 9.2.3 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 806b928523d1..88218c0c092a 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 9.2.2 +version: 9.2.3 groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index 3fd98c386b69..b31db924d53d 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.11.8 + +No user-facing changes. + ## 1.11.7 No user-facing changes. diff --git a/java/ql/src/change-notes/released/1.11.8.md b/java/ql/src/change-notes/released/1.11.8.md new file mode 100644 index 000000000000..0783473b96d3 --- /dev/null +++ b/java/ql/src/change-notes/released/1.11.8.md @@ -0,0 +1,3 @@ +## 1.11.8 + +No user-facing changes. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index da245378bca5..1235b98cb049 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.11.7 +lastReleaseVersion: 1.11.8 diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index 1b8cd80983ae..e22f77c81351 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 1.11.7 +version: 1.11.8 groups: - java - queries diff --git a/javascript/ql/integration-tests/subst/file.expected b/javascript/ql/integration-tests/subst/file.expected index 10416eb5e733..6d3663acac81 100644 --- a/javascript/ql/integration-tests/subst/file.expected +++ b/javascript/ql/integration-tests/subst/file.expected @@ -1,2 +1,2 @@ -| file://Z:/main.js:0:0:0:0 | Z:/main.js | relative | -| file://Z:/test.ts:0:0:0:0 | Z:/test.ts | relative | +| code/main.js:0:0:0:0 | code/main.js | relative | +| code/test.ts:0:0:0:0 | code/test.ts | relative | diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index c0217aee81e7..6ac06fe87b99 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,18 @@ +## 2.9.0 + +### Major Analysis Improvements + +* It is now possible for custom models to refer to specific files in the codebase, using a package name of the form `file:`. The model should describe the public exports + of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. + For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. + +### Minor Analysis Improvements + +* JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. +* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. +* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. +* Added support for treating declared `inputs` properties in Sails Action2 controller files as remote flow sources. This may improve results for security queries such as `js/path-injection`. + ## 2.8.2 No user-facing changes. diff --git a/javascript/ql/lib/change-notes/released/2.9.0.md b/javascript/ql/lib/change-notes/released/2.9.0.md new file mode 100644 index 000000000000..6892fa665580 --- /dev/null +++ b/javascript/ql/lib/change-notes/released/2.9.0.md @@ -0,0 +1,14 @@ +## 2.9.0 + +### Major Analysis Improvements + +* It is now possible for custom models to refer to specific files in the codebase, using a package name of form `file:`. The model should describe the public exports + of that file. This can be used to derive sources and sinks in code that imports the file, but note that sources and sinks will not generally be placed within the file itself. + For example, a source model `['file:lib/service.js', 'Member[getData].ReturnValue', 'remote']` could identify `require('../lib/service').getData()` as a source. + +### Minor Analysis Improvements + +* JavaScript security queries using the `response` threat model now track promise-wrapped client response data into promise fulfillment values. This may improve results for queries such as `js/xss` when response data is consumed through `.then(...)` chains. +* The route object returned by Vue Router's `useRoute()` Composition API is now recognized as a client-side remote flow source, covering its `query`, `params`, `path`, `fullPath`, and `hash` members. These members are additionally reported under the corresponding `browser-url-query`, `browser-url-path`, and `browser-url-fragment` threat models. +* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers. +* Added support for treating declared `inputs` properties in Sails Action2 controller files as remote flow sources. This may improve results for security queries such as `js/path-injection`. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 49d300fe06bf..d6329a574932 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.8.2 +lastReleaseVersion: 2.9.0 diff --git a/javascript/ql/lib/ext/vue.model.yml b/javascript/ql/lib/ext/vue.model.yml new file mode 100644 index 000000000000..17d473210335 --- /dev/null +++ b/javascript/ql/lib/ext/vue.model.yml @@ -0,0 +1,22 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + # `useRoute()` — Vue Router's Composition API returns a route object whose URL-derived + # members are client-side remote flow sources. + - ["vue-router", "Member[useRoute].ReturnValue.Member[params,path,fullPath]", "browser-url-path"] + - ["vue-router", "Member[useRoute].ReturnValue.Member[query]", "browser-url-query"] + - ["vue-router", "Member[useRoute].ReturnValue.Member[hash]", "browser-url-fragment"] + - addsTo: + pack: codeql/javascript-all + extensible: summaryModel + data: + # `ref`, `shallowRef`, `toRef` — the wrapped argument flows to `.value`. + - ["vue", "Member[ref,shallowRef,toRef]", "Argument[0]", "ReturnValue.Member[value]", "value"] + # `reactive` — the wrapped argument taints the returned reactive object. + - ["vue", "Member[reactive]", "Argument[0]", "ReturnValue", "taint"] + # `computed(() => ...)` — function overload: the getter's return value flows to `.value`. + - ["vue", "Member[computed]", "Argument[0].ReturnValue", "ReturnValue.Member[value]", "value"] + # `computed({ get() { ... } })` — object overload: the `get` getter's return value flows to `.value`. + - ["vue", "Member[computed]", "Argument[0].Member[get].ReturnValue", "ReturnValue.Member[value]", "value"] diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index ae298ba83811..a8caae8cf334 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 2.8.2 +version: 2.9.0 groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 9da93400ef92..fabf0a6d38f5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -1016,6 +1016,18 @@ module ClientRequest { override string getSourceType() { result = "HTTP response data" } } + /** + * A taint step from promise-wrapped response data to the value that the promise resolves to. + */ + private class ClientRequestResponsePromiseStep extends TaintTracking::SharedTaintStep { + override predicate promiseStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ClientRequest r | + r.getAResponseDataNode(_, true).getALocalSource().flowsTo(node1) and + PromiseFlow::loadStep(node1, node2, Promises::valueProp()) + ) + } + } + /** * An additional taint step that captures taint propagation from the receiver of fetch response methods * (such as "json", "text", "blob", and "arrayBuffer") to the call result. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HttpFrameworks.qll b/javascript/ql/lib/semmle/javascript/frameworks/HttpFrameworks.qll index 8e91230d3b21..3c8e3993e608 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HttpFrameworks.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HttpFrameworks.qll @@ -7,4 +7,5 @@ import semmle.javascript.frameworks.Micro import semmle.javascript.frameworks.Restify import semmle.javascript.frameworks.Connect import semmle.javascript.frameworks.Fastify +import semmle.javascript.frameworks.Sails import semmle.javascript.frameworks.Spife diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll b/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll new file mode 100644 index 000000000000..eae9d8927f1c --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Sails.qll @@ -0,0 +1,85 @@ +/** + * Provides classes for working with [Sails](https://sailsjs.com/) applications. + */ + +private import javascript +private import semmle.javascript.frameworks.HTTP +private import DataFlow + +/** + * Provides classes for working with [Sails](https://sailsjs.com/) applications. + */ +module Sails { + /** + * A Sails Action2 action object exported from a module. + * + * For example: + * + * ```javascript + * module.exports = { + * inputs: { filename: { type: "string" } }, + * fn(inputs, exits) { ... } + * }; + * ``` + */ + private class Action2Action extends ObjectExpr { + Action2Action() { + exists(Module mod, DataFlow::FunctionNode fn | + mod.getABulkExportedNode().getALocalSource().asExpr() = this and + this.getFile().getRelativePath().regexpMatch("(^|.*/)api/controllers/.*") and + this.getPropertyByName("inputs").getInit() instanceof ObjectExpr and + fn = DataFlow::valueNode(this.getPropertyByName("fn").getInit()).getAFunctionValue() + ) + } + + /** + * Gets the `fn` function that handles the action. + */ + DataFlow::FunctionNode getFunction() { + result = DataFlow::valueNode(this.getPropertyByName("fn").getInit()).getAFunctionValue() + } + + /** + * Gets the name of an input declared by this action. + */ + string getADeclaredInputName() { + result = this.getPropertyByName("inputs").getInit().(ObjectExpr).getAProperty().getName() + } + } + + /** + * A Sails Action2 handler function. + */ + private class Action2RouteHandler extends Http::Servers::StandardRouteHandler, + DataFlow::FunctionNode + { + Action2Action action; + + Action2RouteHandler() { this = action.getFunction() } + + /** + * Gets the parameter of the action handler that contains the validated action inputs. + */ + DataFlow::ParameterNode getInputsParameter() { result = this.getParameter(0) } + + /** + * Gets the name of an input declared by this action. + */ + string getADeclaredInputName() { result = action.getADeclaredInputName() } + } + + /** + * An access to a user-controlled Sails Action2 input. + */ + private class Action2InputAccess extends Http::RequestInputAccess { + Action2RouteHandler rh; + + Action2InputAccess() { + this = rh.getInputsParameter().getAPropertyRead(rh.getADeclaredInputName()) + } + + override Action2RouteHandler getRouteHandler() { result = rh } + + override string getKind() { result = "parameter" } + } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll index 00929f19d279..3db8fa1b4364 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -53,6 +53,13 @@ predicate parseTypeString(string rawType, string package, string qualifiedName) qualifiedName = "" } +/** If `type` has the form `file:` gets the path to the file. */ +bindingset[type] +overlay[caller] +private string getRawFilePathFromTypeName(string type) { + result = type.regexpCapture("file:(.*)", 1) +} + /** * Holds if models describing `package` may be relevant for the analysis of this database. */ @@ -76,6 +83,8 @@ predicate isTypeUsed(string type) { parseTypeString(type, package, _) and isPackageUsed(package) ) + or + exists(getRawFilePathFromTypeName(type)) // No need to prune repository-specific models } /** @@ -126,6 +135,41 @@ private API::Node getGlobalNode(string globalName) { result = any(GlobalApiEntryPoint e | e.getGlobal() = globalName).getANode() } +/** Holds if `type` is used as a type string in a model, and has the form `file:` */ +overlay[local] +private predicate relevantRawFilePath(string type, string filePath) { + isRelevantType(type) and + filePath = getRawFilePathFromTypeName(type) +} + +/** An API graph entry point for package specifiers of form `file:`. */ +overlay[local?] +private class RawFilePathEntryPoint extends API::EntryPoint { + string path; + + RawFilePathEntryPoint() { + relevantRawFilePath(_, path) and + this = "RawFilePathEntryPoint:" + path + } + + override DataFlow::SourceNode getASource() { + exists(JS::Import imprt | + imprt.getImportedFile().getRelativePath() = path and + result = imprt.getImportedModuleNode() + ) + } + + /** Gets the file path being referenced. */ + string getPath() { result = path } +} + +/** + * Gets an API node referring to the given file path (if relevant). + */ +private API::Node getRawFilePathNode(string rawFilePathNode) { + result = any(RawFilePathEntryPoint e | e.getPath() = rawFilePathNode).getANode() +} + /** Gets a JavaScript-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */ bindingset[type, path] API::Node getExtraNodeFromPath(string type, AccessPath path, int n) { @@ -150,6 +194,11 @@ API::Node getExtraNodeFromType(string type) { // Access instance of a type based on type annotations result = API::Internal::getANodeOfTypeRaw(package, qualifiedName) ) + or + exists(string filePath | + relevantRawFilePath(type, filePath) and + result = getRawFilePathNode(filePath) + ) } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll index 8dd9c4831446..5cac49d6dd66 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll @@ -189,7 +189,9 @@ class RouteHandlerLimitedByRateLimiterFlexible extends RateLimitingMiddleware in { } private class FastifyRateLimiter extends RateLimitingMiddleware { - FastifyRateLimiter() { this = DataFlow::moduleImport("fastify-rate-limit") } + FastifyRateLimiter() { + this = DataFlow::moduleImport(["fastify-rate-limit", "@fastify/rate-limit"]) + } } /** diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index 2e8bcd543c25..87b01cbc4afa 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2.4.3 + +### Minor Analysis Improvements + +* The `js/missing-rate-limiting` query now recognizes the `@fastify/rate-limit` package as a rate limiter. + ## 2.4.2 No user-facing changes. diff --git a/javascript/ql/src/change-notes/released/2.4.3.md b/javascript/ql/src/change-notes/released/2.4.3.md new file mode 100644 index 000000000000..11f57d32a7a9 --- /dev/null +++ b/javascript/ql/src/change-notes/released/2.4.3.md @@ -0,0 +1,5 @@ +## 2.4.3 + +### Minor Analysis Improvements + +* The `js/missing-rate-limiting` query now recognizes the `@fastify/rate-limit` package as a rate limiter. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 660b0f7e51c9..2520785bcc40 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.4.2 +lastReleaseVersion: 2.4.3 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 3de8be964060..b21af7515f5b 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 2.4.2 +version: 2.4.3 groups: - javascript - queries diff --git a/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/assigned-action.js b/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/assigned-action.js new file mode 100644 index 000000000000..3e76b3714e0b --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/assigned-action.js @@ -0,0 +1,11 @@ +const action = { + inputs: { + name: { type: "string", required: true } + }, + + fn(inputs, exits) { + return exits.success(inputs.name); + } +}; + +module.exports = action; diff --git a/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/destructured-action.js b/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/destructured-action.js new file mode 100644 index 000000000000..7856c8bc052e --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/destructured-action.js @@ -0,0 +1,9 @@ +module.exports = { + inputs: { + filename: { type: "string", required: true } + }, + + async fn({ filename }, exits) { + return exits.success(filename); + } +}; diff --git a/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/download-thumbnail.js b/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/download-thumbnail.js new file mode 100644 index 000000000000..e78b4f0046ec --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/src/api/controllers/attachments/download-thumbnail.js @@ -0,0 +1,14 @@ +module.exports = { + inputs: { + id: { type: "string", regex: /^[0-9]+$/, required: true }, + filename: { type: "string", required: true } + }, + + async fn(inputs, exits) { + const id = inputs.id; + const filename = inputs.filename; + const notDeclared = inputs.notDeclared; + + return exits.success({ id, filename, notDeclared }); + } +}; diff --git a/javascript/ql/test/library-tests/frameworks/Sails/src/api/helpers/read-thumbnail.js b/javascript/ql/test/library-tests/frameworks/Sails/src/api/helpers/read-thumbnail.js new file mode 100644 index 000000000000..af84ce48f4cb --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/src/api/helpers/read-thumbnail.js @@ -0,0 +1,9 @@ +module.exports = { + inputs: { + filename: { type: "string", required: true } + }, + + async fn(inputs, exits) { + return exits.success(inputs.filename); + } +}; diff --git a/javascript/ql/test/library-tests/frameworks/Sails/src/lib/machine.js b/javascript/ql/test/library-tests/frameworks/Sails/src/lib/machine.js new file mode 100644 index 000000000000..7e07caf47c62 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/src/lib/machine.js @@ -0,0 +1,9 @@ +module.exports = { + inputs: { + filename: { type: "string", required: true } + }, + + fn(inputs, exits) { + return exits.success(inputs.filename); + } +}; diff --git a/javascript/ql/test/library-tests/frameworks/Sails/tests.expected b/javascript/ql/test/library-tests/frameworks/Sails/tests.expected new file mode 100644 index 000000000000..369aa08bc622 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/tests.expected @@ -0,0 +1,9 @@ +test_routeHandler +| src/api/controllers/attachments/assigned-action.js:6:5:8:3 | (inputs ... e);\\n } | +| src/api/controllers/attachments/destructured-action.js:6:11:8:3 | ({ file ... e);\\n } | +| src/api/controllers/attachments/download-thumbnail.js:7:11:13:3 | (inputs ... });\\n } | +test_requestInputAccess +| src/api/controllers/attachments/assigned-action.js:7:26:7:36 | inputs.name | parameter | +| src/api/controllers/attachments/destructured-action.js:6:14:6:21 | filename | parameter | +| src/api/controllers/attachments/download-thumbnail.js:8:16:8:24 | inputs.id | parameter | +| src/api/controllers/attachments/download-thumbnail.js:9:22:9:36 | inputs.filename | parameter | diff --git a/javascript/ql/test/library-tests/frameworks/Sails/tests.ql b/javascript/ql/test/library-tests/frameworks/Sails/tests.ql new file mode 100644 index 000000000000..9c7a7f4dc15b --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Sails/tests.ql @@ -0,0 +1,8 @@ +import javascript +import semmle.javascript.frameworks.Sails + +query predicate test_routeHandler(Http::RouteHandler rh) { any() } + +query predicate test_requestInputAccess(Http::RequestInputAccess ria, string kind) { + kind = ria.getKind() +} diff --git a/javascript/ql/test/library-tests/frameworks/Vue/router.js b/javascript/ql/test/library-tests/frameworks/Vue/router.js index 65dc4d13e99e..efae87483443 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/router.js +++ b/javascript/ql/test/library-tests/frameworks/Vue/router.js @@ -1,4 +1,4 @@ -import Router from 'vue-router'; +import Router, { useRoute } from 'vue-router'; export const router = new Router({ routes: [ @@ -43,3 +43,5 @@ router.afterEach((to, from) => { to.query.x; from.query.x; }); + +useRoute().query; diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected index 633a8f9924db..4ba7ba338637 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected @@ -191,6 +191,7 @@ remoteFlowSource | router.js:39:5:39:14 | from.query | | router.js:43:5:43:12 | to.query | | router.js:44:5:44:14 | from.query | +| router.js:47:1:47:16 | useRoute().query | parseErrors attribute | compont-with-route.vue:2:8:2:21 | v-html=dataA | v-html | @@ -239,6 +240,8 @@ threatModelSource | router.js:39:5:39:14 | from.query | remote | | router.js:43:5:43:12 | to.query | remote | | router.js:44:5:44:14 | from.query | remote | +| router.js:47:1:47:16 | useRoute().query | browser-url-query | +| router.js:47:1:47:16 | useRoute().query | remote | | single-component-file-1.vue:7:45:7:54 | this.input | view-component-input | | single-file-component-3-script.js:5:42:5:51 | this.input | view-component-input | | single-file-component-4.vue:21:14:21:23 | this.input | view-component-input | @@ -246,3 +249,16 @@ threatModelSource | single-file-component-6.vue:5:11:5:15 | input | view-component-input | | single-file-component-7.vue:5:11:5:15 | input | view-component-input | | single-file-component-8.vue:5:11:5:15 | input | view-component-input | +compositionApiDataFlow +| tst.js:119:14:119:26 | source("ref") | tst.js:119:6:119:33 | Vue.ref ... ).value | +| tst.js:120:21:120:40 | source("shallowRef") | tst.js:120:6:120:47 | Vue.sha ... ).value | +| tst.js:121:16:121:30 | source("toRef") | tst.js:121:6:121:37 | Vue.toR ... ).value | +| tst.js:123:25:123:42 | source("computed") | tst.js:123:6:123:49 | Vue.com ... ).value | +| tst.js:124:36:124:59 | source( ... bject") | tst.js:124:6:124:82 | Vue.com ... ).value | +compositionApiTaintFlow +| tst.js:119:14:119:26 | source("ref") | tst.js:119:6:119:33 | Vue.ref ... ).value | +| tst.js:120:21:120:40 | source("shallowRef") | tst.js:120:6:120:47 | Vue.sha ... ).value | +| tst.js:121:16:121:30 | source("toRef") | tst.js:121:6:121:37 | Vue.toR ... ).value | +| tst.js:122:19:122:36 | source("reactive") | tst.js:122:6:122:37 | Vue.rea ... tive")) | +| tst.js:123:25:123:42 | source("computed") | tst.js:123:6:123:49 | Vue.com ... ).value | +| tst.js:124:36:124:59 | source( ... bject") | tst.js:124:6:124:82 | Vue.com ... ).value | diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.ql b/javascript/ql/test/library-tests/frameworks/Vue/tests.ql index c631f46d3293..6121a7f9a46b 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.ql @@ -1,6 +1,24 @@ import javascript import semmle.javascript.security.dataflow.DomBasedXssCustomizations +module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source.(DataFlow::CallNode).getCalleeName() = "source" + } + + predicate isSink(DataFlow::Node sink) { + sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() + } +} + +module TestDataFlow = DataFlow::Global; + +module TestTaintFlow = TaintTracking::Global; + +query predicate compositionApiDataFlow = TestDataFlow::flow/2; + +query predicate compositionApiTaintFlow = TestTaintFlow::flow/2; + query predicate component_getAPropertyValue(Vue::Component c, string name, DataFlow::Node prop) { c.getAPropertyValue(name) = prop } diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tst.js b/javascript/ql/test/library-tests/frameworks/Vue/tst.js index 6ee0954063a9..d402668c2e1d 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Vue/tst.js @@ -115,3 +115,10 @@ let subclass2 = base.extend({ fromSubclass2: 100 } }); + +sink(Vue.ref(source("ref")).value); +sink(Vue.shallowRef(source("shallowRef")).value); +sink(Vue.toRef(source("toRef")).value); +sink(Vue.reactive(source("reactive"))); +sink(Vue.computed(() => source("computed")).value); +sink(Vue.computed({ get() { return source("computedObject"); }, set(v) {} }).value); diff --git a/javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js b/javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js new file mode 100644 index 000000000000..bb1843d113a5 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/data/foo/bar/baz.js @@ -0,0 +1 @@ +export const foo = 1; diff --git a/javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js b/javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js new file mode 100644 index 000000000000..4fcb5c3dc1cf --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/data/importFileBasedModel.js @@ -0,0 +1,5 @@ +import * as bar from './foo/bar/baz'; + +function t1() { + sink(bar.customSource()); // NOT OK +} diff --git a/javascript/ql/test/library-tests/frameworks/data/test.expected b/javascript/ql/test/library-tests/frameworks/data/test.expected index 0bc1b6b6ee07..0f945b6c3515 100644 --- a/javascript/ql/test/library-tests/frameworks/data/test.expected +++ b/javascript/ql/test/library-tests/frameworks/data/test.expected @@ -5,6 +5,7 @@ taintFlow | guardedRouteHandler.js:10:10:10:28 | res.injectedResData | guardedRouteHandler.js:10:10:10:28 | res.injectedResData | | guardedRouteHandler.js:16:10:16:28 | req.injectedReqData | guardedRouteHandler.js:16:10:16:28 | req.injectedReqData | | guardedRouteHandler.js:20:10:20:28 | res.injectedResData | guardedRouteHandler.js:20:10:20:28 | res.injectedResData | +| importFileBasedModel.js:4:10:4:27 | bar.customSource() | importFileBasedModel.js:4:10:4:27 | bar.customSource() | | paramDecorator.ts:6:54:6:54 | x | paramDecorator.ts:7:10:7:10 | x | | test.js:5:30:5:37 | source() | test.js:5:8:5:38 | testlib ... urce()) | | test.js:6:22:6:29 | source() | test.js:6:8:6:30 | preserv ... urce()) | diff --git a/javascript/ql/test/library-tests/frameworks/data/test.ext.yml b/javascript/ql/test/library-tests/frameworks/data/test.ext.yml index 1ac621936a4a..868a8d18998c 100644 --- a/javascript/ql/test/library-tests/frameworks/data/test.ext.yml +++ b/javascript/ql/test/library-tests/frameworks/data/test.ext.yml @@ -15,6 +15,7 @@ extensions: - ['danger-constant', 'Member[danger]', 'test-source'] - ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[0].Member[injectedReqData]', 'test-source'] - ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[1].Member[injectedResData]', 'test-source'] + - ['file:foo/bar/baz.js', 'Member[customSource].ReturnValue', 'test-source'] - addsTo: pack: codeql/javascript-all diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 833128c12924..3f854c95b7d8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -47,6 +47,7 @@ | TaintedPath.js:205:31:205:69 | path.re ... '), '') | TaintedPath.js:200:24:200:30 | req.url | TaintedPath.js:205:31:205:69 | path.re ... '), '') | This path depends on a $@. | TaintedPath.js:200:24:200:30 | req.url | user-provided value | | TaintedPath.js:214:29:214:42 | improperEscape | TaintedPath.js:212:24:212:30 | req.url | TaintedPath.js:214:29:214:42 | improperEscape | This path depends on a $@. | TaintedPath.js:212:24:212:30 | req.url | user-provided value | | TaintedPath.js:216:29:216:43 | improperEscape2 | TaintedPath.js:212:24:212:30 | req.url | TaintedPath.js:216:29:216:43 | improperEscape2 | This path depends on a $@. | TaintedPath.js:212:24:212:30 | req.url | user-provided value | +| api/controllers/attachments/download-thumbnail.js:18:42:18:49 | filePath | api/controllers/attachments/download-thumbnail.js:15:7:15:21 | inputs.filename | api/controllers/attachments/download-thumbnail.js:18:42:18:49 | filePath | This path depends on a $@. | api/controllers/attachments/download-thumbnail.js:15:7:15:21 | inputs.filename | user-provided value | | examples/TaintedPath.js:10:29:10:43 | ROOT + filePath | examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:10:29:10:43 | ROOT + filePath | This path depends on a $@. | examples/TaintedPath.js:8:28:8:34 | req.url | user-provided value | | execa.js:9:26:9:33 | filePath | execa.js:6:30:6:36 | req.url | execa.js:9:26:9:33 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | | execa.js:12:37:12:44 | filePath | execa.js:6:30:6:36 | req.url | execa.js:12:37:12:44 | filePath | This path depends on a $@. | execa.js:6:30:6:36 | req.url | user-provided value | @@ -397,6 +398,9 @@ edges | TaintedPath.js:215:9:215:23 | improperEscape2 | TaintedPath.js:216:29:216:43 | improperEscape2 | provenance | | | TaintedPath.js:215:27:215:40 | unescape(path) | TaintedPath.js:215:9:215:23 | improperEscape2 | provenance | | | TaintedPath.js:215:36:215:39 | path | TaintedPath.js:215:27:215:40 | unescape(path) | provenance | Config | +| api/controllers/attachments/download-thumbnail.js:11:9:11:16 | filePath | api/controllers/attachments/download-thumbnail.js:18:42:18:49 | filePath | provenance | | +| api/controllers/attachments/download-thumbnail.js:11:20:16:5 | path.jo ... e\\n ) | api/controllers/attachments/download-thumbnail.js:11:9:11:16 | filePath | provenance | | +| api/controllers/attachments/download-thumbnail.js:15:7:15:21 | inputs.filename | api/controllers/attachments/download-thumbnail.js:11:20:16:5 | path.jo ... e\\n ) | provenance | Config | | examples/TaintedPath.js:8:7:8:14 | filePath | examples/TaintedPath.js:10:36:10:43 | filePath | provenance | | | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | provenance | Config | | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | examples/TaintedPath.js:8:18:8:52 | url.par ... ry.path | provenance | Config | @@ -950,6 +954,10 @@ nodes | TaintedPath.js:215:27:215:40 | unescape(path) | semmle.label | unescape(path) | | TaintedPath.js:215:36:215:39 | path | semmle.label | path | | TaintedPath.js:216:29:216:43 | improperEscape2 | semmle.label | improperEscape2 | +| api/controllers/attachments/download-thumbnail.js:11:9:11:16 | filePath | semmle.label | filePath | +| api/controllers/attachments/download-thumbnail.js:11:20:16:5 | path.jo ... e\\n ) | semmle.label | path.jo ... e\\n ) | +| api/controllers/attachments/download-thumbnail.js:15:7:15:21 | inputs.filename | semmle.label | inputs.filename | +| api/controllers/attachments/download-thumbnail.js:18:42:18:49 | filePath | semmle.label | filePath | | examples/TaintedPath.js:8:7:8:14 | filePath | semmle.label | filePath | | examples/TaintedPath.js:8:18:8:41 | url.par ... , true) | semmle.label | url.par ... , true) | | examples/TaintedPath.js:8:18:8:47 | url.par ... ).query | semmle.label | url.par ... ).query | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/api/controllers/attachments/download-thumbnail.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/api/controllers/attachments/download-thumbnail.js new file mode 100644 index 000000000000..fdd9df4d2ddf --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/api/controllers/attachments/download-thumbnail.js @@ -0,0 +1,25 @@ +var fs = require("fs"); +var path = require("path"); + +module.exports = { + inputs: { + id: { type: "string", regex: /^[0-9]+$/, required: true }, + filename: { type: "string", required: true } + }, + + async fn(inputs, exits) { + var filePath = path.join( + "/srv/app/attachments", + "42", + "thumbnails", + inputs.filename // $ Source + ); + + return exits.success(fs.readFileSync(filePath)); // $ Alert + } +}; + +function localInputsAreNotRequests(inputs) { + var filePath = path.join("/srv/app/attachments", inputs.filename); + return fs.readFileSync(filePath); +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected index 99cafddc41d2..8d4eae0a7083 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected @@ -1,5 +1,19 @@ #select +| fetch-promise-chain.js:21:47:21:49 | row | fetch-promise-chain.js:7:3:7:12 | fetch(url) | fetch-promise-chain.js:21:47:21:49 | row | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:7:3:7:12 | fetch(url) | user-provided value | +| fetch-promise-chain.js:30:33:30:36 | text | fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | fetch-promise-chain.js:30:33:30:36 | text | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:47:33:47:44 | data.message | fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | fetch-promise-chain.js:47:33:47:44 | data.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:57:33:57:36 | text | fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | fetch-promise-chain.js:57:33:57:36 | text | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:67:55:67:66 | item.message | fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | fetch-promise-chain.js:67:55:67:66 | item.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:76:33:76:39 | message | fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | fetch-promise-chain.js:76:33:76:39 | message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:84:33:84:44 | data.message | fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | fetch-promise-chain.js:84:33:84:44 | data.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:93:31:93:42 | data.message | fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | fetch-promise-chain.js:93:31:93:42 | data.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | user-provided value | +| fetch-promise-chain.js:102:33:102:47 | payload.message | fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | fetch-promise-chain.js:102:33:102:47 | payload.message | Cross-site scripting vulnerability due to $@. | fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | user-provided value | | interceptors.js:9:56:9:72 | userGeneratedHtml | interceptors.js:7:6:7:13 | response | interceptors.js:9:56:9:72 | userGeneratedHtml | Cross-site scripting vulnerability due to $@. | interceptors.js:7:6:7:13 | response | user-provided value | +| non-fetch-promise-chain.js:5:33:5:36 | body | non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | non-fetch-promise-chain.js:5:33:5:36 | body | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | user-provided value | +| non-fetch-promise-chain.js:13:33:13:44 | data.message | non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | non-fetch-promise-chain.js:13:33:13:44 | data.message | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | user-provided value | +| non-fetch-promise-chain.js:21:31:21:51 | respons ... message | non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | non-fetch-promise-chain.js:21:31:21:51 | respons ... message | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | user-provided value | +| non-fetch-promise-chain.js:29:33:29:53 | respons ... message | non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | non-fetch-promise-chain.js:29:33:29:53 | respons ... message | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | user-provided value | +| non-fetch-promise-chain.js:37:33:37:45 | response.text | non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | non-fetch-promise-chain.js:37:33:37:45 | response.text | Cross-site scripting vulnerability due to $@. | non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | user-provided value | | test.jsx:27:29:27:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:27:29:27:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5:63 | fetch(" ... ntent") | user-provided value | | test.ts:21:57:21:76 | response.description | test.ts:8:9:8:79 | this.#h ... query') | test.ts:21:57:21:76 | response.description | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value | | test.ts:24:36:24:90 | `

${ ... o}

` | test.ts:8:9:8:79 | this.#h ... query') | test.ts:24:36:24:90 | `

${ ... o}

` | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value | @@ -19,9 +33,121 @@ | testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | user-provided value | | testUseQueries.vue:25:10:25:23 | v-html=data2 | testUseQueries.vue:11:36:11:49 | fetch("${id}") | testUseQueries.vue:25:10:25:23 | v-html=data2 | Cross-site scripting vulnerability due to $@. | testUseQueries.vue:11:36:11:49 | fetch("${id}") | user-provided value | edges +| fetch-promise-chain.js:7:3:7:12 | fetch(url) | fetch-promise-chain.js:8:11:8:18 | response | provenance | | +| fetch-promise-chain.js:7:3:8:38 | fetch(u ... json()) [PromiseValue] | fetch-promise-chain.js:9:11:9:14 | data | provenance | | +| fetch-promise-chain.js:8:11:8:18 | response | fetch-promise-chain.js:8:23:8:30 | response | provenance | | +| fetch-promise-chain.js:8:23:8:30 | response | fetch-promise-chain.js:8:23:8:37 | response.json() | provenance | | +| fetch-promise-chain.js:8:23:8:37 | response.json() | fetch-promise-chain.js:7:3:8:38 | fetch(u ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:9:11:9:14 | data | fetch-promise-chain.js:13:7:13:10 | data | provenance | | +| fetch-promise-chain.js:13:7:13:10 | data | fetch-promise-chain.js:13:7:13:16 | data.items | provenance | | +| fetch-promise-chain.js:13:7:13:16 | data.items | fetch-promise-chain.js:13:26:13:29 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:14:55:14:58 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:16:17:16:20 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:17:17:17:20 | item | provenance | | +| fetch-promise-chain.js:13:26:13:29 | item | fetch-promise-chain.js:18:17:18:20 | item | provenance | | +| fetch-promise-chain.js:14:15:14:18 | link | fetch-promise-chain.js:19:17:19:20 | link | provenance | | +| fetch-promise-chain.js:14:22:14:88 | `` | fetch-promise-chain.js:14:15:14:18 | link | provenance | | +| fetch-promise-chain.js:14:55:14:58 | item | fetch-promise-chain.js:14:55:14:68 | item.messageId | provenance | | +| fetch-promise-chain.js:14:55:14:68 | item.messageId | fetch-promise-chain.js:14:22:14:88 | `` | provenance | | +| fetch-promise-chain.js:15:15:15:17 | row | fetch-promise-chain.js:21:47:21:49 | row | provenance | | +| fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | fetch-promise-chain.js:15:15:15:17 | row | provenance | | +| fetch-promise-chain.js:16:17:16:20 | item | fetch-promise-chain.js:16:17:16:32 | item.createdDate | provenance | | +| fetch-promise-chain.js:16:17:16:32 | item.createdDate | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:17:17:17:20 | item | fetch-promise-chain.js:17:17:17:30 | item.messageId | provenance | | +| fetch-promise-chain.js:17:17:17:30 | item.messageId | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:18:17:18:20 | item | fetch-promise-chain.js:18:17:18:33 | item.target ?? "" | provenance | | +| fetch-promise-chain.js:18:17:18:33 | item.target ?? "" | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:19:17:19:20 | link | fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | provenance | | +| fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | fetch-promise-chain.js:28:11:28:18 | response | provenance | | +| fetch-promise-chain.js:27:3:28:38 | fetch(" ... text()) [PromiseValue] | fetch-promise-chain.js:29:11:29:14 | text | provenance | | +| fetch-promise-chain.js:28:11:28:18 | response | fetch-promise-chain.js:28:23:28:30 | response | provenance | | +| fetch-promise-chain.js:28:23:28:30 | response | fetch-promise-chain.js:28:23:28:37 | response.text() | provenance | | +| fetch-promise-chain.js:28:23:28:37 | response.text() | fetch-promise-chain.js:27:3:28:38 | fetch(" ... text()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:29:11:29:14 | text | fetch-promise-chain.js:30:33:30:36 | text | provenance | | +| fetch-promise-chain.js:43:9:43:15 | request | fetch-promise-chain.js:44:3:44:9 | request | provenance | | +| fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | fetch-promise-chain.js:43:9:43:15 | request | provenance | | +| fetch-promise-chain.js:44:3:44:9 | request | fetch-promise-chain.js:45:11:45:18 | response | provenance | | +| fetch-promise-chain.js:44:3:45:38 | request ... json()) [PromiseValue] | fetch-promise-chain.js:46:11:46:14 | data | provenance | | +| fetch-promise-chain.js:45:11:45:18 | response | fetch-promise-chain.js:45:23:45:30 | response | provenance | | +| fetch-promise-chain.js:45:23:45:30 | response | fetch-promise-chain.js:45:23:45:37 | response.json() | provenance | | +| fetch-promise-chain.js:45:23:45:37 | response.json() | fetch-promise-chain.js:44:3:45:38 | request ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:46:11:46:14 | data | fetch-promise-chain.js:47:33:47:36 | data | provenance | | +| fetch-promise-chain.js:47:33:47:36 | data | fetch-promise-chain.js:47:33:47:44 | data.message | provenance | | +| fetch-promise-chain.js:53:3:53:9 | request | fetch-promise-chain.js:54:3:54:9 | request | provenance | | +| fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | fetch-promise-chain.js:53:3:53:9 | request | provenance | | +| fetch-promise-chain.js:54:3:54:9 | request | fetch-promise-chain.js:55:11:55:18 | response | provenance | | +| fetch-promise-chain.js:54:3:55:38 | request ... text()) [PromiseValue] | fetch-promise-chain.js:56:11:56:14 | text | provenance | | +| fetch-promise-chain.js:55:11:55:18 | response | fetch-promise-chain.js:55:23:55:30 | response | provenance | | +| fetch-promise-chain.js:55:23:55:30 | response | fetch-promise-chain.js:55:23:55:37 | response.text() | provenance | | +| fetch-promise-chain.js:55:23:55:37 | response.text() | fetch-promise-chain.js:54:3:55:38 | request ... text()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:56:11:56:14 | text | fetch-promise-chain.js:57:33:57:36 | text | provenance | | +| fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | fetch-promise-chain.js:63:11:63:18 | response | provenance | | +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | provenance | | +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:64:11:64:14 | data | provenance | | +| fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | fetch-promise-chain.js:65:11:65:15 | items | provenance | | +| fetch-promise-chain.js:63:11:63:18 | response | fetch-promise-chain.js:63:23:63:30 | response | provenance | | +| fetch-promise-chain.js:63:23:63:30 | response | fetch-promise-chain.js:63:23:63:37 | response.json() | provenance | | +| fetch-promise-chain.js:63:23:63:37 | response.json() | fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:64:11:64:14 | data | fetch-promise-chain.js:64:19:64:22 | data | provenance | | +| fetch-promise-chain.js:64:19:64:22 | data | fetch-promise-chain.js:64:19:64:28 | data.items | provenance | | +| fetch-promise-chain.js:65:11:65:15 | items | fetch-promise-chain.js:66:7:66:11 | items | provenance | | +| fetch-promise-chain.js:66:7:66:11 | items | fetch-promise-chain.js:66:21:66:24 | item | provenance | | +| fetch-promise-chain.js:66:21:66:24 | item | fetch-promise-chain.js:67:55:67:58 | item | provenance | | +| fetch-promise-chain.js:67:55:67:58 | item | fetch-promise-chain.js:67:55:67:66 | item.message | provenance | | +| fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | fetch-promise-chain.js:74:11:74:18 | response | provenance | | +| fetch-promise-chain.js:73:3:74:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:75:12:75:22 | { message } | provenance | | +| fetch-promise-chain.js:74:11:74:18 | response | fetch-promise-chain.js:74:23:74:30 | response | provenance | | +| fetch-promise-chain.js:74:23:74:30 | response | fetch-promise-chain.js:74:23:74:37 | response.json() | provenance | | +| fetch-promise-chain.js:74:23:74:37 | response.json() | fetch-promise-chain.js:73:3:74:38 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:75:12:75:22 | { message } | fetch-promise-chain.js:75:14:75:20 | message | provenance | | +| fetch-promise-chain.js:75:14:75:20 | message | fetch-promise-chain.js:76:33:76:39 | message | provenance | | +| fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | fetch-promise-chain.js:82:17:82:24 | response | provenance | | +| fetch-promise-chain.js:81:3:82:50 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:83:11:83:14 | data | provenance | | +| fetch-promise-chain.js:82:17:82:24 | response | fetch-promise-chain.js:82:35:82:42 | response | provenance | | +| fetch-promise-chain.js:82:29:82:49 | await r ... .json() | fetch-promise-chain.js:81:3:82:50 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:82:35:82:42 | response | fetch-promise-chain.js:82:35:82:49 | response.json() | provenance | | +| fetch-promise-chain.js:82:35:82:49 | response.json() | fetch-promise-chain.js:82:29:82:49 | await r ... .json() | provenance | | +| fetch-promise-chain.js:83:11:83:14 | data | fetch-promise-chain.js:84:33:84:36 | data | provenance | | +| fetch-promise-chain.js:84:33:84:36 | data | fetch-promise-chain.js:84:33:84:44 | data.message | provenance | | +| fetch-promise-chain.js:89:3:92:4 | Promise ... ))\\n ]) [PromiseValue, 0] | fetch-promise-chain.js:92:12:92:17 | [data] [0] | provenance | | +| fetch-promise-chain.js:89:15:92:3 | [\\n f ... ())\\n ] [0, PromiseValue] | fetch-promise-chain.js:89:3:92:4 | Promise ... ))\\n ]) [PromiseValue, 0] | provenance | | +| fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | fetch-promise-chain.js:91:13:91:20 | response | provenance | | +| fetch-promise-chain.js:90:5:91:40 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:89:15:92:3 | [\\n f ... ())\\n ] [0, PromiseValue] | provenance | | +| fetch-promise-chain.js:91:13:91:20 | response | fetch-promise-chain.js:91:25:91:32 | response | provenance | | +| fetch-promise-chain.js:91:25:91:32 | response | fetch-promise-chain.js:91:25:91:39 | response.json() | provenance | | +| fetch-promise-chain.js:91:25:91:39 | response.json() | fetch-promise-chain.js:90:5:91:40 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:92:12:92:17 | [data] [0] | fetch-promise-chain.js:92:13:92:16 | data | provenance | | +| fetch-promise-chain.js:92:13:92:16 | data | fetch-promise-chain.js:92:13:92:16 | data | provenance | | +| fetch-promise-chain.js:92:13:92:16 | data | fetch-promise-chain.js:93:31:93:34 | data | provenance | | +| fetch-promise-chain.js:93:31:93:34 | data | fetch-promise-chain.js:93:31:93:42 | data.message | provenance | | +| fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | fetch-promise-chain.js:99:11:99:18 | response | provenance | | +| fetch-promise-chain.js:98:3:99:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:100:11:100:14 | data | provenance | | +| fetch-promise-chain.js:99:11:99:18 | response | fetch-promise-chain.js:99:23:99:30 | response | provenance | | +| fetch-promise-chain.js:99:23:99:30 | response | fetch-promise-chain.js:99:23:99:37 | response.json() | provenance | | +| fetch-promise-chain.js:99:23:99:37 | response.json() | fetch-promise-chain.js:98:3:99:38 | fetch(" ... json()) [PromiseValue] | provenance | | +| fetch-promise-chain.js:100:11:100:14 | data | fetch-promise-chain.js:101:23:101:26 | data | provenance | | +| fetch-promise-chain.js:101:13:101:19 | payload | fetch-promise-chain.js:102:33:102:39 | payload | provenance | | +| fetch-promise-chain.js:101:23:101:26 | data | fetch-promise-chain.js:101:13:101:19 | payload | provenance | | +| fetch-promise-chain.js:102:33:102:39 | payload | fetch-promise-chain.js:102:33:102:47 | payload.message | provenance | | | interceptors.js:7:6:7:13 | response | interceptors.js:8:35:8:42 | response | provenance | | | interceptors.js:8:15:8:31 | userGeneratedHtml | interceptors.js:9:56:9:72 | userGeneratedHtml | provenance | | | interceptors.js:8:35:8:42 | response | interceptors.js:8:15:8:31 | userGeneratedHtml | provenance | | +| non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | non-fetch-promise-chain.js:4:11:4:14 | body | provenance | | +| non-fetch-promise-chain.js:4:11:4:14 | body | non-fetch-promise-chain.js:5:33:5:36 | body | provenance | | +| non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | non-fetch-promise-chain.js:12:11:12:14 | data | provenance | | +| non-fetch-promise-chain.js:12:11:12:14 | data | non-fetch-promise-chain.js:13:33:13:36 | data | provenance | | +| non-fetch-promise-chain.js:13:33:13:36 | data | non-fetch-promise-chain.js:13:33:13:44 | data.message | provenance | | +| non-fetch-promise-chain.js:19:9:19:15 | request | non-fetch-promise-chain.js:20:3:20:9 | request | provenance | | +| non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | non-fetch-promise-chain.js:19:9:19:15 | request | provenance | | +| non-fetch-promise-chain.js:20:3:20:9 | request | non-fetch-promise-chain.js:20:16:20:23 | response | provenance | | +| non-fetch-promise-chain.js:20:16:20:23 | response | non-fetch-promise-chain.js:21:31:21:38 | response | provenance | | +| non-fetch-promise-chain.js:21:31:21:38 | response | non-fetch-promise-chain.js:21:31:21:51 | respons ... message | provenance | | +| non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | non-fetch-promise-chain.js:28:11:28:18 | response | provenance | | +| non-fetch-promise-chain.js:28:11:28:18 | response | non-fetch-promise-chain.js:29:33:29:40 | response | provenance | | +| non-fetch-promise-chain.js:29:33:29:40 | response | non-fetch-promise-chain.js:29:33:29:53 | respons ... message | provenance | | +| non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | non-fetch-promise-chain.js:36:11:36:18 | response | provenance | | +| non-fetch-promise-chain.js:36:11:36:18 | response | non-fetch-promise-chain.js:37:33:37:40 | response | provenance | | +| non-fetch-promise-chain.js:37:33:37:40 | response | non-fetch-promise-chain.js:37:33:37:45 | response.text | provenance | | | test.jsx:5:11:5:18 | response | test.jsx:6:24:6:31 | response | provenance | | | test.jsx:5:22:5:63 | await f ... ntent") | test.jsx:5:11:5:18 | response | provenance | | | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:5:22:5:63 | await f ... ntent") | provenance | | @@ -100,10 +226,133 @@ edges | testUseQueries.vue:12:20:12:34 | response.json() | testUseQueries.vue:18:22:18:36 | results[0].data | provenance | | | testUseQueries.vue:18:22:18:36 | results[0].data | testUseQueries.vue:25:10:25:23 | v-html=data2 | provenance | | nodes +| fetch-promise-chain.js:7:3:7:12 | fetch(url) | semmle.label | fetch(url) | +| fetch-promise-chain.js:7:3:8:38 | fetch(u ... json()) [PromiseValue] | semmle.label | fetch(u ... json()) [PromiseValue] | +| fetch-promise-chain.js:8:11:8:18 | response | semmle.label | response | +| fetch-promise-chain.js:8:23:8:30 | response | semmle.label | response | +| fetch-promise-chain.js:8:23:8:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:9:11:9:14 | data | semmle.label | data | +| fetch-promise-chain.js:13:7:13:10 | data | semmle.label | data | +| fetch-promise-chain.js:13:7:13:16 | data.items | semmle.label | data.items | +| fetch-promise-chain.js:13:26:13:29 | item | semmle.label | item | +| fetch-promise-chain.js:14:15:14:18 | link | semmle.label | link | +| fetch-promise-chain.js:14:22:14:88 | `` | semmle.label | `` | +| fetch-promise-chain.js:14:55:14:58 | item | semmle.label | item | +| fetch-promise-chain.js:14:55:14:68 | item.messageId | semmle.label | item.messageId | +| fetch-promise-chain.js:15:15:15:17 | row | semmle.label | row | +| fetch-promise-chain.js:15:21:20:14 | `\\n ... ` | semmle.label | `\\n ... ` | +| fetch-promise-chain.js:16:17:16:20 | item | semmle.label | item | +| fetch-promise-chain.js:16:17:16:32 | item.createdDate | semmle.label | item.createdDate | +| fetch-promise-chain.js:17:17:17:20 | item | semmle.label | item | +| fetch-promise-chain.js:17:17:17:30 | item.messageId | semmle.label | item.messageId | +| fetch-promise-chain.js:18:17:18:20 | item | semmle.label | item | +| fetch-promise-chain.js:18:17:18:33 | item.target ?? "" | semmle.label | item.target ?? "" | +| fetch-promise-chain.js:19:17:19:20 | link | semmle.label | link | +| fetch-promise-chain.js:21:47:21:49 | row | semmle.label | row | +| fetch-promise-chain.js:27:3:27:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:27:3:28:38 | fetch(" ... text()) [PromiseValue] | semmle.label | fetch(" ... text()) [PromiseValue] | +| fetch-promise-chain.js:28:11:28:18 | response | semmle.label | response | +| fetch-promise-chain.js:28:23:28:30 | response | semmle.label | response | +| fetch-promise-chain.js:28:23:28:37 | response.text() | semmle.label | response.text() | +| fetch-promise-chain.js:29:11:29:14 | text | semmle.label | text | +| fetch-promise-chain.js:30:33:30:36 | text | semmle.label | text | +| fetch-promise-chain.js:43:9:43:15 | request | semmle.label | request | +| fetch-promise-chain.js:43:19:43:39 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:44:3:44:9 | request | semmle.label | request | +| fetch-promise-chain.js:44:3:45:38 | request ... json()) [PromiseValue] | semmle.label | request ... json()) [PromiseValue] | +| fetch-promise-chain.js:45:11:45:18 | response | semmle.label | response | +| fetch-promise-chain.js:45:23:45:30 | response | semmle.label | response | +| fetch-promise-chain.js:45:23:45:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:46:11:46:14 | data | semmle.label | data | +| fetch-promise-chain.js:47:33:47:36 | data | semmle.label | data | +| fetch-promise-chain.js:47:33:47:44 | data.message | semmle.label | data.message | +| fetch-promise-chain.js:53:3:53:9 | request | semmle.label | request | +| fetch-promise-chain.js:53:13:53:33 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:54:3:54:9 | request | semmle.label | request | +| fetch-promise-chain.js:54:3:55:38 | request ... text()) [PromiseValue] | semmle.label | request ... text()) [PromiseValue] | +| fetch-promise-chain.js:55:11:55:18 | response | semmle.label | response | +| fetch-promise-chain.js:55:23:55:30 | response | semmle.label | response | +| fetch-promise-chain.js:55:23:55:37 | response.text() | semmle.label | response.text() | +| fetch-promise-chain.js:56:11:56:14 | text | semmle.label | text | +| fetch-promise-chain.js:57:33:57:36 | text | semmle.label | text | +| fetch-promise-chain.js:62:3:62:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | semmle.label | fetch(" ... .items) [PromiseValue] | +| fetch-promise-chain.js:63:11:63:18 | response | semmle.label | response | +| fetch-promise-chain.js:63:23:63:30 | response | semmle.label | response | +| fetch-promise-chain.js:63:23:63:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:64:11:64:14 | data | semmle.label | data | +| fetch-promise-chain.js:64:19:64:22 | data | semmle.label | data | +| fetch-promise-chain.js:64:19:64:28 | data.items | semmle.label | data.items | +| fetch-promise-chain.js:65:11:65:15 | items | semmle.label | items | +| fetch-promise-chain.js:66:7:66:11 | items | semmle.label | items | +| fetch-promise-chain.js:66:21:66:24 | item | semmle.label | item | +| fetch-promise-chain.js:67:55:67:58 | item | semmle.label | item | +| fetch-promise-chain.js:67:55:67:66 | item.message | semmle.label | item.message | +| fetch-promise-chain.js:73:3:73:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:73:3:74:38 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:74:11:74:18 | response | semmle.label | response | +| fetch-promise-chain.js:74:23:74:30 | response | semmle.label | response | +| fetch-promise-chain.js:74:23:74:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:75:12:75:22 | { message } | semmle.label | { message } | +| fetch-promise-chain.js:75:14:75:20 | message | semmle.label | message | +| fetch-promise-chain.js:76:33:76:39 | message | semmle.label | message | +| fetch-promise-chain.js:81:3:81:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:81:3:82:50 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:82:17:82:24 | response | semmle.label | response | +| fetch-promise-chain.js:82:29:82:49 | await r ... .json() | semmle.label | await r ... .json() | +| fetch-promise-chain.js:82:35:82:42 | response | semmle.label | response | +| fetch-promise-chain.js:82:35:82:49 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:83:11:83:14 | data | semmle.label | data | +| fetch-promise-chain.js:84:33:84:36 | data | semmle.label | data | +| fetch-promise-chain.js:84:33:84:44 | data.message | semmle.label | data.message | +| fetch-promise-chain.js:89:3:92:4 | Promise ... ))\\n ]) [PromiseValue, 0] | semmle.label | Promise ... ))\\n ]) [PromiseValue, 0] | +| fetch-promise-chain.js:89:15:92:3 | [\\n f ... ())\\n ] [0, PromiseValue] | semmle.label | [\\n f ... ())\\n ] [0, PromiseValue] | +| fetch-promise-chain.js:90:5:90:25 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:90:5:91:40 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:91:13:91:20 | response | semmle.label | response | +| fetch-promise-chain.js:91:25:91:32 | response | semmle.label | response | +| fetch-promise-chain.js:91:25:91:39 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:92:12:92:17 | [data] [0] | semmle.label | [data] [0] | +| fetch-promise-chain.js:92:13:92:16 | data | semmle.label | data | +| fetch-promise-chain.js:92:13:92:16 | data | semmle.label | data | +| fetch-promise-chain.js:93:31:93:34 | data | semmle.label | data | +| fetch-promise-chain.js:93:31:93:42 | data.message | semmle.label | data.message | +| fetch-promise-chain.js:98:3:98:23 | fetch(" ... ssage") | semmle.label | fetch(" ... ssage") | +| fetch-promise-chain.js:98:3:99:38 | fetch(" ... json()) [PromiseValue] | semmle.label | fetch(" ... json()) [PromiseValue] | +| fetch-promise-chain.js:99:11:99:18 | response | semmle.label | response | +| fetch-promise-chain.js:99:23:99:30 | response | semmle.label | response | +| fetch-promise-chain.js:99:23:99:37 | response.json() | semmle.label | response.json() | +| fetch-promise-chain.js:100:11:100:14 | data | semmle.label | data | +| fetch-promise-chain.js:101:13:101:19 | payload | semmle.label | payload | +| fetch-promise-chain.js:101:23:101:26 | data | semmle.label | data | +| fetch-promise-chain.js:102:33:102:39 | payload | semmle.label | payload | +| fetch-promise-chain.js:102:33:102:47 | payload.message | semmle.label | payload.message | | interceptors.js:7:6:7:13 | response | semmle.label | response | | interceptors.js:8:15:8:31 | userGeneratedHtml | semmle.label | userGeneratedHtml | | interceptors.js:8:35:8:42 | response | semmle.label | response | | interceptors.js:9:56:9:72 | userGeneratedHtml | semmle.label | userGeneratedHtml | +| non-fetch-promise-chain.js:3:3:3:35 | rp("htt ... ssage") | semmle.label | rp("htt ... ssage") | +| non-fetch-promise-chain.js:4:11:4:14 | body | semmle.label | body | +| non-fetch-promise-chain.js:5:33:5:36 | body | semmle.label | body | +| non-fetch-promise-chain.js:11:3:11:56 | rp({ ur ... true }) | semmle.label | rp({ ur ... true }) | +| non-fetch-promise-chain.js:12:11:12:14 | data | semmle.label | data | +| non-fetch-promise-chain.js:13:33:13:36 | data | semmle.label | data | +| non-fetch-promise-chain.js:13:33:13:44 | data.message | semmle.label | data.message | +| non-fetch-promise-chain.js:19:9:19:15 | request | semmle.label | request | +| non-fetch-promise-chain.js:19:19:19:58 | axios.g ... ssage") | semmle.label | axios.g ... ssage") | +| non-fetch-promise-chain.js:20:3:20:9 | request | semmle.label | request | +| non-fetch-promise-chain.js:20:16:20:23 | response | semmle.label | response | +| non-fetch-promise-chain.js:21:31:21:38 | response | semmle.label | response | +| non-fetch-promise-chain.js:21:31:21:51 | respons ... message | semmle.label | respons ... message | +| non-fetch-promise-chain.js:27:3:27:46 | needle( ... ssage") | semmle.label | needle( ... ssage") | +| non-fetch-promise-chain.js:28:11:28:18 | response | semmle.label | response | +| non-fetch-promise-chain.js:29:33:29:40 | response | semmle.label | response | +| non-fetch-promise-chain.js:29:33:29:53 | respons ... message | semmle.label | respons ... message | +| non-fetch-promise-chain.js:35:3:35:47 | superag ... ssage") | semmle.label | superag ... ssage") | +| non-fetch-promise-chain.js:36:11:36:18 | response | semmle.label | response | +| non-fetch-promise-chain.js:37:33:37:40 | response | semmle.label | response | +| non-fetch-promise-chain.js:37:33:37:45 | response.text | semmle.label | response.text | | test.jsx:5:11:5:18 | response | semmle.label | response | | test.jsx:5:22:5:63 | await f ... ntent") | semmle.label | await f ... ntent") | | test.jsx:5:28:5:63 | fetch(" ... ntent") | semmle.label | fetch(" ... ntent") | @@ -197,3 +446,4 @@ nodes | testUseQueries.vue:18:22:18:36 | results[0].data | semmle.label | results[0].data | | testUseQueries.vue:25:10:25:23 | v-html=data2 | semmle.label | v-html=data2 | subpaths +| fetch-promise-chain.js:62:3:63:38 | fetch(" ... json()) [PromiseValue] | fetch-promise-chain.js:64:11:64:14 | data | fetch-promise-chain.js:64:19:64:28 | data.items | fetch-promise-chain.js:62:3:64:29 | fetch(" ... .items) [PromiseValue] | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js new file mode 100644 index 000000000000..ee6f6731f136 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/fetch-promise-chain.js @@ -0,0 +1,145 @@ +function insertMessageRows(pageSize, continuationToken) { + let url = "?handler=LoadMessageLogs&pageSize=" + pageSize; + if (continuationToken) { + url += "&continuationToken=" + encodeURIComponent(continuationToken); + } + + fetch(url) // $ Source[js/xss] + .then(response => response.json()) + .then(data => { + const tbody = document.querySelector("#tblMessageLogs tbody"); + tbody.innerHTML = ""; + + data.items.forEach(item => { + const link = `View message`; + const row = ` + ${item.createdDate} + ${item.messageId} + ${item.target ?? ""} + ${link} + `; + tbody.insertAdjacentHTML("beforeend", row); // $ Alert[js/xss] + }); + }); +} + +function insertPlainTextResponse() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.text()) + .then(text => { + document.body.innerHTML = text; // $ Alert[js/xss] + }); +} + +function assignTextContent() { + fetch("/api/message") + .then(response => response.json()) + .then(data => { + document.body.textContent = data.message; + }); +} + +function insertAliasedFetchResponse() { + const request = fetch("/api/message"); // $ Source[js/xss] + request + .then(response => response.json()) + .then(data => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertReassignedFetchResponse() { + let request; + request = fetch("/api/message"); // $ Source[js/xss] + request + .then(response => response.text()) + .then(text => { + document.body.innerHTML = text; // $ Alert[js/xss] + }); +} + +function insertMessageAfterMultipleThenHops() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + .then(data => data.items) + .then(items => { + items.forEach(item => { + document.body.insertAdjacentHTML("beforeend", item.message); // $ Alert[js/xss] + }); + }); +} + +function insertDestructuredMessage() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + .then(({ message }) => { + document.body.innerHTML = message; // $ Alert[js/xss] + }); +} + +function insertMessageFromAsyncThenCallback() { + fetch("/api/message") // $ Source[js/xss] + .then(async response => await response.json()) + .then(data => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertPromiseAllMessage() { + Promise.all([ + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + ]).then(([data]) => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertAliasedDataMessage() { + fetch("/api/message") // $ Source[js/xss] + .then(response => response.json()) + .then(data => { + const payload = data; + document.body.innerHTML = payload.message; // $ Alert[js/xss] + }); +} + +function insertSanitizedHtml() { + fetch("/api/message") + .then(response => response.text()) + .then(text => { + document.body.innerHTML = DOMPurify.sanitize(text); + }); +} + +function assignInputValue() { + fetch("/api/message") + .then(response => response.text()) + .then(text => { + document.querySelector("input").value = text; + }); +} + +function assignSafeAttributes() { + fetch("/api/message") + .then(response => response.text()) + .then(text => { + const element = document.querySelector("div"); + element.setAttribute("title", text); + element.setAttribute("aria-label", text); + }); +} + +function catchDoesNotInventResponseValue() { + fetch("/api/message") + .catch(error => { + document.body.innerHTML = error.message; + }); +} + +function finallyDoesNotInventResponseValue() { + let text = ""; + fetch("/api/message") + .finally(() => { + document.body.innerHTML = text; + }); +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js new file mode 100644 index 000000000000..2996c9012fa8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/non-fetch-promise-chain.js @@ -0,0 +1,47 @@ +function insertRequestPromiseBody() { + const rp = require("request-promise-native"); + rp("https://example.com/message") // $ Source[js/xss] + .then(body => { + document.body.innerHTML = body; // $ Alert[js/xss] + }); +} + +function insertRequestPromiseJsonBody() { + const rp = require("request-promise"); + rp({ uri: "https://example.com/message", json: true }) // $ Source[js/xss] + .then(data => { + document.body.innerHTML = data.message; // $ Alert[js/xss] + }); +} + +function insertAxiosResponseData() { + const axios = require("axios"); + const request = axios.get("https://example.com/message"); // $ Source[js/xss] + request.then(response => { + document.body.innerHTML = response.data.message; // $ Alert[js/xss] + }); +} + +function insertNeedleResponseBody() { + const needle = require("needle"); + needle("get", "https://example.com/message") // $ Source[js/xss] + .then(response => { + document.body.innerHTML = response.body.message; // $ Alert[js/xss] + }); +} + +function insertSuperagentResponseText() { + const superagent = require("superagent"); + superagent.get("https://example.com/message") // $ Source[js/xss] + .then(response => { + document.body.innerHTML = response.text; // $ Alert[js/xss] + }); +} + +function assignAxiosResponseToInputValue() { + const axios = require("axios"); + axios.get("https://example.com/message") + .then(response => { + document.querySelector("input").value = response.data.message; + }); +} diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected index 8d197d6e37f6..5e2265f64b49 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected +++ b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/MissingRateLimiting.expected @@ -9,4 +9,5 @@ | tst.js:64:25:64:63 | functio ... req); } | This route handler performs $@, but is not rate-limited. | tst.js:64:46:64:60 | verifyUser(req) | authorization | | tst.js:76:25:76:53 | catchAs ... ndler1) | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | | tst.js:88:24:88:40 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | -| tst.js:112:28:112:44 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | +| tst.js:111:28:111:44 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | +| tst.js:116:39:116:55 | expensiveHandler1 | This route handler performs $@, but is not rate-limited. | tst.js:14:40:14:46 | login() | authorization | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js index 5b4312bbbe0e..7ff0c067fb51 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-770/MissingRateLimit/tst.js @@ -91,7 +91,6 @@ fastifyApp.get('/bar', expensiveHandler1); // Fastify per-route rate limiting via config.rateLimit const fastifyApp2 = require('fastify')(); -fastifyApp2.register(require('@fastify/rate-limit')); fastifyApp2.post('/login', { config: { @@ -110,3 +109,10 @@ fastifyApp2.post('/signup', { }, expensiveHandler1); // OK - has per-route rateLimit directly in options fastifyApp2.post('/other', expensiveHandler1); // $ Alert - no rate limiting + +// rate limiting using the scoped package name +const fastifyApp3 = require('fastify')(); + +fastifyApp3.get('/before-rate-limit', expensiveHandler1); // $ Alert +fastifyApp3.register(require('@fastify/rate-limit')); +fastifyApp3.get('/after-rate-limit', expensiveHandler1); diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel index ce1d79a772b9..e4e959491d45 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel @@ -55,18 +55,6 @@ alias( tags = ["manual"], ) -alias( - name = "cc-1.2.61", - actual = "@vendor_ts__cc-1.2.61//:cc", - tags = ["manual"], -) - -alias( - name = "cc", - actual = "@vendor_ts__cc-1.2.61//:cc", - tags = ["manual"], -) - alias( name = "chalk-ir-0.104.0", actual = "@vendor_ts__chalk-ir-0.104.0//:chalk_ir", @@ -649,18 +637,6 @@ alias( tags = ["manual"], ) -alias( - name = "tree-sitter-generate-0.26.8", - actual = "@vendor_ts__tree-sitter-generate-0.26.8//:tree_sitter_generate", - tags = ["manual"], -) - -alias( - name = "tree-sitter-generate", - actual = "@vendor_ts__tree-sitter-generate-0.26.8//:tree_sitter_generate", - tags = ["manual"], -) - alias( name = "tree-sitter-json-0.24.8", actual = "@vendor_ts__tree-sitter-json-0.24.8//:tree_sitter_json", @@ -673,18 +649,6 @@ alias( tags = ["manual"], ) -alias( - name = "tree-sitter-language-0.1.5", - actual = "@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language", - tags = ["manual"], -) - -alias( - name = "tree-sitter-language", - actual = "@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language", - tags = ["manual"], -) - alias( name = "tree-sitter-python-0.23.6", actual = "@vendor_ts__tree-sitter-python-0.23.6//:tree_sitter_python", @@ -721,18 +685,6 @@ alias( tags = ["manual"], ) -alias( - name = "tree-sitter-swift-0.7.2", - actual = "@vendor_ts__tree-sitter-swift-0.7.2//:tree_sitter_swift", - tags = ["manual"], -) - -alias( - name = "tree-sitter-swift", - actual = "@vendor_ts__tree-sitter-swift-0.7.2//:tree_sitter_swift", - tags = ["manual"], -) - alias( name = "triomphe-0.1.14", actual = "@vendor_ts__triomphe-0.1.14//:triomphe", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel deleted file mode 100644 index 903b1c8fc773..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bindgen-0.72.1.bazel +++ /dev/null @@ -1,190 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "bindgen", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "logging", - "prettyplease", - "runtime", - ], - crate_root = "lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=bindgen", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.72.1", - deps = [ - "@vendor_ts__bindgen-0.72.1//:build_script_build", - "@vendor_ts__bitflags-2.9.4//:bitflags", - "@vendor_ts__cexpr-0.6.0//:cexpr", - "@vendor_ts__clang-sys-1.8.1//:clang_sys", - "@vendor_ts__itertools-0.12.1//:itertools", - "@vendor_ts__log-0.4.28//:log", - "@vendor_ts__prettyplease-0.2.37//:prettyplease", - "@vendor_ts__proc-macro2-1.0.101//:proc_macro2", - "@vendor_ts__quote-1.0.41//:quote", - "@vendor_ts__regex-1.11.3//:regex", - "@vendor_ts__rustc-hash-2.1.1//:rustc_hash", - "@vendor_ts__shlex-1.3.0//:shlex", - "@vendor_ts__syn-2.0.106//:syn", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "logging", - "prettyplease", - "runtime", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - link_deps = [ - "@vendor_ts__clang-sys-1.8.1//:clang_sys", - "@vendor_ts__prettyplease-0.2.37//:prettyplease", - ], - pkg_name = "bindgen", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=bindgen", - "manual", - "noclippy", - "norustfmt", - ], - version = "0.72.1", - visibility = ["//visibility:private"], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel deleted file mode 100644 index 500c657be108..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.cexpr-0.6.0.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "cexpr", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=cexpr", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.6.0", - deps = [ - "@vendor_ts__nom-7.1.3//:nom", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel deleted file mode 100644 index b039f4c28e5b..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.clang-sys-1.8.1.bazel +++ /dev/null @@ -1,203 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "clang_sys", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "clang_10_0", - "clang_11_0", - "clang_3_5", - "clang_3_6", - "clang_3_7", - "clang_3_8", - "clang_3_9", - "clang_4_0", - "clang_5_0", - "clang_6_0", - "clang_7_0", - "clang_8_0", - "clang_9_0", - "libloading", - "runtime", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=clang-sys", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.8.1", - deps = [ - "@vendor_ts__clang-sys-1.8.1//:build_script_build", - "@vendor_ts__glob-0.3.3//:glob", - "@vendor_ts__libc-0.2.175//:libc", - "@vendor_ts__libloading-0.8.9//:libloading", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "clang_10_0", - "clang_11_0", - "clang_3_5", - "clang_3_6", - "clang_3_7", - "clang_3_8", - "clang_3_9", - "clang_4_0", - "clang_5_0", - "clang_6_0", - "clang_7_0", - "clang_8_0", - "clang_9_0", - "libloading", - "runtime", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - links = "clang", - pkg_name = "clang-sys", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=clang-sys", - "manual", - "noclippy", - "norustfmt", - ], - version = "1.8.1", - visibility = ["//visibility:private"], - deps = [ - "@vendor_ts__glob-0.3.3//:glob", - ], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel deleted file mode 100644 index a1a2df07bf1f..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.convert_case-0.8.0.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "convert_case", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=convert_case", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.8.0", - deps = [ - "@vendor_ts__unicode-segmentation-1.13.2//:unicode_segmentation", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel deleted file mode 100644 index f6f016a9f467..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.fastrand-2.4.1.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "fastrand", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=fastrand", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.4.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel deleted file mode 100644 index 03940fb08ac2..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.foldhash-0.2.0.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "foldhash", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=foldhash", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.0", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel deleted file mode 100644 index 8090f6f8c7fc..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.hashbrown-0.16.1.bazel +++ /dev/null @@ -1,110 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "hashbrown", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "allocator-api2", - "default", - "default-hasher", - "equivalent", - "inline-more", - "raw-entry", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=hashbrown", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.16.1", - deps = [ - "@vendor_ts__allocator-api2-0.2.21//:allocator_api2", - "@vendor_ts__equivalent-1.0.2//:equivalent", - "@vendor_ts__foldhash-0.2.0//:foldhash", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel deleted file mode 100644 index f3a9dea14d42..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.indoc-2.0.7.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_proc_macro") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_proc_macro( - name = "indoc", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=indoc", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.0.7", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel deleted file mode 100644 index e87fddeaaa5c..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.libloading-0.8.9.bazel +++ /dev/null @@ -1,190 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "libloading", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2015", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=libloading", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.8.9", - deps = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-apple-ios": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-linux-android": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [ - "@vendor_ts__windows-link-0.2.0//:windows_link", # cfg(windows) - ], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:armv7-linux-androideabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-apple-darwin": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-linux-android": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [ - "@vendor_ts__windows-link-0.2.0//:windows_link", # cfg(windows) - ], - "@rules_rust//rust/platform:i686-unknown-freebsd": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-apple-darwin": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-apple-ios": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-linux-android": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [ - "@vendor_ts__windows-link-0.2.0//:windows_link", # cfg(windows) - ], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [ - "@vendor_ts__cfg-if-1.0.3//:cfg_if", # cfg(unix) - ], - "//conditions:default": [], - }), -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel deleted file mode 100644 index 40e1e2259be6..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.minimal-lexical-0.2.1.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "minimal_lexical", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "std", - ], - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=minimal-lexical", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel deleted file mode 100644 index b1524d8a86d9..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.nom-7.1.3.bazel +++ /dev/null @@ -1,105 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "nom", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "alloc", - "std", - ], - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=nom", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "7.1.3", - deps = [ - "@vendor_ts__memchr-2.7.5//:memchr", - "@vendor_ts__minimal-lexical-0.2.1//:minimal_lexical", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel deleted file mode 100644 index 48df9a3c3d89..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.pathdiff-0.2.3.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "pathdiff", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=pathdiff", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.3", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel deleted file mode 100644 index 8c41939eb97f..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf-0.13.1.bazel +++ /dev/null @@ -1,104 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "phf", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=phf", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.13.1", - deps = [ - "@vendor_ts__phf_shared-0.13.1//:phf_shared", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel deleted file mode 100644 index c270102428d2..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_generator-0.13.1.bazel +++ /dev/null @@ -1,101 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "phf_generator", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=phf_generator", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.13.1", - deps = [ - "@vendor_ts__fastrand-2.4.1//:fastrand", - "@vendor_ts__phf_shared-0.13.1//:phf_shared", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel deleted file mode 100644 index 164cee335225..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.phf_shared-0.13.1.bazel +++ /dev/null @@ -1,104 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "phf_shared", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=phf_shared", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.13.1", - deps = [ - "@vendor_ts__siphasher-1.0.3//:siphasher", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel deleted file mode 100644 index 5d0886807cb8..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.prettyplease-0.2.37.bazel +++ /dev/null @@ -1,171 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "prettyplease", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "verbatim", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=prettyplease", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.37", - deps = [ - "@vendor_ts__prettyplease-0.2.37//:build_script_build", - "@vendor_ts__proc-macro2-1.0.101//:proc_macro2", - "@vendor_ts__syn-2.0.106//:syn", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "verbatim", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - links = "prettyplease02", - pkg_name = "prettyplease", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=prettyplease", - "manual", - "noclippy", - "norustfmt", - ], - version = "0.2.37", - visibility = ["//visibility:private"], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel deleted file mode 100644 index 0ae50367face..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.proc-macro-crate-3.5.0.bazel +++ /dev/null @@ -1,100 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "proc_macro_crate", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=proc-macro-crate", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "3.5.0", - deps = [ - "@vendor_ts__toml_edit-0.25.11-spec-1.1.0//:toml_edit", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel deleted file mode 100644 index 67aef624737c..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.relative-path-2.0.1.bazel +++ /dev/null @@ -1,101 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "relative_path", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "alloc", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=relative-path", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.0.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel deleted file mode 100644 index 3c57513b3d3b..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-0.10.0.bazel +++ /dev/null @@ -1,112 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "rquickjs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "default", - "loader", - "macro", - "phf", - "rquickjs-macro", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - proc_macro_deps = [ - "@vendor_ts__rquickjs-macro-0.10.0//:rquickjs_macro", - ], - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__rquickjs-core-0.10.0//:rquickjs_core", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel deleted file mode 100644 index 415c9ee4e4b3..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-core-0.10.0.bazel +++ /dev/null @@ -1,110 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "rquickjs_core", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "loader", - "phf", - "relative-path", - "std", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-core", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__hashbrown-0.16.1//:hashbrown", - "@vendor_ts__phf-0.13.1//:phf", - "@vendor_ts__relative-path-2.0.1//:relative_path", - "@vendor_ts__rquickjs-sys-0.10.0//:rquickjs_sys", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel deleted file mode 100644 index 055e627f3bed..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-macro-0.10.0.bazel +++ /dev/null @@ -1,116 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_proc_macro") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_proc_macro( - name = "rquickjs_macro", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "phf", - "phf_generator", - "phf_shared", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-macro", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__convert_case-0.8.0//:convert_case", - "@vendor_ts__fnv-1.0.7//:fnv", - "@vendor_ts__ident_case-1.0.1//:ident_case", - "@vendor_ts__indexmap-2.14.0//:indexmap", - "@vendor_ts__phf_generator-0.13.1//:phf_generator", - "@vendor_ts__phf_shared-0.13.1//:phf_shared", - "@vendor_ts__proc-macro-crate-3.5.0//:proc_macro_crate", - "@vendor_ts__proc-macro2-1.0.101//:proc_macro2", - "@vendor_ts__quote-1.0.41//:quote", - "@vendor_ts__rquickjs-core-0.10.0//:rquickjs_core", - "@vendor_ts__syn-2.0.106//:syn", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel deleted file mode 100644 index 185637f6ba47..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.rquickjs-sys-0.10.0.bazel +++ /dev/null @@ -1,177 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load( - "@rules_rust//cargo:defs.bzl", - "cargo_build_script", - "cargo_toml_env_vars", -) -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "rquickjs_sys", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "bindgen-rs", - ], - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-sys", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.10.0", - deps = [ - "@vendor_ts__rquickjs-sys-0.10.0//:build_script_build", - ], -) - -cargo_build_script( - name = "_bs", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - aliases = { - "@vendor_ts__bindgen-0.72.1//:bindgen": "bindgen_rs", - }, - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - "**/*.rs", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "bindgen", - "bindgen-rs", - ], - crate_name = "build_script_build", - crate_root = "build.rs", - data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - edition = "2021", - pkg_name = "rquickjs-sys", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=rquickjs-sys", - "manual", - "noclippy", - "norustfmt", - ], - version = "0.10.0", - visibility = ["//visibility:private"], - deps = [ - "@vendor_ts__bindgen-0.72.1//:bindgen", - "@vendor_ts__cc-1.2.61//:cc", - ], -) - -alias( - name = "build_script_build", - actual = ":_bs", - tags = ["manual"], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel deleted file mode 100644 index 472af635f83e..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.siphasher-1.0.3.bazel +++ /dev/null @@ -1,101 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "siphasher", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=siphasher", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.0.3", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel deleted file mode 100644 index 6dc39e352601..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.smallbitvec-2.6.1.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "smallbitvec", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2021", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=smallbitvec", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "2.6.1", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel deleted file mode 100644 index a4809f145b60..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel +++ /dev/null @@ -1,102 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "toml_datetime", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "alloc", - "default", - "std", - ], - crate_root = "src/lib.rs", - edition = "2024", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=toml_datetime", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.1.1+spec-1.1.0", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel deleted file mode 100644 index 596127714520..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_edit-0.25.11+spec-1.1.0.bazel +++ /dev/null @@ -1,106 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "toml_edit", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "parse", - ], - crate_root = "src/lib.rs", - edition = "2024", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=toml_edit", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.25.11+spec-1.1.0", - deps = [ - "@vendor_ts__indexmap-2.14.0//:indexmap", - "@vendor_ts__toml_datetime-1.1.1-spec-1.1.0//:toml_datetime", - "@vendor_ts__toml_parser-1.1.2-spec-1.1.0//:toml_parser", - "@vendor_ts__winnow-1.0.2//:winnow", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel index 4504ea44e88a..3e9b84dd8a92 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.toml_parser-1.1.2+spec-1.1.0.bazel @@ -37,54 +37,7 @@ rust_library( crate_features = [ "alloc", "std", - ] + select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [ - "default", # aarch64-apple-darwin - ], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [ - "default", # aarch64-pc-windows-msvc - ], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [ - "default", # aarch64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [ - "default", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - ], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [ - "default", # arm-unknown-linux-gnueabi - ], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [ - "default", # i686-pc-windows-msvc - ], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [ - "default", # i686-unknown-linux-gnu - ], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [ - "default", # powerpc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [ - "default", # riscv64gc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [ - "default", # s390x-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-apple-darwin": [ - "default", # x86_64-apple-darwin - ], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [ - "default", # x86_64-pc-windows-msvc - ], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [ - "default", # x86_64-unknown-freebsd - ], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [ - "default", # x86_64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [ - "default", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - ], - "//conditions:default": [], - }), + ], crate_root = "src/lib.rs", edition = "2024", rustc_env_files = [ diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel deleted file mode 100644 index 4cba2e919677..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.topological-sort-0.2.2.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "topological_sort", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=topological-sort", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.2.2", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel deleted file mode 100644 index 12951a955489..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-generate-0.26.8.bazel +++ /dev/null @@ -1,124 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "tree_sitter_generate", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_features = [ - "default", - "load", - "pathdiff", - "qjs-rt", - "rquickjs", - ], - crate_root = "src/generate.rs", - edition = "2021", - proc_macro_deps = [ - "@vendor_ts__indoc-2.0.7//:indoc", - ], - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=tree-sitter-generate", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "0.26.8", - deps = [ - "@vendor_ts__bitflags-2.9.4//:bitflags", - "@vendor_ts__dunce-1.0.5//:dunce", - "@vendor_ts__indexmap-2.14.0//:indexmap", - "@vendor_ts__log-0.4.28//:log", - "@vendor_ts__pathdiff-0.2.3//:pathdiff", - "@vendor_ts__regex-1.11.3//:regex", - "@vendor_ts__regex-syntax-0.8.6//:regex_syntax", - "@vendor_ts__rquickjs-0.10.0//:rquickjs", - "@vendor_ts__rustc-hash-2.1.1//:rustc_hash", - "@vendor_ts__semver-1.0.28//:semver", - "@vendor_ts__serde-1.0.228//:serde", - "@vendor_ts__serde_json-1.0.145//:serde_json", - "@vendor_ts__smallbitvec-2.6.1//:smallbitvec", - "@vendor_ts__thiserror-2.0.18//:thiserror", - "@vendor_ts__topological-sort-0.2.2//:topological_sort", - ], -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel deleted file mode 100644 index 020b1bf1a716..000000000000 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.unicode-segmentation-1.13.2.bazel +++ /dev/null @@ -1,97 +0,0 @@ -############################################################################### -# @generated -# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To -# regenerate this file, run the following: -# -# bazel run @@//misc/bazel/3rdparty:vendor_tree_sitter_extractors -############################################################################### - -load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") -load("@rules_rust//rust:defs.bzl", "rust_library") - -package(default_visibility = ["//visibility:public"]) - -cargo_toml_env_vars( - name = "cargo_toml_env_vars", - src = "Cargo.toml", -) - -rust_library( - name = "unicode_segmentation", - srcs = glob( - include = ["**/*.rs"], - allow_empty = True, - ), - compile_data = glob( - include = ["**"], - allow_empty = True, - exclude = [ - "**/* *", - ".tmp_git_root/**/*", - "BUILD", - "BUILD.bazel", - "WORKSPACE", - "WORKSPACE.bazel", - ], - ), - crate_root = "src/lib.rs", - edition = "2018", - rustc_env_files = [ - ":cargo_toml_env_vars", - ], - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-bazel", - "crate-name=unicode-segmentation", - "manual", - "noclippy", - "norustfmt", - ], - target_compatible_with = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [], - "@rules_rust//rust/platform:aarch64-apple-ios": [], - "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], - "@rules_rust//rust/platform:aarch64-linux-android": [], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], - "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], - "@rules_rust//rust/platform:aarch64-unknown-uefi": [], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], - "@rules_rust//rust/platform:armv7-linux-androideabi": [], - "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], - "@rules_rust//rust/platform:i686-apple-darwin": [], - "@rules_rust//rust/platform:i686-linux-android": [], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [], - "@rules_rust//rust/platform:i686-unknown-freebsd": [], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], - "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], - "@rules_rust//rust/platform:thumbv7em-none-eabi": [], - "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], - "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], - "@rules_rust//rust/platform:wasm32-unknown-unknown": [], - "@rules_rust//rust/platform:wasm32-wasip1": [], - "@rules_rust//rust/platform:wasm32-wasip1-threads": [], - "@rules_rust//rust/platform:wasm32-wasip2": [], - "@rules_rust//rust/platform:x86_64-apple-darwin": [], - "@rules_rust//rust/platform:x86_64-apple-ios": [], - "@rules_rust//rust/platform:x86_64-linux-android": [], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], - "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], - "@rules_rust//rust/platform:x86_64-unknown-none": [], - "@rules_rust//rust/platform:x86_64-unknown-uefi": [], - "//conditions:default": ["@platforms//:incompatible"], - }), - version = "1.13.2", -) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel index e9d478c9c660..995dce1204f2 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.winnow-1.0.2.bazel @@ -34,129 +34,6 @@ rust_library( "WORKSPACE.bazel", ], ), - crate_features = select({ - "@rules_rust//rust/platform:aarch64-apple-darwin": [ - "alloc", # aarch64-apple-darwin - "ascii", # aarch64-apple-darwin - "binary", # aarch64-apple-darwin - "default", # aarch64-apple-darwin - "parser", # aarch64-apple-darwin - "std", # aarch64-apple-darwin - ], - "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [ - "alloc", # aarch64-pc-windows-msvc - "ascii", # aarch64-pc-windows-msvc - "binary", # aarch64-pc-windows-msvc - "default", # aarch64-pc-windows-msvc - "parser", # aarch64-pc-windows-msvc - "std", # aarch64-pc-windows-msvc - ], - "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [ - "alloc", # aarch64-unknown-linux-gnu - "ascii", # aarch64-unknown-linux-gnu - "binary", # aarch64-unknown-linux-gnu - "default", # aarch64-unknown-linux-gnu - "parser", # aarch64-unknown-linux-gnu - "std", # aarch64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [ - "alloc", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "ascii", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "binary", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "default", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "parser", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - "std", # aarch64-unknown-linux-gnu, aarch64-unknown-nixos-gnu - ], - "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [ - "alloc", # arm-unknown-linux-gnueabi - "ascii", # arm-unknown-linux-gnueabi - "binary", # arm-unknown-linux-gnueabi - "default", # arm-unknown-linux-gnueabi - "parser", # arm-unknown-linux-gnueabi - "std", # arm-unknown-linux-gnueabi - ], - "@rules_rust//rust/platform:i686-pc-windows-msvc": [ - "alloc", # i686-pc-windows-msvc - "ascii", # i686-pc-windows-msvc - "binary", # i686-pc-windows-msvc - "default", # i686-pc-windows-msvc - "parser", # i686-pc-windows-msvc - "std", # i686-pc-windows-msvc - ], - "@rules_rust//rust/platform:i686-unknown-linux-gnu": [ - "alloc", # i686-unknown-linux-gnu - "ascii", # i686-unknown-linux-gnu - "binary", # i686-unknown-linux-gnu - "default", # i686-unknown-linux-gnu - "parser", # i686-unknown-linux-gnu - "std", # i686-unknown-linux-gnu - ], - "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [ - "alloc", # powerpc-unknown-linux-gnu - "ascii", # powerpc-unknown-linux-gnu - "binary", # powerpc-unknown-linux-gnu - "default", # powerpc-unknown-linux-gnu - "parser", # powerpc-unknown-linux-gnu - "std", # powerpc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [ - "alloc", # riscv64gc-unknown-linux-gnu - "ascii", # riscv64gc-unknown-linux-gnu - "binary", # riscv64gc-unknown-linux-gnu - "default", # riscv64gc-unknown-linux-gnu - "parser", # riscv64gc-unknown-linux-gnu - "std", # riscv64gc-unknown-linux-gnu - ], - "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [ - "alloc", # s390x-unknown-linux-gnu - "ascii", # s390x-unknown-linux-gnu - "binary", # s390x-unknown-linux-gnu - "default", # s390x-unknown-linux-gnu - "parser", # s390x-unknown-linux-gnu - "std", # s390x-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-apple-darwin": [ - "alloc", # x86_64-apple-darwin - "ascii", # x86_64-apple-darwin - "binary", # x86_64-apple-darwin - "default", # x86_64-apple-darwin - "parser", # x86_64-apple-darwin - "std", # x86_64-apple-darwin - ], - "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [ - "alloc", # x86_64-pc-windows-msvc - "ascii", # x86_64-pc-windows-msvc - "binary", # x86_64-pc-windows-msvc - "default", # x86_64-pc-windows-msvc - "parser", # x86_64-pc-windows-msvc - "std", # x86_64-pc-windows-msvc - ], - "@rules_rust//rust/platform:x86_64-unknown-freebsd": [ - "alloc", # x86_64-unknown-freebsd - "ascii", # x86_64-unknown-freebsd - "binary", # x86_64-unknown-freebsd - "default", # x86_64-unknown-freebsd - "parser", # x86_64-unknown-freebsd - "std", # x86_64-unknown-freebsd - ], - "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [ - "alloc", # x86_64-unknown-linux-gnu - "ascii", # x86_64-unknown-linux-gnu - "binary", # x86_64-unknown-linux-gnu - "default", # x86_64-unknown-linux-gnu - "parser", # x86_64-unknown-linux-gnu - "std", # x86_64-unknown-linux-gnu - ], - "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [ - "alloc", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "ascii", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "binary", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "default", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "parser", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - "std", # x86_64-unknown-linux-gnu, x86_64-unknown-nixos-gnu - ], - "//conditions:default": [], - }), crate_root = "src/lib.rs", edition = "2021", rustc_env_files = [ diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl index f3b5edb59cd6..be869ecf7388 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl @@ -420,13 +420,6 @@ _NORMAL_DEPENDENCIES = { "serde_json": Label("@vendor_ts__serde_json-1.0.145//:serde_json"), "tracing": Label("@vendor_ts__tracing-0.1.41//:tracing"), "tracing-subscriber": Label("@vendor_ts__tracing-subscriber-0.3.20//:tracing_subscriber"), - "tree-sitter": Label("@vendor_ts__tree-sitter-0.26.8//:tree_sitter"), - "tree-sitter-embedded-template": Label("@vendor_ts__tree-sitter-embedded-template-0.25.0//:tree_sitter_embedded_template"), - }, - }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - "tree-sitter-language": Label("@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language"), }, }, "unified/swift-syntax-rs": { @@ -475,10 +468,6 @@ _NORMAL_ALIASES = { _COMMON_CONDITION: { }, }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - }, - }, "unified/swift-syntax-rs": { _COMMON_CONDITION: { }, @@ -511,8 +500,6 @@ _NORMAL_DEV_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -540,8 +527,6 @@ _NORMAL_DEV_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -567,8 +552,6 @@ _PROC_MACRO_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -594,8 +577,6 @@ _PROC_MACRO_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -621,8 +602,6 @@ _PROC_MACRO_DEV_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -650,8 +629,6 @@ _PROC_MACRO_DEV_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -677,12 +654,6 @@ _BUILD_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - "cc": Label("@vendor_ts__cc-1.2.61//:cc"), - "tree-sitter-generate": Label("@vendor_ts__tree-sitter-generate-0.26.8//:tree_sitter_generate"), - }, - }, "unified/swift-syntax-rs": { }, } @@ -708,10 +679,6 @@ _BUILD_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - _COMMON_CONDITION: { - }, - }, "unified/swift-syntax-rs": { }, } @@ -737,8 +704,6 @@ _BUILD_PROC_MACRO_DEPENDENCIES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -764,8 +729,6 @@ _BUILD_PROC_MACRO_ALIASES = { }, "unified/extractor": { }, - "unified/extractor/tree-sitter-swift": { - }, "unified/swift-syntax-rs": { }, } @@ -1009,16 +972,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.base64-0.22.1.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__bindgen-0.72.1", - sha256 = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895", - type = "tar.gz", - urls = ["https://static.crates.io/crates/bindgen/0.72.1/download"], - strip_prefix = "bindgen-0.72.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.bindgen-0.72.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__bitflags-1.3.2", @@ -1139,16 +1092,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.cc-1.2.61.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__cexpr-0.6.0", - sha256 = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", - type = "tar.gz", - urls = ["https://static.crates.io/crates/cexpr/0.6.0/download"], - strip_prefix = "cexpr-0.6.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.cexpr-0.6.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__cfg-if-1.0.3", @@ -1239,16 +1182,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.chrono-0.4.42.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__clang-sys-1.8.1", - sha256 = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4", - type = "tar.gz", - urls = ["https://static.crates.io/crates/clang-sys/1.8.1/download"], - strip_prefix = "clang-sys-1.8.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.clang-sys-1.8.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__clap-4.5.48", @@ -1299,16 +1232,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.colorchoice-1.0.4.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__convert_case-0.8.0", - sha256 = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f", - type = "tar.gz", - urls = ["https://static.crates.io/crates/convert_case/0.8.0/download"], - strip_prefix = "convert_case-0.8.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.convert_case-0.8.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__core-foundation-sys-0.8.7", @@ -1599,16 +1522,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.erased-serde-0.4.6.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__fastrand-2.4.1", - sha256 = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6", - type = "tar.gz", - urls = ["https://static.crates.io/crates/fastrand/2.4.1/download"], - strip_prefix = "fastrand-2.4.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.fastrand-2.4.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__figment-0.10.19", @@ -1669,16 +1582,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.foldhash-0.1.5.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__foldhash-0.2.0", - sha256 = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", - type = "tar.gz", - urls = ["https://static.crates.io/crates/foldhash/0.2.0/download"], - strip_prefix = "foldhash-0.2.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.foldhash-0.2.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__form_urlencoded-1.2.2", @@ -1779,16 +1682,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.hashbrown-0.15.5.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__hashbrown-0.16.1", - sha256 = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100", - type = "tar.gz", - urls = ["https://static.crates.io/crates/hashbrown/0.16.1/download"], - strip_prefix = "hashbrown-0.16.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.hashbrown-0.16.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__hashbrown-0.17.1", @@ -1989,16 +1882,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.indexmap-2.14.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__indoc-2.0.7", - sha256 = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706", - type = "tar.gz", - urls = ["https://static.crates.io/crates/indoc/2.0.7/download"], - strip_prefix = "indoc-2.0.7", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.indoc-2.0.7.bazel"), - ) - maybe( http_archive, name = "vendor_ts__inlinable_string-0.1.15", @@ -2159,16 +2042,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.libc-0.2.175.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__libloading-0.8.9", - sha256 = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", - type = "tar.gz", - urls = ["https://static.crates.io/crates/libloading/0.8.9/download"], - strip_prefix = "libloading-0.8.9", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.libloading-0.8.9.bazel"), - ) - maybe( http_archive, name = "vendor_ts__line-index-0.1.2", @@ -2249,16 +2122,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.memoffset-0.9.1.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__minimal-lexical-0.2.1", - sha256 = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", - type = "tar.gz", - urls = ["https://static.crates.io/crates/minimal-lexical/0.2.1/download"], - strip_prefix = "minimal-lexical-0.2.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.minimal-lexical-0.2.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__miniz_oxide-0.8.9", @@ -2309,16 +2172,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.nohash-hasher-0.2.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__nom-7.1.3", - sha256 = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", - type = "tar.gz", - urls = ["https://static.crates.io/crates/nom/7.1.3/download"], - strip_prefix = "nom-7.1.3", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.nom-7.1.3.bazel"), - ) - maybe( http_archive, name = "vendor_ts__notify-8.2.0", @@ -2459,16 +2312,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.parking_lot_core-0.9.11.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__pathdiff-0.2.3", - sha256 = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3", - type = "tar.gz", - urls = ["https://static.crates.io/crates/pathdiff/0.2.3/download"], - strip_prefix = "pathdiff-0.2.3", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.pathdiff-0.2.3.bazel"), - ) - maybe( http_archive, name = "vendor_ts__pear-0.2.9", @@ -2529,36 +2372,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.petgraph-0.6.5.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__phf-0.13.1", - sha256 = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf", - type = "tar.gz", - urls = ["https://static.crates.io/crates/phf/0.13.1/download"], - strip_prefix = "phf-0.13.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.phf-0.13.1.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__phf_generator-0.13.1", - sha256 = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737", - type = "tar.gz", - urls = ["https://static.crates.io/crates/phf_generator/0.13.1/download"], - strip_prefix = "phf_generator-0.13.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.phf_generator-0.13.1.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__phf_shared-0.13.1", - sha256 = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266", - type = "tar.gz", - urls = ["https://static.crates.io/crates/phf_shared/0.13.1/download"], - strip_prefix = "phf_shared-0.13.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.phf_shared-0.13.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__pin-project-lite-0.2.16", @@ -2619,26 +2432,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.ppv-lite86-0.2.21.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__prettyplease-0.2.37", - sha256 = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b", - type = "tar.gz", - urls = ["https://static.crates.io/crates/prettyplease/0.2.37/download"], - strip_prefix = "prettyplease-0.2.37", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.prettyplease-0.2.37.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__proc-macro-crate-3.5.0", - sha256 = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f", - type = "tar.gz", - urls = ["https://static.crates.io/crates/proc-macro-crate/3.5.0/download"], - strip_prefix = "proc-macro-crate-3.5.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.proc-macro-crate-3.5.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__proc-macro2-1.0.101", @@ -3119,16 +2912,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.regex-syntax-0.8.6.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__relative-path-2.0.1", - sha256 = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0", - type = "tar.gz", - urls = ["https://static.crates.io/crates/relative-path/2.0.1/download"], - strip_prefix = "relative-path-2.0.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.relative-path-2.0.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__rowan-0.15.15", @@ -3139,46 +2922,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rowan-0.15.15.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__rquickjs-0.10.0", - sha256 = "a135375fbac5ba723bb6a48f432a72f81539cedde422f0121a86c7c4e96d8e0d", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs/0.10.0/download"], - strip_prefix = "rquickjs-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-0.10.0.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__rquickjs-core-0.10.0", - sha256 = "bccb7121a123865c8ace4dea42e7ed84d78b90cbaf4ca32c59849d8d210c9672", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs-core/0.10.0/download"], - strip_prefix = "rquickjs-core-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-core-0.10.0.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__rquickjs-macro-0.10.0", - sha256 = "89f93602cc3112c7f30bf5f29e722784232138692c7df4c52ebbac7e035d900d", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs-macro/0.10.0/download"], - strip_prefix = "rquickjs-macro-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-macro-0.10.0.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__rquickjs-sys-0.10.0", - sha256 = "57b1b6528590d4d65dc86b5159eae2d0219709546644c66408b2441696d1d725", - type = "tar.gz", - urls = ["https://static.crates.io/crates/rquickjs-sys/0.10.0/download"], - strip_prefix = "rquickjs-sys-0.10.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.rquickjs-sys-0.10.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__rustc-hash-1.1.0", @@ -3479,26 +3222,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.shlex-1.3.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__siphasher-1.0.3", - sha256 = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649", - type = "tar.gz", - urls = ["https://static.crates.io/crates/siphasher/1.0.3/download"], - strip_prefix = "siphasher-1.0.3", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.siphasher-1.0.3.bazel"), - ) - - maybe( - http_archive, - name = "vendor_ts__smallbitvec-2.6.1", - sha256 = "9b0e903ee191d8f7a8fbf0d712c3a1699d19e04ceba5ad1eb673053c7d938a09", - type = "tar.gz", - urls = ["https://static.crates.io/crates/smallbitvec/2.6.1/download"], - strip_prefix = "smallbitvec-2.6.1", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.smallbitvec-2.6.1.bazel"), - ) - maybe( http_archive, name = "vendor_ts__smallvec-1.15.1", @@ -3709,16 +3432,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_datetime-0.7.2.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__toml_datetime-1.1.1-spec-1.1.0", - sha256 = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7", - type = "tar.gz", - urls = ["https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download"], - strip_prefix = "toml_datetime-1.1.1+spec-1.1.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__toml_edit-0.22.27", @@ -3729,16 +3442,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_edit-0.22.27.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__toml_edit-0.25.11-spec-1.1.0", - sha256 = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b", - type = "tar.gz", - urls = ["https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download"], - strip_prefix = "toml_edit-0.25.11+spec-1.1.0", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_edit-0.25.11+spec-1.1.0.bazel"), - ) - maybe( http_archive, name = "vendor_ts__toml_parser-1.1.2-spec-1.1.0", @@ -3769,16 +3472,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.toml_writer-1.0.3.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__topological-sort-0.2.2", - sha256 = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d", - type = "tar.gz", - urls = ["https://static.crates.io/crates/topological-sort/0.2.2/download"], - strip_prefix = "topological-sort-0.2.2", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.topological-sort-0.2.2.bazel"), - ) - maybe( http_archive, name = "vendor_ts__tracing-0.1.41", @@ -3859,16 +3552,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.tree-sitter-embedded-template-0.25.0.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__tree-sitter-generate-0.26.8", - sha256 = "c3fb2e1bdb1d5f9d23cd5fa68cf98b3bedbd223c92a2edd60bbcf30bcf7180a5", - type = "tar.gz", - urls = ["https://static.crates.io/crates/tree-sitter-generate/0.26.8/download"], - strip_prefix = "tree-sitter-generate-0.26.8", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.tree-sitter-generate-0.26.8.bazel"), - ) - maybe( http_archive, name = "vendor_ts__tree-sitter-json-0.24.8", @@ -3989,16 +3672,6 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.unicode-properties-0.1.3.bazel"), ) - maybe( - http_archive, - name = "vendor_ts__unicode-segmentation-1.13.2", - sha256 = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c", - type = "tar.gz", - urls = ["https://static.crates.io/crates/unicode-segmentation/1.13.2/download"], - strip_prefix = "unicode-segmentation-1.13.2", - build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.unicode-segmentation-1.13.2.bazel"), - ) - maybe( http_archive, name = "vendor_ts__unicode-xid-0.2.6", @@ -4632,7 +4305,6 @@ def crate_repositories(): return [ struct(repo = "vendor_ts__anyhow-1.0.100", is_dev_dep = False), struct(repo = "vendor_ts__argfile-0.2.1", is_dev_dep = False), - struct(repo = "vendor_ts__cc-1.2.61", is_dev_dep = False), struct(repo = "vendor_ts__chalk-ir-0.104.0", is_dev_dep = False), struct(repo = "vendor_ts__chrono-0.4.42", is_dev_dep = False), struct(repo = "vendor_ts__clap-4.5.48", is_dev_dep = False), @@ -4679,8 +4351,6 @@ def crate_repositories(): struct(repo = "vendor_ts__tracing-subscriber-0.3.20", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-0.26.8", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-embedded-template-0.25.0", is_dev_dep = False), - struct(repo = "vendor_ts__tree-sitter-generate-0.26.8", is_dev_dep = False), - struct(repo = "vendor_ts__tree-sitter-language-0.1.5", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-python-0.23.6", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-ruby-0.23.1", is_dev_dep = False), struct(repo = "vendor_ts__triomphe-0.1.14", is_dev_dep = False), diff --git a/misc/bazel/BUILD.bazel b/misc/bazel/BUILD.bazel index e00a6f7a64c7..b71a9b6ca6a3 100644 --- a/misc/bazel/BUILD.bazel +++ b/misc/bazel/BUILD.bazel @@ -1,5 +1,16 @@ load("@rules_shell//shell:sh_library.bzl", "sh_library") +# Matches the Linux arm64 target, used to give it a distinct `CODEQL_PLATFORM` string +# (`linux-arm64`). Every other configuration keeps its OS-only string. +config_setting( + name = "linux_arm64", + constraint_values = [ + "@platforms//os:linux", + "@platforms//cpu:arm64", + ], + visibility = ["//visibility:public"], +) + sh_library( name = "sh_runfiles", srcs = ["runfiles.sh"], diff --git a/misc/bazel/os.bzl b/misc/bazel/os.bzl index 34093e76331d..39b12773c780 100644 --- a/misc/bazel/os.bzl +++ b/misc/bazel/os.bzl @@ -1,38 +1,88 @@ """ Os detection facilities. """ -def os_select( +def codeql_platform_select( ctx = None, *, - linux = None, - windows = None, - macos = None, - default = None): + linux64 = None, + linux_arm64 = None, + osx64 = None, + win64 = None, + otherwise = None): """ - This can work both in a macro and a rule context to choose something based on the current OS. - If used in a rule implementation, you need to pass `ctx` and add `OS_DETECTION_ATTRS` to the - rule attributes. + Choose a value based on the target CodeQL platform, discriminating the four platforms CodeQL + knows about: `linux64` (Linux on x86_64), `linux_arm64` (Linux on arm64), `osx64` (macOS, any + architecture) and `win64` (Windows on x86_64). Any platform left unspecified uses `otherwise`. + + There is deliberately no fallback between `linux64` and `linux_arm64`: if you want the same value + for both (i.e. you only care about the OS, not the architecture), use `os_select` instead. + + This works both in a macro context (`ctx = None`, returning a `select`) and in a rule context + (passing `ctx`, which then needs `OS_DETECTION_ATTRS` on the rule attributes). """ + + def _or_otherwise(value): + return value if value != None else otherwise + + linux_arm64_setting = Label("//misc/bazel:linux_arm64") choices = { - "linux": linux or default, - "windows": windows or default, - "macos": macos or default, + linux_arm64_setting: _or_otherwise(linux_arm64), + "@platforms//os:linux": _or_otherwise(linux64), + "@platforms//os:macos": _or_otherwise(osx64), + "@platforms//os:windows": _or_otherwise(win64), } if not ctx: return select({ - "@platforms//os:%s" % os: v - for os, v in choices.items() + setting: v + for setting, v in choices.items() if v != None }) - for os, v in choices.items(): - if ctx.target_platform_has_constraint(getattr(ctx.attr, "_%s_constraint" % os)[platform_common.ConstraintValueInfo]): - if v == None: - fail("%s not supported by %s" % (os, ctx.label)) - return v - fail("Unknown OS detected") + def has(constraint): + return ctx.target_platform_has_constraint(getattr(ctx.attr, "_%s_constraint" % constraint)[platform_common.ConstraintValueInfo]) + + if has("linux"): + result = choices[linux_arm64_setting] if has("arm64") else choices["@platforms//os:linux"] + elif has("macos"): + result = choices["@platforms//os:macos"] + elif has("windows"): + result = choices["@platforms//os:windows"] + else: + fail("Unknown OS detected") + if result == None: + fail("platform not supported by %s" % ctx.label) + return result + +def os_select( + ctx = None, + *, + linux = None, + windows = None, + macos = None, + posix = None, + default = None): + """ + Choose a value based on the target OS, ignoring the architecture. This is a thin, OS-only wrapper + around `codeql_platform_select` (Linux gets the same value on both x86_64 and arm64). + `posix` is a convenience for the value shared by `linux` and `macos`; it is mutually exclusive + with both. See `codeql_platform_select` for macro vs rule usage. + """ + if posix != None: + if linux != None or macos != None: + fail("`posix` is mutually exclusive with `linux` and `macos`") + linux = posix + macos = posix + return codeql_platform_select( + ctx, + linux64 = linux, + linux_arm64 = linux, + osx64 = macos, + win64 = windows, + otherwise = default, + ) OS_DETECTION_ATTRS = { "_windows_constraint": attr.label(default = "@platforms//os:windows"), "_macos_constraint": attr.label(default = "@platforms//os:macos"), "_linux_constraint": attr.label(default = "@platforms//os:linux"), + "_arm64_constraint": attr.label(default = "@platforms//cpu:arm64"), } diff --git a/misc/bazel/pkg.bzl b/misc/bazel/pkg.bzl index 25f2bf3577d0..684bcbb8c3ba 100644 --- a/misc/bazel/pkg.bzl +++ b/misc/bazel/pkg.bzl @@ -8,7 +8,7 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_fil load("@rules_pkg//pkg:pkg.bzl", "pkg_zip") load("@rules_pkg//pkg:providers.bzl", "PackageFilegroupInfo", "PackageFilesInfo") load("@rules_python//python:defs.bzl", "py_binary", "py_test") -load("//misc/bazel:os.bzl", "OS_DETECTION_ATTRS", "os_select") +load("//misc/bazel:os.bzl", "OS_DETECTION_ATTRS", "codeql_platform_select") def _make_internal(name): def internal(suffix = "internal", *args): @@ -26,7 +26,13 @@ def _expand_path(path, platform): return ("common", path) def _detect_platform(ctx = None): - return os_select(ctx, linux = "linux64", macos = "osx64", windows = "win64") + return codeql_platform_select( + ctx, + linux64 = "linux64", + linux_arm64 = "linux-arm64", + osx64 = "osx64", + win64 = "win64", + ) def codeql_pkg_files( *, @@ -458,12 +464,12 @@ def codeql_pack( `zips` is a map from `.zip` files to prefixes to import. The distinction between arch-specific and common contents is made based on whether the paths (including possible prefixes added by rules) contain the special `{CODEQL_PLATFORM}` placeholder, which in case it is present will also - be replaced by the appropriate platform (`linux64`, `win64` or `osx64`). + be replaced by the appropriate platform (`linux64`, `linux-arm64`, `win64` or `osx64`). Specific file paths can be placed in the arch-specific package by adding them to `arch_overrides`, even if their path doesn't contain the `CODEQL_PLATFORM` placeholder. The codeql pack rules will expand the `{CODEQL_PLATFORM}` marker in paths, and use that to split the files into a common and an arch-specific part. - This placeholder will be replaced by the appropriate platform (`linux64`, `win64` or `osx64`). + This placeholder will be replaced by the appropriate platform (`linux64`, `linux-arm64`, `win64` or `osx64`). `arch_overrides` is a list of files that should be included in the arch-specific bits of the pack, even if their path doesn't contain the `{CODEQL_PLATFORM}` marker. All files in the pack will be prefixed with `name`, unless `pack_prefix` is set, then is used instead. diff --git a/misc/ripunzip/ripunzip.bzl b/misc/ripunzip/ripunzip.bzl index 2e707c267e24..5b049d901273 100644 --- a/misc/ripunzip/ripunzip.bzl +++ b/misc/ripunzip/ripunzip.bzl @@ -3,12 +3,24 @@ def _ripunzip_archive_impl(repository_ctx): url_prefix = "https://github.com/GoogleChrome/ripunzip/releases/download/v%s" % version build_file = Label("//misc/ripunzip:BUILD.ripunzip.bazel") if "linux" in repository_ctx.os.name: + arch = repository_ctx.os.arch + if arch == "aarch64": + deb_arch = "arm64" + sha256 = repository_ctx.attr.sha256_linux_arm64 + canonical_id = "ripunzip-linux-arm64" + elif arch in ("x86_64", "amd64"): + deb_arch = "amd64" + sha256 = repository_ctx.attr.sha256_linux_x64 + canonical_id = "ripunzip-linux-x64" + else: + fail("Unsupported Linux architecture: %s" % arch) + # ripunzip only provides a deb package for Linux: we fish the binary out of it # a deb archive contains a data.tar.xz one which contains the files to be installed under usr/bin repository_ctx.download_and_extract( - url = "%s/ripunzip_%s-1_amd64.deb" % (url_prefix, version), - sha256 = repository_ctx.attr.sha256_linux, - canonical_id = "ripunzip-linux", + url = "%s/ripunzip_%s-1_%s.deb" % (url_prefix, version, deb_arch), + sha256 = sha256, + canonical_id = canonical_id, output = "deb", ) repository_ctx.extract( @@ -19,20 +31,20 @@ def _ripunzip_archive_impl(repository_ctx): elif "windows" in repository_ctx.os.name: repository_ctx.download_and_extract( url = "%s/ripunzip_v%s_x86_64-pc-windows-msvc.zip" % (url_prefix, version), - canonical_id = "ripunzip-windows", - sha256 = repository_ctx.attr.sha256_windows, + canonical_id = "ripunzip-windows-x64", + sha256 = repository_ctx.attr.sha256_windows_x64, output = "bin", ) elif "mac os" in repository_ctx.os.name: arch = repository_ctx.os.arch if arch == "x86_64": suffix = "x86_64-apple-darwin" - sha256 = repository_ctx.attr.sha256_macos_intel - canonical_id = "ripunzip-macos-intel" + sha256 = repository_ctx.attr.sha256_macos_x64 + canonical_id = "ripunzip-macos-x64" elif arch == "aarch64": suffix = "aarch64-apple-darwin" - sha256 = repository_ctx.attr.sha256_macos_arm - canonical_id = "ripunzip-macos-arm" + sha256 = repository_ctx.attr.sha256_macos_arm64 + canonical_id = "ripunzip-macos-arm64" else: fail("Unsupported macOS architecture: %s" % arch) repository_ctx.download_and_extract( @@ -51,9 +63,10 @@ ripunzip_archive = repository_rule( doc = "Downloads a prebuilt ripunzip binary for the host platform from https://github.com/GoogleChrome/ripunzip/releases", attrs = { "version": attr.string(mandatory = True), - "sha256_linux": attr.string(mandatory = True), - "sha256_windows": attr.string(mandatory = True), - "sha256_macos_intel": attr.string(mandatory = True), - "sha256_macos_arm": attr.string(mandatory = True), + "sha256_linux_x64": attr.string(mandatory = True), + "sha256_linux_arm64": attr.string(mandatory = True), + "sha256_windows_x64": attr.string(mandatory = True), + "sha256_macos_x64": attr.string(mandatory = True), + "sha256_macos_arm64": attr.string(mandatory = True), }, ) diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index 2e398f4824df..dd22444f54fe 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/1.0.55.md b/misc/suite-helpers/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/misc/suite-helpers/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 9ff990aba75a..dff0d253cbce 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/suite-helpers -version: 1.0.54 +version: 1.0.55 groups: shared warnOnImplicitThis: true diff --git a/python/ql/consistency-queries/CfgConsistency.ql b/python/ql/consistency-queries/CfgConsistency.ql new file mode 100644 index 000000000000..ab13eddf190c --- /dev/null +++ b/python/ql/consistency-queries/CfgConsistency.ql @@ -0,0 +1,2 @@ +import semmle.python.controlflow.internal.AstNodeImpl +import ControlFlow::Consistency diff --git a/python/ql/integration-tests/subst/file.expected b/python/ql/integration-tests/subst/file.expected index 1bc4d03914a1..e001d4959bb5 100644 --- a/python/ql/integration-tests/subst/file.expected +++ b/python/ql/integration-tests/subst/file.expected @@ -1 +1 @@ -| code/main.py:0:0:0:0 | code/main.py | | +| code/main.py:0:0:0:0 | code/main.py | relative | diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index e36b11806aa3..2a6de92ecbce 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.2.3 + +No user-facing changes. + ## 7.2.2 No user-facing changes. diff --git a/python/ql/lib/change-notes/released/7.2.3.md b/python/ql/lib/change-notes/released/7.2.3.md new file mode 100644 index 000000000000..ba04214fb88d --- /dev/null +++ b/python/ql/lib/change-notes/released/7.2.3.md @@ -0,0 +1,3 @@ +## 7.2.3 + +No user-facing changes. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index fa4a7164fb7b..7d0dee6395ee 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 7.2.2 +lastReleaseVersion: 7.2.3 diff --git a/python/ql/lib/ide-contextual-queries/printCfg.ql b/python/ql/lib/ide-contextual-queries/printCfg.ql new file mode 100644 index 000000000000..819022c750c9 --- /dev/null +++ b/python/ql/lib/ide-contextual-queries/printCfg.ql @@ -0,0 +1,41 @@ +/** + * @name Print CFG + * @description Produces a representation of a file's Control Flow Graph. + * This query is used by the VS Code extension. + * @id py/print-cfg + * @kind graph + * @tags ide-contextual-queries/print-cfg + */ + +import semmle.python.Files as Files +import semmle.python.controlflow.internal.AstNodeImpl + +external string selectedSourceFile(); + +private predicate selectedSourceFileAlias = selectedSourceFile/0; + +external int selectedSourceLine(); + +private predicate selectedSourceLineAlias = selectedSourceLine/0; + +external int selectedSourceColumn(); + +private predicate selectedSourceColumnAlias = selectedSourceColumn/0; + +module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig { + predicate selectedSourceFile = selectedSourceFileAlias/0; + + predicate selectedSourceLine = selectedSourceLineAlias/0; + + predicate selectedSourceColumn = selectedSourceColumnAlias/0; + + predicate cfgScopeSpan( + Ast::Callable scope, Files::File file, int startLine, int startColumn, int endLine, + int endColumn + ) { + file = scope.getLocation().getFile() and + scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn) + } +} + +import ControlFlow::ViewCfgQuery diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index f2e1d18d2e19..d8914df8750b 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 7.2.2 +version: 7.2.3 groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll new file mode 100644 index 000000000000..78218f489215 --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -0,0 +1,1772 @@ +/** + * Provides classes for the shared control-flow library, mediating between + * the Python AST and `AstSig`. + * + * The `Ast` module wraps Python's `Stmt`, `Expr`, `Scope`, and `Pattern`, + * and adds two synthetic kinds of node: + * - `BlockStmt`, identifying a body slot of a parent AST node (e.g. an + * `if`'s then or else branch). `Py::StmtList` itself is not directly + * wrapped. + * - Intermediate nodes for multi-operand boolean expressions. + */ +overlay[local?] +module; + +private import python as Py +private import codeql.controlflow.ControlFlowGraph +private import codeql.controlflow.SuccessorType +private import codeql.util.Void + +/** + * Gets the bound `Name` of a PEP 695 type parameter (`TypeVar`, + * `ParamSpec`, or `TypeVarTuple`). The base `TypeParameter` class does + * not expose `getName()`; this helper dispatches over the subtypes. + */ +private Py::Name typeParameterName(Py::TypeParameter tp) { + result = tp.(Py::TypeVar).getName() + or + result = tp.(Py::ParamSpec).getName() + or + result = tp.(Py::TypeVarTuple).getName() +} + +/** Provides the Python implementation of the shared CFG `AstSig`. */ +module Ast implements AstSig { + private newtype TAstNode = + TPyStmt(Py::Stmt s) or + TPyExpr(Py::Expr e) { not e instanceof Py::BoolExpr } or + TScope(Py::Scope sc) or + TPattern(Py::Pattern p) or + /** + * A synthetic node representing an operand pair of an `and`/`or` + * expression. For `a and b and c` (operands 0, 1, 2) we model the + * operation as a right-nested tree: pair 0 represents the whole + * expression with left=a and right=pair 1; pair 1 represents + * `b and c` with left=b and right=c. Each Python `Py::BoolExpr` + * with `n` operands has `n - 1` such pairs (indices `0 .. n - 2`). + */ + TBoolExprPair(Py::BoolExpr be, int index) { index = [0 .. count(be.getAValue()) - 2] } or + /** + * A synthetic block statement, wrapping a `Py::StmtList`. Each list of + * statements that represents an imperative block (a function/class/module + * body, an `if`/`while`/`for` branch, a `try`/`except`/`finally` body, + * etc.) becomes one `BlockStmt` node in the CFG. `Py::StmtList`s used + * in other roles - `Try.getHandlers()` (iterated via `getCatch`) and + * `MatchStmt.getCases()` (iterated via `getCase`) - are excluded, as + * the shared library's `Try`/`Switch` logic walks their items + * individually. + */ + TBlockStmt(Py::StmtList sl) { + not sl = any(Py::Try t).getHandlers() and + not sl = any(Py::MatchStmt m).getCases() + } + + /** + * The union of `TPyStmt` (wrapping `Py::Stmt`) and `TBlockStmt` (wrapping + * `Py::StmtList`). Both represent the kinds of node that can appear in + * a `Stmt` position in the CFG. + */ + private class TStmt = TPyStmt or TBlockStmt; + + /** + * The union of `TPyExpr` (wrapping non-boolean `Py::Expr`) and + * `TBoolExprPair` (synthetic operand pairs of `and`/`or` expressions). + * Both represent the kinds of node that can appear in an `Expr` + * position in the CFG. + */ + private class TExpr = TPyExpr or TBoolExprPair; + + /** + * An AST node visible to the shared CFG. + * + * This is the abstract implementation class. It enforces that each + * concrete subclass provides `toString`, `getLocation`, and + * `getEnclosingCallable` (one subclass per `TAstNode` newtype branch). + * The public alias `AstNode` is what users (and the `AstSig` signature) + * see; subclasses inside this module extend `AstNodeImpl` directly. + */ + abstract private class AstNodeImpl extends TAstNode { + /** Gets a textual representation of this AST node. */ + abstract string toString(); + + /** Gets the location of this AST node. */ + abstract Py::Location getLocation(); + + /** Gets the enclosing callable that contains this node, if any. */ + abstract Callable getEnclosingCallable(); + + /** Gets the underlying Python `Stmt`, if this node wraps one. */ + Py::Stmt asStmt() { this = TPyStmt(result) } + + /** + * Gets the underlying Python `Expr`, if this node wraps one. Boolean + * expressions are represented by `TBoolExprPair(_, 0)`; this + * predicate also recovers the underlying `Py::BoolExpr` from such a + * representation. + */ + Py::Expr asExpr() { + this = TPyExpr(result) + or + this = TBoolExprPair(result, 0) + } + + /** Gets the underlying Python `Scope`, if this node wraps one. */ + Py::Scope asScope() { this = TScope(result) } + + /** Gets the underlying Python `Pattern`, if this node wraps one. */ + Py::Pattern asPattern() { this = TPattern(result) } + + /** Gets the underlying Python `StmtList`, if this node is a `BlockStmt`. */ + Py::StmtList asStmtList() { this = TBlockStmt(result) } + + /** + * Gets the child of this AST node at the specified (zero-based) + * index, in evaluation order. Subclasses with children override + * this method. + */ + AstNode getChild(int index) { none() } + } + + /** An AST node visible to the shared CFG. */ + final class AstNode = AstNodeImpl; + + /** Gets the immediately enclosing callable that contains `node`. */ + Callable getEnclosingCallable(AstNode node) { result = node.getEnclosingCallable() } + + /** + * A callable: a function, class, or module scope. + * + * In Python, all three are executable scopes with statement bodies. + */ + class Callable extends AstNodeImpl, TScope { + private Py::Scope sc; + + Callable() { this = TScope(sc) } + + override string toString() { result = sc.toString() } + + override Py::Location getLocation() { result = sc.getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = sc.getEnclosingScope() } + } + + /** Gets the body of callable `c`. */ + AstNode callableGetBody(Callable c) { result.asStmtList() = c.asScope().getBody() } + + /** + * A parameter of a callable. + * + * Modeled per the C# template (`csharp/.../ControlFlowGraph.qll`): + * each Python parameter (the `Py::Parameter` AST node, which is a `Name` + * or — Python 2 only — a `Tuple` in store context) becomes a CFG node + * at a stable position in the enclosing callable's entry sequence. + * + * Default-value expressions for positional and keyword-only parameters + * are wired separately on the `FunctionDefExpr` / `LambdaExpr` wrappers + * (they evaluate at function-definition time, not at call time). + * `Parameter::getDefaultValue()` returns `none()` here, signalling to + * the shared library that the parameter never falls back to a default + * during call binding. This mirrors C# for non-optional parameters. + */ + class Parameter extends Expr { + private Py::Parameter param; + + Parameter() { this = TPyExpr(param) } + + /** Gets the underlying Python parameter. */ + Py::Parameter asParameter() { result = param } + + /** + * Gets the default-value expression of this parameter, if any. + * + * Returns `none()`: defaults evaluate at function-definition time and + * are wired into the CFG via `FunctionDefExpr.getDefault` / + * `LambdaExpr.getDefault`. The shared library calls this predicate + * to model the "missing argument → evaluate default" fallback during + * call binding, which Python does not model at the CFG level. + */ + Expr getDefaultValue() { none() } + + /** + * Gets the pattern for this parameter. In Python, there is no destructuring + * pattern syntax for parameters, so the pattern is the parameter itself. + */ + AstNode getPattern() { result = this } + } + + /** + * Gets the `index`th parameter of callable `c`, ordered as Python binds + * them at call time: positional, then vararg (`*args`), then + * keyword-only, then kwarg (`**kwargs`). + */ + Parameter callableGetParameter(Callable c, int index) { + exists(Py::Function f | f = c.asScope() | + result.asParameter() = + rank[index + 1](Py::Parameter p, int subOrder, int subIndex | + // positional parameters first + p = f.getArg(subIndex) and subOrder = 0 + or + // then *args + p = f.getVararg() and subOrder = 1 and subIndex = 0 + or + // then keyword-only parameters + p = f.getKeywordOnlyArg(subIndex) and subOrder = 2 + or + // finally **kwargs + p = f.getKwarg() and subOrder = 3 and subIndex = 0 + | + p order by subOrder, subIndex + ) + ) + } + + /** A statement. */ + class Stmt extends AstNodeImpl, TStmt { + // For `TPyStmt` instances, delegate to the wrapped Python statement. + // `BlockStmt` (the only `TBlockStmt` subclass) provides its own overrides. + override string toString() { result = this.asStmt().toString() } + + override Py::Location getLocation() { result = this.asStmt().getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = this.asStmt().getScope() } + } + + /** An expression. */ + class Expr extends AstNodeImpl, TExpr { + // For `TPyExpr` instances, delegate to the wrapped Python expression. + // `BinaryExpr` (the only `TBoolExprPair` subclass) provides its own overrides. + override string toString() { result = this.asExpr().toString() } + + override Py::Location getLocation() { result = this.asExpr().getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = this.asExpr().getScope() } + } + + /** A pattern in a `match` statement. */ + additional class Pattern extends AstNodeImpl, TPattern { + private Py::Pattern p; + + Pattern() { this = TPattern(p) } + + override string toString() { result = p.toString() } + + override Py::Location getLocation() { result = p.getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = p.getScope() } + } + + /** + * A `case x` pattern that binds `x` to the matched value. + */ + additional class MatchCapturePattern extends Pattern { + private Py::MatchCapturePattern cap; + + MatchCapturePattern() { this = TPattern(cap) } + + /** Gets the bound Name expression. */ + Expr getVariable() { result.asExpr() = cap.getVariable() } + + override AstNode getChild(int index) { index = 0 and result = this.getVariable() } + } + + /** + * A `case pattern as name` pattern. + */ + additional class MatchAsPattern extends Pattern { + private Py::MatchAsPattern asp; + + MatchAsPattern() { this = TPattern(asp) } + + /** Gets the inner pattern. */ + AstNode getPattern() { result.asPattern() = asp.getPattern() } + + /** Gets the bound Name expression. */ + Expr getAlias() { result.asExpr() = asp.getAlias() } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern() + or + index = 1 and result = this.getAlias() + } + } + + /** + * A `case [a, b, *rest]` star pattern. Binds `rest` to the remaining + * elements of the sequence. + */ + additional class MatchStarPattern extends Pattern { + private Py::MatchStarPattern starp; + + MatchStarPattern() { this = TPattern(starp) } + + /** Gets the target Pattern (a `MatchCapturePattern` if `*rest`). */ + AstNode getTarget() { result.asPattern() = starp.getTarget() } + + override AstNode getChild(int index) { index = 0 and result = this.getTarget() } + } + + /** + * A `case [a, b, ...]` sequence pattern. Recurses into the sub-patterns. + */ + additional class MatchSequencePattern extends Pattern { + private Py::MatchSequencePattern seqp; + + MatchSequencePattern() { this = TPattern(seqp) } + + /** Gets the `n`th sub-pattern. */ + AstNode getPattern(int n) { result.asPattern() = seqp.getPattern(n) } + + override AstNode getChild(int index) { result = this.getPattern(index) } + } + + /** + * A `case Cls(a, b, x=y)` class pattern. + */ + additional class MatchClassPattern extends Pattern { + private Py::MatchClassPattern clsp; + + MatchClassPattern() { this = TPattern(clsp) } + + /** Gets the class expression of this class pattern. */ + Expr getClass() { result.asExpr() = clsp.getClass() } + + /** Gets the `n`th positional sub-pattern. */ + AstNode getPositional(int n) { result.asPattern() = clsp.getPositional(n) } + + /** Gets the `n`th keyword sub-pattern. */ + AstNode getKeyword(int n) { result.asPattern() = clsp.getKeyword(n) } + + private int numPositional() { result = count(int i | exists(clsp.getPositional(i))) } + + override AstNode getChild(int index) { + index = 0 and result = this.getClass() + or + result = this.getPositional(index - 1) and index >= 1 + or + result = this.getKeyword(index - 1 - this.numPositional()) and + index >= 1 + this.numPositional() + } + } + + /** + * A `case {k: v}` mapping pattern. + */ + additional class MatchMappingPattern extends Pattern { + private Py::MatchMappingPattern mapp; + + MatchMappingPattern() { this = TPattern(mapp) } + + AstNode getMapping(int n) { result.asPattern() = mapp.getMapping(n) } + + override AstNode getChild(int index) { result = this.getMapping(index) } + } + + /** + * A key-value pair inside a `case {k: v}` mapping pattern. + */ + additional class MatchKeyValuePattern extends Pattern { + private Py::MatchKeyValuePattern kvp; + + MatchKeyValuePattern() { this = TPattern(kvp) } + + AstNode getKey() { result.asPattern() = kvp.getKey() } + + AstNode getValue() { result.asPattern() = kvp.getValue() } + + override AstNode getChild(int index) { + index = 0 and result = this.getKey() + or + index = 1 and result = this.getValue() + } + } + + /** + * A `case Cls(name=value)` keyword sub-pattern. + */ + additional class MatchKeywordPattern extends Pattern { + private Py::MatchKeywordPattern kwp; + + MatchKeywordPattern() { this = TPattern(kwp) } + + Expr getAttribute() { result.asExpr() = kwp.getAttribute() } + + AstNode getValue() { result.asPattern() = kwp.getValue() } + + override AstNode getChild(int index) { + index = 0 and result = this.getAttribute() + or + index = 1 and result = this.getValue() + } + } + + /** A `case **rest` double-star mapping sub-pattern. */ + additional class MatchDoubleStarPattern extends Pattern { + private Py::MatchDoubleStarPattern dsp; + + MatchDoubleStarPattern() { this = TPattern(dsp) } + + AstNode getTarget() { result.asPattern() = dsp.getTarget() } + + override AstNode getChild(int index) { index = 0 and result = this.getTarget() } + } + + /** A `case p1 | p2 | …` or-pattern. */ + additional class MatchOrPattern extends Pattern { + private Py::MatchOrPattern orp; + + MatchOrPattern() { this = TPattern(orp) } + + AstNode getPattern(int n) { result.asPattern() = orp.getPattern(n) } + + override AstNode getChild(int index) { result = this.getPattern(index) } + } + + /** A `case 1` literal pattern. */ + additional class MatchLiteralPattern extends Pattern { + private Py::MatchLiteralPattern litp; + + MatchLiteralPattern() { this = TPattern(litp) } + + Expr getLiteral() { result.asExpr() = litp.getLiteral() } + + override AstNode getChild(int index) { index = 0 and result = this.getLiteral() } + } + + /** A `case Cls.NAME` value pattern. */ + additional class MatchValuePattern extends Pattern { + private Py::MatchValuePattern vp; + + MatchValuePattern() { this = TPattern(vp) } + + Expr getValue() { result.asExpr() = vp.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** + * A block statement, modeling the body of a parent AST node as a + * sequence of statements. + */ + class BlockStmt extends Stmt, TBlockStmt { + private Py::StmtList sl; + + BlockStmt() { this = TBlockStmt(sl) } + + /** Gets the `n`th (zero-based) statement in this block. */ + Stmt getStmt(int n) { result.asStmt() = sl.getItem(n) } + + /** Gets the last statement in this block. */ + Stmt getLastStmt() { result.asStmt() = sl.getLastItem() } + + override string toString() { result = sl.toString() } + + // `Py::StmtList` has no native location; approximate with the first + // item's location. + override Py::Location getLocation() { result = sl.getItem(0).getLocation() } + + override Callable getEnclosingCallable() { + result.asScope() = sl.getParent().(Py::Scope) + or + result.asScope() = sl.getParent().(Py::Stmt).getScope() + } + + override AstNode getChild(int index) { result = this.getStmt(index) } + } + + /** An expression statement. */ + class ExprStmt extends Stmt { + private Py::ExprStmt exprStmt; + + ExprStmt() { this = TPyStmt(exprStmt) } + + /** Gets the expression in this expression statement. */ + Expr getExpr() { result.asExpr() = exprStmt.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getExpr() } + } + + /** An assignment statement (`x = y = expr`). */ + additional class AssignStmt extends Stmt { + private Py::Assign assign; + + AssignStmt() { this = TPyStmt(assign) } + + Expr getValue() { result.asExpr() = assign.getValue() } + + Expr getTarget(int n) { result.asExpr() = assign.getTarget(n) } + + int getNumberOfTargets() { result = count(assign.getATarget()) } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + result = this.getTarget(index - 1) and index >= 1 + } + } + + /** An augmented assignment statement (`x += expr`). */ + additional class AugAssignStmt extends Stmt { + private Py::AugAssign augAssign; + + AugAssignStmt() { this = TPyStmt(augAssign) } + + Expr getOperation() { result.asExpr() = augAssign.getOperation() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperation() } + } + + /** + * An annotated assignment statement (`x: T = expr`, or `x: T` without + * value). The evaluation order follows CPython: annotation first, then + * the optional value, then the target binding. + */ + additional class AnnAssignStmt extends Stmt { + private Py::AnnAssign annAssign; + + AnnAssignStmt() { this = TPyStmt(annAssign) } + + Expr getAnnotation() { result.asExpr() = annAssign.getAnnotation() } + + Expr getValue() { result.asExpr() = annAssign.getValue() } + + Expr getTarget() { result.asExpr() = annAssign.getTarget() } + + override AstNode getChild(int index) { + index = 0 and result = this.getAnnotation() + or + index = 1 and result = this.getValue() + or + index = 2 and result = this.getTarget() + } + } + + /** An assignment expression / walrus operator (`x := expr`). */ + additional class NamedExpr extends Expr { + private Py::AssignExpr assignExpr; + + NamedExpr() { this = TPyExpr(assignExpr) } + + Expr getValue() { result.asExpr() = assignExpr.getValue() } + + Expr getTarget() { result.asExpr() = assignExpr.getTarget() } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + index = 1 and result = this.getTarget() + } + } + + /** + * An `if` statement. + * + * Python's `elif` chains are represented as nested `If` nodes in the + * else branch's `StmtList`. The shared CFG library handles this + * naturally: `getElse()` returns the `BlockStmt` wrapping the else + * branch, and if that block contains a single `If`, the result is + * a chained conditional. + */ + class IfStmt extends Stmt { + private Py::If ifStmt; + + IfStmt() { this = TPyStmt(ifStmt) } + + /** Gets the underlying Python `If` statement. */ + Py::If asIf() { result = ifStmt } + + /** Gets the condition of this `if` statement. */ + Expr getCondition() { result.asExpr() = ifStmt.getTest() } + + /** Gets the `then` (true) branch of this `if` statement. */ + Stmt getThen() { result.asStmtList() = ifStmt.getBody() } + + /** Gets the `else` (false) branch, if any. */ + Stmt getElse() { result.asStmtList() = ifStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getThen() + or + index = 2 and result = this.getElse() + } + } + + /** A loop statement. */ + final class LoopStmt = LoopStmtImpl; + + abstract private class LoopStmtImpl extends Stmt { + LoopStmtImpl() { + this = TPyStmt(any(Py::While w)) + or + this = TPyStmt(any(Py::For f)) + } + + /** Gets the body of this loop statement. */ + Stmt getBody() { none() } + } + + /** A `while` loop statement. */ + class WhileStmt extends LoopStmtImpl { + private Py::While whileStmt; + + WhileStmt() { this = TPyStmt(whileStmt) } + + /** Gets the boolean condition of this `while` loop. */ + Expr getCondition() { result.asExpr() = whileStmt.getTest() } + + override Stmt getBody() { result.asStmtList() = whileStmt.getBody() } + + /** Gets the `else` branch of this `while` loop, if any. */ + Stmt getElse() { result.asStmtList() = whileStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getBody() + or + index = 2 and result = this.getElse() + } + } + + /** + * A `do-while` loop statement. Python has no do-while construct. + */ + class DoStmt extends LoopStmtImpl { + DoStmt() { none() } + + Expr getCondition() { none() } + } + + /** An `until` loop. Python has no `until` loop. */ + class UntilStmt extends LoopStmtImpl { + UntilStmt() { none() } + + Expr getCondition() { none() } + } + + /** A C-style `for` loop. Python has no C-style for loop. */ + class ForStmt extends LoopStmtImpl { + ForStmt() { none() } + + AstNode getInit(int index) { none() } + + Expr getCondition() { none() } + + AstNode getUpdate(int index) { none() } + } + + /** A for-each loop (`for x in iterable:`). */ + class ForeachStmt extends LoopStmtImpl { + private Py::For forStmt; + + ForeachStmt() { this = TPyStmt(forStmt) } + + /** Gets the loop variable. */ + Expr getVariable() { result.asExpr() = forStmt.getTarget() } + + /** Gets the collection being iterated. */ + Expr getCollection() { result.asExpr() = forStmt.getIter() } + + override Stmt getBody() { result.asStmtList() = forStmt.getBody() } + + /** Gets the `else` branch of this `for` loop, if any. */ + Stmt getElse() { result.asStmtList() = forStmt.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCollection() + or + index = 1 and result = this.getVariable() + or + index = 2 and result = this.getBody() + or + index = 3 and result = this.getElse() + } + } + + /** A `break` statement. */ + class BreakStmt extends Stmt { + BreakStmt() { this = TPyStmt(any(Py::Break b)) } + } + + /** A `continue` statement. */ + class ContinueStmt extends Stmt { + ContinueStmt() { this = TPyStmt(any(Py::Continue c)) } + } + + /** A `goto` statement. Python has no goto. */ + class GotoStmt extends Stmt { + GotoStmt() { none() } + } + + /** A `return` statement. */ + class ReturnStmt extends Stmt { + private Py::Return ret; + + ReturnStmt() { this = TPyStmt(ret) } + + /** Gets the expression being returned, if any. */ + Expr getExpr() { result.asExpr() = ret.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getExpr() } + } + + /** A `raise` statement (mapped to `Throw`). */ + class Throw extends Stmt { + private Py::Raise raise; + + Throw() { this = TPyStmt(raise) } + + /** Gets the expression being raised. */ + Expr getExpr() { result.asExpr() = raise.getException() } + + /** Gets the cause of this `raise`, if any. */ + Expr getCause() { result.asExpr() = raise.getCause() } + + override AstNode getChild(int index) { + index = 0 and result = this.getExpr() + or + index = 1 and result = this.getCause() + } + } + + /** + * An `import` statement (`import a, b` or `from m import a, b`). + * + * Each alias contributes two children in evaluation order: first the + * value expression (which performs the import side-effect), then the + * bound `asname` Name (the in-scope binding). This makes both reachable + * from the CFG and allows `Name.defines(v)` for `asname` Names to have + * corresponding CFG nodes — which is essential for SSA to see import + * bindings. + */ + additional class ImportStmt extends Stmt { + private Py::Import imp; + + ImportStmt() { this = TPyStmt(imp) } + + /** Gets the value (module/member expression) of the `n`th alias. */ + Expr getValue(int n) { result.asExpr() = imp.getName(n).getValue() } + + /** Gets the bound `asname` of the `n`th alias. */ + Expr getAsname(int n) { result.asExpr() = imp.getName(n).getAsname() } + + /** Gets the number of aliases in this import statement. */ + int getNumberOfAliases() { result = count(int i | exists(imp.getName(i))) } + + override AstNode getChild(int index) { + exists(int i | + index = 2 * i and result = this.getValue(i) + or + index = 2 * i + 1 and result = this.getAsname(i) + ) + } + } + + /** + * A `from m import *` statement. Evaluates the module expression but + * binds no name (the bindings happen by side-effect at runtime, which + * is not modeled at the CFG level). + */ + additional class ImportStarStmt extends Stmt { + private Py::ImportStar imp; + + ImportStarStmt() { this = TPyStmt(imp) } + + Expr getModule() { result.asExpr() = imp.getModule() } + + override AstNode getChild(int index) { index = 0 and result = this.getModule() } + } + + /** A `with` statement. */ + additional class WithStmt extends Stmt { + private Py::With withStmt; + + WithStmt() { this = TPyStmt(withStmt) } + + Expr getContextExpr() { result.asExpr() = withStmt.getContextExpr() } + + Expr getOptionalVars() { result.asExpr() = withStmt.getOptionalVars() } + + Stmt getBody() { result.asStmtList() = withStmt.getBody() } + + override AstNode getChild(int index) { + index = 0 and result = this.getContextExpr() + or + index = 1 and result = this.getOptionalVars() + or + index = 2 and result = this.getBody() + } + } + + /** An `assert` statement. */ + additional class AssertStmt extends Stmt { + private Py::Assert assertStmt; + + AssertStmt() { this = TPyStmt(assertStmt) } + + Expr getTest() { result.asExpr() = assertStmt.getTest() } + + Expr getMsg() { result.asExpr() = assertStmt.getMsg() } + + override AstNode getChild(int index) { + index = 0 and result = this.getTest() + or + index = 1 and result = this.getMsg() + } + } + + /** A `delete` statement. */ + additional class DeleteStmt extends Stmt { + private Py::Delete del; + + DeleteStmt() { this = TPyStmt(del) } + + Expr getTarget(int n) { result.asExpr() = del.getTarget(n) } + + override AstNode getChild(int index) { result = this.getTarget(index) } + } + + /** + * A PEP 695 `type` statement (`type Alias[T1, T2] = value`). + * + * The type parameters bind at statement-evaluation time. The value + * expression is captured for lazy evaluation but the alias `Name` + * itself binds the resulting `TypeAliasType` object — so the CFG must + * visit at minimum the type-parameter names and the alias name. + */ + additional class TypeAliasStmt extends Stmt { + private Py::TypeAlias ta; + + TypeAliasStmt() { this = TPyStmt(ta) } + + /** Gets the alias `Name` bound by this statement. */ + Expr getName() { result.asExpr() = ta.getName() } + + /** + * Gets the `n`th PEP 695 type-parameter name (a `Name` in store + * context), in declaration order. + */ + Expr getTypeParamName(int n) { result.asExpr() = typeParameterName(ta.getTypeParameter(n)) } + + int getNumberOfTypeParams() { result = count(ta.getATypeParameter()) } + + override AstNode getChild(int index) { + result = this.getTypeParamName(index) + or + index = this.getNumberOfTypeParams() and result = this.getName() + } + } + + /** A `try` statement. */ + class TryStmt extends Stmt { + private Py::Try tryStmt; + + TryStmt() { this = TPyStmt(tryStmt) } + + AstNode getBody(int index) { index = 0 and result.asStmtList() = tryStmt.getBody() } + + /** Gets the `else` branch of this `try` statement, if any. */ + Stmt getElse() { result.asStmtList() = tryStmt.getOrelse() } + + Stmt getFinally() { result.asStmtList() = tryStmt.getFinalbody() } + + CatchClause getCatch(int index) { result.asStmt() = tryStmt.getHandler(index) } + + override AstNode getChild(int index) { + index = 0 and result = this.getBody(0) + or + result = this.getCatch(index - 1) and index >= 1 + or + index = -1 and result = this.getFinally() + or + index = -2 and result = this.getElse() + } + } + + /** + * Gets the `else` branch of `try` statement `try`, if any. + */ + AstNode getTryElse(TryStmt try) { result = try.getElse() } + + /** + * Gets the `else` branch of loop `loop`, if any. + * + * Python's `while`/`for` loops may have an `else` block that runs when the + * loop completes without `break`. + */ + AstNode getLoopElse(LoopStmt loop) { + result = loop.(WhileStmt).getElse() + or + result = loop.(ForeachStmt).getElse() + } + + /** An exception handler (`except` or `except*`). */ + class CatchClause extends Stmt { + private Py::ExceptionHandler handler; + + CatchClause() { this = TPyStmt(handler) } + + /** + * Gets the type-test pattern of this exception handler, if any. + * + * This is the single syntactic type expression (`except TypeError:` → + * `TypeError`; `except (A, B):` → the `(A, B)` tuple). A bare `except:` + * has no pattern and is therefore a catch-all that matches any + * exception. The type test and the variable binding are independent + * child nodes in Python, matching the shared CFG model. + * + * We read the raw type child directly (extractor relation `py_exprs` + * at child index 1) rather than the public `getType()` accessor: the + * latter flattens a tuple of exception types (`except (A, B):`) into + * its individual elements, which would yield several patterns for one + * handler and violate the shared CFG's single-pattern-per-catch + * contract. The raw child is the one tuple node, modeling the + * runtime's single `isinstance(exc, (A, B))` test. + */ + AstNode getPattern() { + exists(Py::Expr rawType | py_exprs(rawType, _, handler, 1) | result.asExpr() = rawType) + } + + /** Gets the variable name of this exception handler, if any. */ + AstNode getVariable() { result.asExpr() = handler.getName() } + + /** Holds: catch clauses do not have a `Condition` in Python's model. */ + Expr getCondition() { none() } + + /** Gets the body of this exception handler. */ + Stmt getBody() { + result.asStmtList() = handler.(Py::ExceptStmt).getBody() + or + result.asStmtList() = handler.(Py::ExceptGroupStmt).getBody() + } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern() + or + index = 1 and result = this.getVariable() + or + index = 2 and result = this.getBody() + } + } + + /** A `match` statement, mapped to the shared CFG's `Switch`. */ + class Switch extends Stmt { + private Py::MatchStmt matchStmt; + + Switch() { this = TPyStmt(matchStmt) } + + Expr getExpr() { result.asExpr() = matchStmt.getSubject() } + + Case getCase(int index) { result.asStmt() = matchStmt.getCase(index) } + + Stmt getStmt(int index) { none() } + + override AstNode getChild(int index) { + index = 0 and result = this.getExpr() + or + result = this.getCase(index - 1) and index >= 1 + } + } + + /** A `case` clause in a match statement. */ + class Case extends Stmt { + private Py::Case caseStmt; + + Case() { this = TPyStmt(caseStmt) } + + AstNode getPattern(int index) { index = 0 and result.asPattern() = caseStmt.getPattern() } + + Expr getGuard() { result.asExpr() = caseStmt.getGuard().(Py::Guard).getTest() } + + AstNode getBody() { result.asStmtList() = caseStmt.getBody() } + + /** Holds if this case is a wildcard pattern (`case _:`). */ + predicate isWildcard() { caseStmt.getPattern() instanceof Py::MatchWildcardPattern } + + override AstNode getChild(int index) { + index = 0 and result = this.getPattern(0) + or + index = 1 and result = this.getGuard() + or + index = 2 and result = this.getBody() + } + } + + /** A wildcard case (`case _:`). */ + class DefaultCase extends Case { + DefaultCase() { this.isWildcard() } + } + + /** A conditional expression (`x if cond else y`). */ + class ConditionalExpr extends Expr { + private Py::IfExp ifExp; + + ConditionalExpr() { this = TPyExpr(ifExp) } + + /** Gets the condition of this expression. */ + Expr getCondition() { result.asExpr() = ifExp.getTest() } + + /** Gets the true branch of this expression. */ + Expr getThen() { result.asExpr() = ifExp.getBody() } + + /** Gets the false branch of this expression. */ + Expr getElse() { result.asExpr() = ifExp.getOrelse() } + + override AstNode getChild(int index) { + index = 0 and result = this.getCondition() + or + index = 1 and result = this.getThen() + or + index = 2 and result = this.getElse() + } + } + + /** + * A binary expression for the shared CFG. In Python, this covers all + * `and`/`or` expression operand pairs. + */ + class BinaryExpr extends Expr, TBoolExprPair { + private Py::BoolExpr be; + private int index; + + BinaryExpr() { this = TBoolExprPair(be, index) } + + /** Gets the underlying Python `BoolExpr`. */ + Py::BoolExpr getBoolExpr() { result = be } + + /** Gets the (zero-based) index of this pair within its `BoolExpr`. */ + int getIndex() { result = index } + + override string toString() { result = be.getOperator() } + + override Py::Location getLocation() { result = be.getValue(index).getLocation() } + + override Callable getEnclosingCallable() { result.asScope() = be.getScope() } + + /** Gets the left operand of this binary expression. */ + Expr getLeftOperand() { result.asExpr() = be.getValue(index) } + + /** Gets the right operand of this binary expression. */ + Expr getRightOperand() { + // Last pair: right operand is the final value. + index = count(be.getAValue()) - 2 and result.asExpr() = be.getValue(index + 1) + or + // Non-last pair: right operand is the next synthetic pair. + index < count(be.getAValue()) - 2 and + exists(BinaryExpr next | + next.getBoolExpr() = be and next.getIndex() = index + 1 and result = next + ) + } + + override AstNode getChild(int childIndex) { + childIndex = 0 and result = this.getLeftOperand() + or + childIndex = 1 and result = this.getRightOperand() + } + } + + /** A short-circuiting logical `and` expression. */ + class LogicalAndExpr extends BinaryExpr { + LogicalAndExpr() { this.getBoolExpr().getOp() instanceof Py::And } + } + + /** A short-circuiting logical `or` expression. */ + class LogicalOrExpr extends BinaryExpr { + LogicalOrExpr() { this.getBoolExpr().getOp() instanceof Py::Or } + } + + /** A null-coalescing expression. Python has no null-coalescing operator. */ + class NullCoalescingExpr extends BinaryExpr { + NullCoalescingExpr() { none() } + } + + /** + * A unary expression. Currently only used for the `not` subclass. + */ + class UnaryExpr extends Expr { + UnaryExpr() { exists(Py::UnaryExpr u | this = TPyExpr(u) and u.getOp() instanceof Py::Not) } + + /** Gets the operand of this unary expression. */ + Expr getOperand() { result.asExpr() = this.asExpr().(Py::UnaryExpr).getOperand() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperand() } + } + + /** A logical `not` expression. */ + class LogicalNotExpr extends UnaryExpr { } + + /** + * An assignment expression. + * + * Empty in Python: `x = y` and `x += y` are statements (`AssignStmt` and + * `AugAssignStmt`), not expressions, and the walrus `x := y` is modeled + * separately as `NamedExpr`. The shared library's `Assignment` extends + * `BinaryExpr`, so it cannot share instances with our `Stmt`-based + * assignment forms. + */ + class Assignment extends BinaryExpr { + Assignment() { none() } + } + + /** A simple assignment expression. Empty in Python (see `Assignment`). */ + class AssignExpr extends Assignment { } + + /** A compound assignment expression. Empty in Python (see `Assignment`). */ + class CompoundAssignment extends Assignment { } + + /** + * A short-circuiting logical AND compound assignment expression (`&&=`). + * Python has no such operator. + */ + class AssignLogicalAndExpr extends CompoundAssignment { } + + /** + * A short-circuiting logical OR compound assignment expression (`||=`). + * Python has no such operator. + */ + class AssignLogicalOrExpr extends CompoundAssignment { } + + /** + * A short-circuiting null-coalescing compound assignment expression + * (`??=`). Python has no such operator. + */ + class AssignNullCoalescingExpr extends CompoundAssignment { } + + /** A boolean literal expression (`True` or `False`). */ + class BooleanLiteral extends Expr { + BooleanLiteral() { this = TPyExpr(any(Py::True t)) or this = TPyExpr(any(Py::False f)) } + + /** Gets the boolean value of this literal. */ + boolean getValue() { + this.asExpr() instanceof Py::True and result = true + or + this.asExpr() instanceof Py::False and result = false + } + } + + /** A pattern match expression. Python has no `instanceof`-style pattern match expression. */ + class PatternMatchExpr extends Expr { + PatternMatchExpr() { none() } + + Expr getExpr() { none() } + + AstNode getPattern() { none() } + } + + // ===== Python-specific expression classes (used by `getChild`) ===== + /** A Python binary expression (arithmetic, bitwise, matmul, etc.). */ + additional class ArithBinaryExpr extends Expr { + private Py::BinaryExpr binExpr; + + ArithBinaryExpr() { this = TPyExpr(binExpr) } + + Expr getLeft() { result.asExpr() = binExpr.getLeft() } + + Expr getRight() { result.asExpr() = binExpr.getRight() } + + override AstNode getChild(int index) { + index = 0 and result = this.getLeft() + or + index = 1 and result = this.getRight() + } + } + + /** A call expression (`func(args...)`). */ + additional class CallExpr extends Expr { + private Py::Call call; + + CallExpr() { this = TPyExpr(call) } + + Expr getFunc() { result.asExpr() = call.getFunc() } + + Expr getPositionalArg(int n) { result.asExpr() = call.getPositionalArg(n) } + + int getNumberOfPositionalArgs() { result = count(call.getAPositionalArg()) } + + Expr getKeywordValue(int n) { + result.asExpr() = call.getNamedArg(n).(Py::Keyword).getValue() + or + result.asExpr() = call.getNamedArg(n).(Py::DictUnpacking).getValue() + } + + int getNumberOfNamedArgs() { result = count(call.getANamedArg()) } + + override AstNode getChild(int index) { + index = 0 and result = this.getFunc() + or + result = this.getPositionalArg(index - 1) and index >= 1 + or + result = this.getKeywordValue(index - 1 - this.getNumberOfPositionalArgs()) and + index >= 1 + this.getNumberOfPositionalArgs() + } + } + + /** A subscript expression (`obj[index]`). */ + additional class SubscriptExpr extends Expr { + private Py::Subscript sub; + + SubscriptExpr() { this = TPyExpr(sub) } + + Expr getObject() { result.asExpr() = sub.getObject() } + + Expr getIndex() { result.asExpr() = sub.getIndex() } + + override AstNode getChild(int index) { + index = 0 and result = this.getObject() + or + index = 1 and result = this.getIndex() + } + } + + /** An attribute access (`obj.name`). */ + additional class AttributeExpr extends Expr { + private Py::Attribute attr; + + AttributeExpr() { this = TPyExpr(attr) } + + Expr getObject() { result.asExpr() = attr.getObject() } + + override AstNode getChild(int index) { index = 0 and result = this.getObject() } + } + + /** + * An `import x.y` module expression. Modeled as a leaf — the dotted + * name is just a string. + */ + additional class ImportExpression extends Expr { + ImportExpression() { this.asExpr() instanceof Py::ImportExpr } + } + + /** + * A `from m import x` member access. The module sub-expression is a + * child so that the CFG visits both the module load and this + * attribute selection. + */ + additional class ImportMemberExpr extends Expr { + private Py::ImportMember im; + + ImportMemberExpr() { this = TPyExpr(im) } + + /** Gets the module expression `m` in `from m import x`. */ + Expr getModule() { result.asExpr() = im.getModule() } + + override AstNode getChild(int index) { index = 0 and result = this.getModule() } + } + + /** A tuple literal. */ + additional class TupleExpr extends Expr { + private Py::Tuple tuple; + + TupleExpr() { this = TPyExpr(tuple) } + + Expr getElt(int n) { result.asExpr() = tuple.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A list literal. */ + additional class ListExpr extends Expr { + private Py::List list; + + ListExpr() { this = TPyExpr(list) } + + Expr getElt(int n) { result.asExpr() = list.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A set literal. */ + additional class SetExpr extends Expr { + private Py::Set set; + + SetExpr() { this = TPyExpr(set) } + + Expr getElt(int n) { result.asExpr() = set.getElt(n) } + + override AstNode getChild(int index) { result = this.getElt(index) } + } + + /** A dict literal. */ + additional class DictExpr extends Expr { + private Py::Dict dict; + + DictExpr() { this = TPyExpr(dict) } + + /** + * Gets the key of the `n`th item (at child index `2*n`); the value is + * at child index `2*n + 1`. + */ + Expr getKey(int n) { result.asExpr() = dict.getItem(n).(Py::KeyValuePair).getKey() } + + Expr getValue(int n) { result.asExpr() = dict.getItem(n).(Py::KeyValuePair).getValue() } + + int getNumberOfItems() { result = count(dict.getAnItem()) } + + override AstNode getChild(int index) { + exists(int item | + index = 2 * item and result = this.getKey(item) + or + index = 2 * item + 1 and result = this.getValue(item) + ) + } + } + + /** A unary expression other than `not` (e.g., `-x`, `+x`, `~x`). */ + additional class ArithUnaryExpr extends Expr { + private Py::UnaryExpr unaryExpr; + + ArithUnaryExpr() { this = TPyExpr(unaryExpr) and not unaryExpr.getOp() instanceof Py::Not } + + Expr getOperand() { result.asExpr() = unaryExpr.getOperand() } + + override AstNode getChild(int index) { index = 0 and result = this.getOperand() } + } + + /** + * A comprehension or generator expression. The iterable is evaluated in + * the enclosing scope; the body runs in a nested synthetic function + * scope handled by its own CFG. + */ + additional class Comprehension extends Expr { + private Py::Expr iterable; + + Comprehension() { + exists(Py::Expr c | this = TPyExpr(c) | + iterable = c.(Py::ListComp).getIterable() + or + iterable = c.(Py::SetComp).getIterable() + or + iterable = c.(Py::DictComp).getIterable() + or + iterable = c.(Py::GeneratorExp).getIterable() + ) + } + + Expr getIterable() { result.asExpr() = iterable } + + override AstNode getChild(int index) { index = 0 and result = this.getIterable() } + } + + /** A comparison expression (`a < b`, `a < b < c`, etc.). */ + additional class CompareExpr extends Expr { + private Py::Compare cmp; + + CompareExpr() { this = TPyExpr(cmp) } + + Expr getLeft() { result.asExpr() = cmp.getLeft() } + + Expr getComparator(int n) { result.asExpr() = cmp.getComparator(n) } + + override AstNode getChild(int index) { + index = 0 and result = this.getLeft() + or + result = this.getComparator(index - 1) and index >= 1 + } + } + + /** A slice expression (`start:stop:step`). */ + additional class SliceExpr extends Expr { + private Py::Slice slice; + + SliceExpr() { this = TPyExpr(slice) } + + Expr getStart() { result.asExpr() = slice.getStart() } + + Expr getStop() { result.asExpr() = slice.getStop() } + + Expr getStep() { result.asExpr() = slice.getStep() } + + override AstNode getChild(int index) { + index = 0 and result = this.getStart() + or + index = 1 and result = this.getStop() + or + index = 2 and result = this.getStep() + } + } + + /** A starred expression (`*x`). */ + additional class StarredExpr extends Expr { + private Py::Starred starred; + + StarredExpr() { this = TPyExpr(starred) } + + Expr getValue() { result.asExpr() = starred.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** A formatted string literal (`f"...{expr}..."`). */ + additional class FstringExpr extends Expr { + private Py::Fstring fstring; + + FstringExpr() { this = TPyExpr(fstring) } + + Expr getValue(int n) { result.asExpr() = fstring.getValue(n) } + + override AstNode getChild(int index) { result = this.getValue(index) } + } + + /** A formatted value inside an f-string (`{expr}` or `{expr:spec}`). */ + additional class FormattedValueExpr extends Expr { + private Py::FormattedValue fv; + + FormattedValueExpr() { this = TPyExpr(fv) } + + Expr getValue() { result.asExpr() = fv.getValue() } + + Expr getFormatSpec() { result.asExpr() = fv.getFormatSpec() } + + override AstNode getChild(int index) { + index = 0 and result = this.getValue() + or + index = 1 and result = this.getFormatSpec() + } + } + + /** A `yield` expression. */ + additional class YieldExpr extends Expr { + private Py::Yield yield; + + YieldExpr() { this = TPyExpr(yield) } + + Expr getValue() { result.asExpr() = yield.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** A `yield from` expression. */ + additional class YieldFromExpr extends Expr { + private Py::YieldFrom yieldFrom; + + YieldFromExpr() { this = TPyExpr(yieldFrom) } + + Expr getValue() { result.asExpr() = yieldFrom.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** An `await` expression. */ + additional class AwaitExpr extends Expr { + private Py::Await await; + + AwaitExpr() { this = TPyExpr(await) } + + Expr getValue() { result.asExpr() = await.getValue() } + + override AstNode getChild(int index) { index = 0 and result = this.getValue() } + } + + /** + * A class definition expression (visits bases, but NOT PEP 695 type + * parameters — those bind in an annotation scope that nests the class + * body, so they belong to the inner scope's CFG, not the enclosing + * scope's; the legacy CFG also omitted them). + */ + additional class ClassDefExpr extends Expr { + private Py::ClassExpr classExpr; + + ClassDefExpr() { this = TPyExpr(classExpr) } + + Expr getBase(int n) { result.asExpr() = classExpr.getBase(n) } + + override AstNode getChild(int index) { result = this.getBase(index) } + } + + /** + * A function definition expression (visits positional and keyword + * defaults followed by parameter and return type annotations, but NOT + * PEP 695 type parameters — those bind in an annotation scope that + * nests the function body, so they belong to the inner scope's CFG, + * not the enclosing scope's; the legacy CFG also omitted them). + * + * Evaluation order follows CPython: defaults are pushed first, then + * keyword-only defaults, then annotations (the `__annotations__` dict + * is built last, before `MAKE_FUNCTION`). Annotations are emitted as + * CFG nodes so that flows from a class reference into a parameter's + * type annotation are visible to dataflow (e.g. so that framework + * models like FastAPI's `Depends()` can use a parameter's type hint + * to track that the parameter receives an instance of the annotated + * class — see `LocalSources::annotatedInstance`). + */ + additional class FunctionDefExpr extends Expr { + private Py::FunctionExpr funcExpr; + + FunctionDefExpr() { this = TPyExpr(funcExpr) } + + /** + * Gets the `n`th default for a positional argument, in evaluation + * order. Note that `Args.getDefault(int)` is indexed by argument + * position (with gaps for arguments without defaults), so we must + * renumber here to obtain contiguous indices. + */ + Expr getDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getDefault(i) | d order by i) + } + + /** Gets the `n`th default for a keyword-only argument, in evaluation order. */ + Expr getKwDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getKwDefault(i) | d order by i) + } + + /** + * Gets the `n`th annotation expression, in CPython evaluation + * order: positional parameter annotations (by argument position), + * `*args` annotation, keyword-only parameter annotations (by + * argument position), `**kwargs` annotation, then the return + * annotation. Each annotation appears at most once. + */ + Expr getAnnotation(int n) { + result.asExpr() = + rank[n + 1](Py::Expr a, int subOrder, int subIndex | + functionAnnotation(funcExpr, a, subOrder, subIndex) + | + a order by subOrder, subIndex + ) + } + + int getNumberOfDefaults() { result = count(funcExpr.getArgs().getADefault()) } + + int getNumberOfKwDefaults() { result = count(funcExpr.getArgs().getAKwDefault()) } + + int getNumberOfAnnotations() { + result = count(Py::Expr a | functionAnnotation(funcExpr, a, _, _)) + } + + override AstNode getChild(int index) { + result = this.getDefault(index) + or + result = this.getKwDefault(index - this.getNumberOfDefaults()) + or + result = this.getAnnotation(index - this.getNumberOfDefaults() - this.getNumberOfKwDefaults()) + } + } + + /** + * Holds if `a` is an annotation of `funcExpr` in slot + * `(subOrder, subIndex)`. Slots are CPython evaluation order: + * positional param annotations (subOrder 0, subIndex = argument + * position), `*args` annotation (1, 0), keyword-only annotations + * (2, position), `**kwargs` annotation (3, 0), return annotation + * (4, 0). + */ + private predicate functionAnnotation( + Py::FunctionExpr funcExpr, Py::Expr a, int subOrder, int subIndex + ) { + a = funcExpr.getArgs().getAnnotation(subIndex) and subOrder = 0 + or + a = funcExpr.getArgs().getVarargannotation() and subOrder = 1 and subIndex = 0 + or + a = funcExpr.getArgs().getKwAnnotation(subIndex) and subOrder = 2 + or + a = funcExpr.getArgs().getKwargannotation() and subOrder = 3 and subIndex = 0 + or + a = funcExpr.getReturns() and subOrder = 4 and subIndex = 0 + } + + /** A lambda expression (has default args evaluated at definition time). */ + additional class LambdaExpr extends Expr { + private Py::Lambda lambda; + + LambdaExpr() { this = TPyExpr(lambda) } + + /** Gets the `n`th default for a positional argument, in evaluation order. */ + Expr getDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = lambda.getArgs().getDefault(i) | d order by i) + } + + /** Gets the `n`th default for a keyword-only argument, in evaluation order. */ + Expr getKwDefault(int n) { + result.asExpr() = + rank[n + 1](Py::Expr d, int i | d = lambda.getArgs().getKwDefault(i) | d order by i) + } + + int getNumberOfDefaults() { result = count(lambda.getArgs().getADefault()) } + + override AstNode getChild(int index) { + result = this.getDefault(index) + or + result = this.getKwDefault(index - this.getNumberOfDefaults()) + } + } + + /** Gets the child of `n` at the specified (zero-based) index. */ + AstNode getChild(AstNode n, int index) { result = n.getChild(index) } +} + +private module Cfg0 = Make0; + +private import Cfg0 + +private module Cfg1 = Make1; + +private import Cfg1 + +private module Cfg2 = Make2; + +private import Cfg2 + +private module Input implements InputSig1, InputSig2 { + predicate cfgCachedStageRef() { CfgCachedStage::ref() } + + private newtype TLabel = TNone() + + class Label extends TLabel { + string toString() { result = "label" } + } + + class CallableContext = Void; + + predicate inConditionalContext(Ast::AstNode n, ConditionKind kind) { + kind.isBoolean() and + n = any(Ast::AssertStmt a).getTest() + } + + private string assertThrowTag() { result = "[assert-throw]" } + + /** + * Holds if the expression node `e` may raise an exception at runtime as part of + * its normal evaluation (not via an explicit `raise`/`assert`, which are + * modeled separately). + * + * The set mirrors what the legacy CFG used to flag implicitly: function + * calls (anything can raise), attribute access (`AttributeError`), + * subscript access (`IndexError`/`KeyError`/`TypeError`), arithmetic and + * comparison operators (`TypeError`/`ZeroDivisionError`), imports + * (`ImportError`/`ModuleNotFoundError`), and generator/coroutine + * suspension points (`await`/`yield`/`yield from`). + * + * Bare `Name` reads are intentionally excluded — modeling every name + * read as `mayThrow` would explode CFG edge count for negligible + * analysis value. `BoolExpr`/`IfExp` containers are also excluded; the + * operands they evaluate contribute their own exception edges. + */ + private predicate exprMayThrow(Py::Expr e) { + e instanceof Py::Call + or + e instanceof Py::Attribute + or + e instanceof Py::Subscript + or + e instanceof Py::BinaryExpr + or + e instanceof Py::UnaryExpr + or + e instanceof Py::Compare + or + e instanceof Py::ImportExpr + or + e instanceof Py::ImportMember + or + e instanceof Py::Await + or + e instanceof Py::Yield + or + e instanceof Py::YieldFrom + } + + /** + * Holds if the statement `s` may raise an exception at runtime as part + * of its normal evaluation. Currently restricted to `from m import *` + * (which performs the import as a statement-level side effect). + */ + private predicate stmtMayThrow(Py::Stmt s) { s instanceof Py::ImportStar } + + /** + * Holds if `py` is syntactically inside the body, handlers, `else`, or + * `finally` of a `try` statement (or the body of a `with` statement, + * which compiles to an implicit try/finally for `__exit__`) in the + * same scope. + * + * This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits + * exception edges when there is local exception handling that would + * observe them. Outside such contexts, exception edges would add CFG + * complexity (weakening BarrierGuard precision and breaking SSA + * continuity around augmented assignments and subscript stores) + * without any analysis benefit, since exceptions just propagate to + * the function exit anyway. + */ + private predicate inExceptionContext(Py::AstNode py) { + exists(Py::Try t | t.containsInScope(py)) + or + exists(Py::With w | w.containsInScope(py)) + } + + /** + * Holds if `n` may raise an exception during normal evaluation. See + * `exprMayThrow` and `stmtMayThrow` for the included AST classes. + * + * Restricted to nodes inside a `try`/`with` statement: matches Java's + * approach of only modeling exception flow where it can be observed + * by local handling. + */ + private predicate mayThrow(Ast::AstNode n) { + exists(Py::AstNode py | py = n.asExpr() or py = n.asStmt() | + (exprMayThrow(py) or stmtMayThrow(py)) and + inExceptionContext(py) + ) + } + + predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) { + n instanceof Ast::AssertStmt and tag = assertThrowTag() and t instanceof DirectSuccessor + } + + predicate beginAbruptCompletion( + Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always + ) { + ast instanceof Ast::AssertStmt and + n.isAdditional(ast, assertThrowTag()) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = true + or + mayThrow(ast) and + n.isIn(ast) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = false + } + + predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) { + none() + } + + predicate step(PreControlFlowNode n1, PreControlFlowNode n2) { + exists(Ast::AssertStmt assertStmt | + n1.isBefore(assertStmt) and + n2.isBefore(assertStmt.getTest()) + or + n1.isAfterTrue(assertStmt.getTest()) and + n2.isAfter(assertStmt) + or + n1.isAfterFalse(assertStmt.getTest()) and + ( + n2.isBefore(assertStmt.getMsg()) + or + not exists(assertStmt.getMsg()) and + n2.isAdditional(assertStmt, assertThrowTag()) + ) + or + n1.isAfter(assertStmt.getMsg()) and + n2.isAdditional(assertStmt, assertThrowTag()) + ) + } +} + +import Public + +/** + * Maps a CFG AST wrapper node to the corresponding Python AST node, if any. + * Entry, exit, and synthetic nodes have no corresponding Python AST node. + */ +Py::AstNode astNodeToPyNode(Ast::AstNode n) { + result = n.asExpr() + or + result = n.asStmt() + or + result = n.asScope() + or + result = n.asPattern() +} diff --git a/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll new file mode 100644 index 000000000000..3441ad0203c1 --- /dev/null +++ b/python/ql/lib/semmle/python/controlflow/internal/Cfg.qll @@ -0,0 +1,926 @@ +/** + * Provides a Python control flow graph facade backed by the shared + * `codeql.controlflow.ControlFlowGraph` library (via `AstNodeImpl.qll`). + * + * This module re-exposes the same API surface as `semmle/python/Flow.qll` + * (the legacy CFG), but is implemented on the new shared CFG. It is + * intended as a drop-in replacement for use by the Python dataflow library + * and other downstream code. + * + * Layering follows the Java pattern (`java/ql/lib/semmle/code/java/Expr.qll` + * and `SsaImpl.qll`): variable identity and similar AST-level semantics + * live on the Python AST classes (`Name.defines(v)`, `Name.uses(v)`, ...); + * the CFG layer is purely positional, with `toAst` / `getNode` bridging + * back to the AST. The shared SSA library can then be parameterized on + * (`BasicBlock`, `int`) directly, with no CFG-level variable predicates. + */ +overlay[local?] +module; + +private import python as Py +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType + +/** + * A control flow node. + * + * This is the full set of CFG nodes from the shared library — it includes + * before-nodes, in-order/post-order nodes, after-value-split nodes, and + * entry/exit nodes. This enables full control-flow-level reasoning and + * compatibility with the shared control-flow reachability library. + * + * AST-level semantics (`getNode()`, `isLoad()`, typed wrappers, etc.) + * are available only on the `injects` (canonical) node for each AST node. + * Non-injects nodes are purely positional CFG nodes with no AST mapping. + */ +class ControlFlowNode extends CfgImpl::ControlFlowNode { + /** Gets the syntactic element corresponding to this flow node, if any. */ + Py::AstNode getNode() { + exists(CfgImpl::Ast::AstNode n | this.injects(n) | result = CfgImpl::astNodeToPyNode(n)) + } + + Py::Expr asPyExpr() { result = this.getNode() } + + /** Gets a predecessor of this flow node. */ + ControlFlowNode getAPredecessor() { this = result.getASuccessor() } + + /** Gets a successor of this flow node. */ + ControlFlowNode getASuccessor() { result = super.getASuccessor() } + + /** Gets a successor for this node if the relevant condition is True. */ + ControlFlowNode getATrueSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = true)) + } + + /** Gets a successor for this node if the relevant condition is False. */ + ControlFlowNode getAFalseSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = false)) + } + + /** Gets a successor for this node if an exception is raised. */ + ControlFlowNode getAnExceptionalSuccessor() { result = super.getAnExceptionSuccessor() } + + /** Gets a successor for this node if no exception is raised. */ + ControlFlowNode getANormalSuccessor() { result = super.getANormalSuccessor() } + + /** Gets the basic block containing this flow node. */ + BasicBlock getBasicBlock() { result = super.getBasicBlock() } + + /** Gets the scope containing this flow node. */ + Py::Scope getScope() { result = super.getEnclosingCallable().asScope() } + + /** Gets the enclosing module. */ + Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() } + + /** Gets the immediate dominator of this flow node. */ + ControlFlowNode getImmediateDominator() { + // Defined positionally via the basic-block dominance tree. + exists(BasicBlock bb, int i | bb.getNode(i) = this | + // Predecessor within the same basic block. + i > 0 and result = bb.getNode(i - 1) + or + // First node of `bb`: dominator is the last node of the immediate dominator block. + i = 0 and result = bb.getImmediateDominator().getLastNode() + ) + } + + /** Holds if this strictly dominates `other`. */ + overlay[caller?] + pragma[inline] + predicate strictlyDominates(ControlFlowNode other) { super.strictlyDominates(other) } + + /** Holds if this dominates `other` (reflexively). */ + overlay[caller?] + pragma[inline] + predicate dominates(ControlFlowNode other) { super.dominates(other) } + + /** Holds if this is the first node in its enclosing scope. */ + predicate isEntryNode() { this instanceof CfgImpl::ControlFlow::EntryNode } + + /** Holds if this is the first node of a module. */ + predicate isModuleEntry() { + this.isEntryNode() and super.getAstNode().asScope() instanceof Py::Module + } + + /** Holds if this node may exit its scope by raising an exception. */ + predicate isExceptionalExit(Py::Scope s) { + this instanceof CfgImpl::ControlFlow::ExceptionalExitNode and + super.getEnclosingCallable().asScope() = s + } + + /** Holds if this node is a normal (non-exceptional) exit. */ + predicate isNormalExit() { this instanceof CfgImpl::ControlFlow::NormalExitNode } + + // ===== AST-shape predicates (bridges to the wrapped Python AST) ===== + /** + * Holds if this flow node is a load (including those in augmented + * assignments). + * + * Note: an augmented-assignment target (`x[i]` in `x[i] += 1`) is + * both a load and a store — `isLoad` and `isStore` both hold on the + * canonical CFG node. This mirrors Java's `VarAccess.isVarRead`, + * which holds on the destination of compound and unary assignments + * even though the destination is also a write. + */ + predicate isLoad() { py_expr_contexts(_, 3, this.asPyExpr()) } + + /** Holds if this flow node is a store (including those in augmented assignments). */ + predicate isStore() { py_expr_contexts(_, 5, this.asPyExpr()) or augstore(_, this) } + + /** Holds if this flow node is a delete. */ + predicate isDelete() { py_expr_contexts(_, 2, this.asPyExpr()) } + + /** Holds if this flow node is a parameter. */ + predicate isParameter() { py_expr_contexts(_, 4, this.asPyExpr()) } + + /** Holds if this flow node is a store in an augmented assignment. */ + predicate isAugStore() { augstore(_, this) } + + /** Holds if this flow node is a load in an augmented assignment. */ + predicate isAugLoad() { augstore(this, _) } + + /** Holds if this flow node corresponds to a literal. */ + predicate isLiteral() { + this.getNode() instanceof Py::Bytes or + this.getNode() instanceof Py::Dict or + this.getNode() instanceof Py::DictComp or + this.getNode() instanceof Py::Set or + this.getNode() instanceof Py::SetComp or + this.getNode() instanceof Py::Ellipsis or + this.getNode() instanceof Py::GeneratorExp or + this.getNode() instanceof Py::Lambda or + this.getNode() instanceof Py::ListComp or + this.getNode() instanceof Py::List or + this.getNode() instanceof Py::Num or + this.getNode() instanceof Py::Tuple or + this.getNode() instanceof Py::Unicode or + this.getNode() instanceof Py::NameConstant + } + + /** Holds if this flow node corresponds to an attribute expression. */ + predicate isAttribute() { this.getNode() instanceof Py::Attribute } + + /** Holds if this flow node corresponds to a subscript expression. */ + predicate isSubscript() { this.getNode() instanceof Py::Subscript } + + /** Holds if this flow node corresponds to an import member. */ + predicate isImportMember() { this.getNode() instanceof Py::ImportMember } + + /** Holds if this flow node corresponds to a call. */ + predicate isCall() { this.getNode() instanceof Py::Call } + + /** Holds if this flow node corresponds to an import. */ + predicate isImport() { this.getNode() instanceof Py::ImportExpr } + + /** Holds if this flow node corresponds to a conditional expression. */ + predicate isIfExp() { this.getNode() instanceof Py::IfExp } + + /** Holds if this flow node corresponds to a function definition expression. */ + predicate isFunction() { this.getNode() instanceof Py::FunctionExpr } + + /** Holds if this flow node corresponds to a class definition expression. */ + predicate isClass() { this.getNode() instanceof Py::ClassExpr } + + /** + * Holds if this flow node is a branch (i.e. has both a true and a + * false successor). + */ + predicate isBranch() { exists(this.getATrueSuccessor()) or exists(this.getAFalseSuccessor()) } + + /** + * Gets a CFG child of this node, defined as a CFG node whose AST node + * is a child of this CFG node's AST node, restricted to nodes that + * dominate this one (so the child has been evaluated by the time we + * reach this node). + * + * Mirrors `Flow.qll`'s `getAChild`. UnaryExprNode is excluded because + * its operand is its CFG predecessor (handled separately). + */ + pragma[nomagic] + ControlFlowNode getAChild() { + this.getNode().(Py::Expr).getAChildNode() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) and + not this instanceof UnaryExprNode + } + + /** Holds if this flow node strictly reaches `other`. */ + predicate strictlyReaches(ControlFlowNode other) { this.getASuccessor+() = other } +} + +/** + * Holds if `load` is the load half of an augmented-assignment target, + * and `store` is the corresponding store half. + * + * In the legacy CFG (`Flow.qll`) the same Python `Name` had two + * distinct CFG nodes — a load node (context 3) earlier in the BB, and + * a store node (context 5) later. The legacy `augstore` related the + * pair via dominance. + * + * In the new (shared) CFG, the canonical node for an AST expression is + * unique, so `load` and `store` collapse onto the same CFG node. The + * predicate is therefore reflexive on the augmented-assignment + * target's canonical node. + */ +private predicate augstore(ControlFlowNode load, ControlFlowNode store) { + exists(Py::AugAssign aa | aa.getTarget() = load.getNode()) and + load = store +} + +/** + * A basic block — a maximal-length sequence of control flow nodes such + * that no node except the first has a predecessor outside the sequence, + * and no node except the last has a successor outside the sequence. + */ +class BasicBlock extends CfgImpl::BasicBlock { + /** Gets the `n`th node in this basic block. */ + ControlFlowNode getNode(int n) { result = super.getNode(n) } + + /** Gets a node in this basic block. */ + ControlFlowNode getANode() { result = super.getNode(_) } + + /** Gets the first node in this basic block. */ + ControlFlowNode firstNode() { result = this.getNode(0) } + + /** Gets the last node in this basic block. */ + ControlFlowNode getLastNode() { result = super.getLastNode() } + + /** Holds if this basic block contains `node`. */ + predicate contains(ControlFlowNode node) { node = this.getANode() } + + // Inherited from the shared library's `BasicBlock`: + // getASuccessor(), getASuccessor(SuccessorType), getAPredecessor(), + // strictlyDominates(), dominates(), getImmediateDominator(), + // length(), inLoop(). + // We shadow `getNode(int)` etc. to return `ControlFlowNode` (this + // facade's type) and add Python-style helpers below. + /** Gets a true successor to this basic block. */ + BasicBlock getATrueSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = true)) + } + + /** Gets a false successor to this basic block. */ + BasicBlock getAFalseSuccessor() { + result = super.getASuccessor(any(BooleanSuccessor t | t.getValue() = false)) + } + + /** Gets an unconditional successor to this basic block. */ + BasicBlock getAnUnconditionalSuccessor() { + result = super.getASuccessor() and + not result = this.getATrueSuccessor() and + not result = this.getAFalseSuccessor() + } + + /** Gets an exceptional successor to this basic block. */ + BasicBlock getAnExceptionalSuccessor() { result = super.getASuccessor(any(ExceptionSuccessor t)) } + + /** + * Holds if this basic block is in the dominance frontier of `df`. + * + * Note: implemented locally rather than via the shared lib, which + * doesn't currently expose a `dominanceFrontier` predicate at this + * level. + */ + predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) } + + /** Holds if this basic block strictly reaches `other`. */ + predicate strictlyReaches(BasicBlock other) { super.getASuccessor+() = other } + + /** Holds if this basic block reaches `other` (reflexively). */ + predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) } + + /** Holds if flow from this basic block reaches a normal exit from its scope. */ + predicate reachesExit() { + this.getANode() instanceof CfgImpl::ControlFlow::NormalExitNode + or + exists(BasicBlock succ | succ = super.getASuccessor() and succ.reachesExit()) + } + + /** Gets the scope of this basic block. */ + Py::Scope getScope() { exists(ControlFlowNode n | n = this.getANode() | result = n.getScope()) } + + /** Holds if flow from this BasicBlock always reaches `succ`. */ + predicate alwaysReaches(BasicBlock succ) { + succ = this + or + strictcount(BasicBlock s | s = super.getASuccessor()) = 1 and + succ = super.getASuccessor() + or + forex(BasicBlock immsucc | immsucc = super.getASuccessor() | immsucc.alwaysReaches(succ)) + } + + /** + * Holds if this basic block ends in a node that branches on a boolean + * outcome, and `other` is dominated by the corresponding successor + * for `branch` while not being reachable from the other branch + * without going through this BB. + * + * In other words: any execution that reaches `other` must have just + * evaluated the last node of this BB and taken the `branch` outcome. + * This mirrors the legacy `ConditionBlock.controls(BB, branch)`. + */ + predicate controls(BasicBlock other, boolean branch) { + super.edgeDominates(other, any(BooleanSuccessor t | t.getValue() = branch)) + } +} + +// =========================================================================== +// Re-exports for SSA / dominance consumers +// +// The shared `BB::CfgSig` requires `EntryBasicBlock` and `dominatingEdge` in +// addition to the BasicBlock class we already expose. They are provided by +// the shared CFG library on the `BB::Make` instantiation produced by +// `AstNodeImpl.qll`. +// =========================================================================== +/** An entry basic block, that is, a basic block whose first node is an entry node. */ +class EntryBasicBlock = CfgImpl::Cfg::EntryBasicBlock; + +/** + * Holds if `bb1` has `bb2` as a direct successor and the edge between `bb1` + * and `bb2` is a dominating edge. + */ +predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; + +// =========================================================================== +// AST-shape subclasses of ControlFlowNode +// +// Each class is a thin wrapper around the canonical CFG node for a given +// kind of Python AST node. Methods that take/return CFG nodes look up +// related CFG nodes by AST identity (via `getNode()`), and the dominance +// constraint from the old CFG (`result.getBasicBlock().dominates(this.getBasicBlock())`) +// is preserved. +// =========================================================================== +/** Gets the canonical `ControlFlowNode` for AST expression `e`. */ +ControlFlowNode astExprToCfg(Py::Expr e) { result.getNode() = e } + +/** A control flow node corresponding to a `Name` or `PlaceHolder` expression. */ +class NameNode extends ControlFlowNode { + NameNode() { + this.getNode() instanceof Py::Name + or + this.getNode() instanceof Py::PlaceHolder + } + + /** + * Holds if this flow node defines the variable `v`. + * + * This includes augmented-assignment targets — `n += 1` is both a + * read and a write of `n`, so `defines(n)` and `uses(n)` both hold + * on the same canonical CFG node. Mirrors Java's `VariableUpdate` + * semantics where compound assignments register both a write + * (`VarWrite`) and a read (`VarRead`) on the destination. + */ + predicate defines(Py::Variable v) { exists(Py::Name n | n = this.getNode() and n.defines(v)) } + + /** Holds if this flow node deletes the variable `v`. */ + predicate deletes(Py::Variable v) { exists(Py::Name n | n = this.getNode() and n.deletes(v)) } + + /** Holds if this flow node uses the variable `v`. */ + predicate uses(Py::Variable v) { + this.isLoad() and + exists(Py::Name u | u = this.getNode() and u.uses(v)) + or + exists(Py::PlaceHolder u | + u = this.getNode() and u.getVariable() = v and u.getCtx() instanceof Py::Load + ) + } + + /** Gets the identifier of this name node. */ + string getId() { + result = this.getNode().(Py::Name).getId() + or + result = this.getNode().(Py::PlaceHolder).getId() + } + + /** Holds if this is a use of a local variable. */ + predicate isLocal() { exists(Py::Variable v | this.uses(v) and v instanceof Py::LocalVariable) } + + /** Holds if this is a use of a non-local variable. */ + predicate isNonLocal() { + exists(Py::Variable v | this.uses(v) and v.getScope() != this.getScope()) + } + + /** Holds if this is a use of a global (including builtin) variable. */ + predicate isGlobal() { exists(Py::Variable v | this.uses(v) and v instanceof Py::GlobalVariable) } + + /** + * Holds if this is a use of `self` — the first parameter of an + * enclosing method. + * + * AST-level approximation: matches when the Name uses a `Variable` + * that is the first parameter of an enclosing `Function` defined + * inside a `Class`. + */ + predicate isSelf() { + exists(Py::Variable v, Py::Function f, Py::Class c | + this.uses(v) and + f = c.getAMethod() and + v.getScope() = f and + v = f.getArg(0).(Py::Name).getVariable() + ) + } +} + +/** A control flow node corresponding to a named constant (`None`, `True`, `False`). */ +class NameConstantNode extends NameNode { + NameConstantNode() { this.getNode() instanceof Py::NameConstant } +} + +/** A control flow node corresponding to a call. */ +class CallNode extends ControlFlowNode { + CallNode() { super.getNode() instanceof Py::Call } + + override Py::Call getNode() { result = super.getNode() } + + /** Gets the underlying Python `Call`. */ + Py::Call getCall() { result = this.getNode() } + + /** Gets the flow node for the function component of this call. */ + ControlFlowNode getFunction() { + this.getCall().getFunc() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Gets the flow node for the `n`th positional argument. */ + ControlFlowNode getArg(int n) { + this.getCall().getArg(n) = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Gets the flow node for the named argument with name `name`. */ + ControlFlowNode getArgByName(string name) { + exists(Py::Keyword k | + k = this.getCall().getANamedArg() and + k.getValue() = result.getNode() and + k.getArg() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets a flow node corresponding to any argument. */ + ControlFlowNode getAnArg() { result = this.getArg(_) or result = this.getArgByName(_) } + + /** Gets the first tuple (`*args`) argument, if any. */ + ControlFlowNode getStarArg() { + this.getCall().getStarArg() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Gets a dictionary (`**kwargs`) argument, if any. */ + ControlFlowNode getKwargs() { + this.getCall().getKwargs() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Holds if this call is a decorator call applied to a class or a function. */ + predicate isDecoratorCall() { this.isClassDecoratorCall() or this.isFunctionDecoratorCall() } + + /** Holds if this call is a decorator call applied to a class. */ + predicate isClassDecoratorCall() { + exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall()) + } + + /** Holds if this call is a decorator call applied to a function. */ + predicate isFunctionDecoratorCall() { + exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall()) + } +} + +/** A control flow node corresponding to an attribute expression. */ +class AttrNode extends ControlFlowNode { + AttrNode() { super.getNode() instanceof Py::Attribute } + + override Py::Attribute getNode() { result = super.getNode() } + + /** Gets the flow node for the object of the attribute expression. */ + ControlFlowNode getObject() { + this.getNode().getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Gets the flow node for the object of this attribute expression, with the matching name. */ + ControlFlowNode getObject(string name) { + this.getName() = name and + result = this.getObject() + } + + /** Gets the attribute name. */ + string getName() { result = this.getNode().getName() } +} + +/** A control flow node corresponding to an import statement (`import x`). */ +class ImportExprNode extends ControlFlowNode { + ImportExprNode() { super.getNode() instanceof Py::ImportExpr } + + override Py::ImportExpr getNode() { result = super.getNode() } +} + +/** A control flow node corresponding to a `from ... import name` expression. */ +class ImportMemberNode extends ControlFlowNode { + ImportMemberNode() { super.getNode() instanceof Py::ImportMember } + + override Py::ImportMember getNode() { result = super.getNode() } + + /** Gets the flow node for the module being imported from, with the matching name. */ + ControlFlowNode getModule(string name) { + exists(Py::ImportMember i | + i = this.getNode() and + i.getModule() = result.getNode() and + i.getName() = name and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a `from ... import *` statement. */ +class ImportStarNode extends ControlFlowNode { + ImportStarNode() { super.getNode() instanceof Py::ImportStar } + + override Py::ImportStar getNode() { result = super.getNode() } + + /** Gets the flow node for the module being imported from. */ + ControlFlowNode getModule() { + this.getNode().getModuleExpr() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a subscript expression. */ +class SubscriptNode extends ControlFlowNode { + SubscriptNode() { super.getNode() instanceof Py::Subscript } + + override Py::Subscript getNode() { result = super.getNode() } + + /** Gets the flow node for the value being subscripted. */ + ControlFlowNode getObject() { + this.getNode().getObject() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Gets the flow node for the index expression. */ + ControlFlowNode getIndex() { + this.getNode().getIndex() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a comparison operation. */ +class CompareNode extends ControlFlowNode { + CompareNode() { super.getNode() instanceof Py::Compare } + + override Py::Compare getNode() { result = super.getNode() } + + /** Holds if `left` and `right` are a pair of operands for this comparison. */ + predicate operands(ControlFlowNode left, Py::Cmpop op, ControlFlowNode right) { + exists(Py::Compare c, Py::Expr eleft, Py::Expr eright | + c = this.getNode() and eleft = left.getNode() and eright = right.getNode() + | + eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0) + or + exists(int i | + eleft = c.getComparator(i - 1) and eright = c.getComparator(i) and op = c.getOp(i) + ) + ) and + left.getBasicBlock().dominates(this.getBasicBlock()) and + right.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a conditional expression (`x if c else y`). */ +class IfExprNode extends ControlFlowNode { + IfExprNode() { super.getNode() instanceof Py::IfExp } + + override Py::IfExp getNode() { result = super.getNode() } + + /** Gets the flow node for one of the value operands (true-branch or false-branch). */ + ControlFlowNode getAnOperand() { + exists(Py::IfExp ie | + ie = this.getNode() and + (result.getNode() = ie.getBody() or result.getNode() = ie.getOrelse()) + ) + } +} + +/** A control flow node corresponding to an assignment expression (walrus `:=`). */ +class AssignmentExprNode extends ControlFlowNode { + AssignmentExprNode() { super.getNode() instanceof Py::AssignExpr } + + override Py::AssignExpr getNode() { result = super.getNode() } + + /** Gets the flow node for the left-hand side. */ + ControlFlowNode getTarget() { + this.getNode().getTarget() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + /** Gets the flow node for the right-hand side. */ + ControlFlowNode getValue() { + this.getNode().getValue() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a binary expression (`a + b` etc.). */ +class BinaryExprNode extends ControlFlowNode { + BinaryExprNode() { super.getNode() instanceof Py::BinaryExpr } + + override Py::BinaryExpr getNode() { result = super.getNode() } + + ControlFlowNode getLeft() { + this.getNode().getLeft() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + ControlFlowNode getRight() { + this.getNode().getRight() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + Py::Operator getOp() { result = this.getNode().(Py::BinaryExpr).getOp() } + + /** Holds if `left` and `right` are the operands and `op` is the operator. */ + predicate operands(ControlFlowNode left, Py::Operator op, ControlFlowNode right) { + left = this.getLeft() and right = this.getRight() and op = this.getOp() + } + + /** Gets either operand. */ + ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() } +} + +/** A control flow node corresponding to a boolean expression (`a and b`, `a or b`). */ +class BoolExprNode extends ControlFlowNode { + BoolExprNode() { super.getNode() instanceof Py::BoolExpr } + + override Py::BoolExpr getNode() { result = super.getNode() } + + Py::Boolop getOp() { result = this.getNode().(Py::BoolExpr).getOp() } + + /** Gets any operand of this boolean expression. */ + ControlFlowNode getAnOperand() { this.getNode().getAValue() = result.getNode() } +} + +/** A control flow node corresponding to a unary expression (`-x`, `not x`, etc.). */ +class UnaryExprNode extends ControlFlowNode { + UnaryExprNode() { super.getNode() instanceof Py::UnaryExpr } + + override Py::UnaryExpr getNode() { result = super.getNode() } + + ControlFlowNode getOperand() { + this.getNode().getOperand() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } + + Py::Unaryop getOp() { result = this.getNode().(Py::UnaryExpr).getOp() } +} + +/** + * A control flow node that is a definition: it appears in a context that + * binds a variable (assignment target, parameter, etc.). + */ +class DefinitionNode extends ControlFlowNode { + DefinitionNode() { this.isStore() or this.isParameter() } + + /** Gets the value assigned, if any. */ + ControlFlowNode getValue() { + // For-target: the value is the for-loop's iter expression (which + // is also where `Cfg::ForNode` lives — its `getNode()` returns the + // enclosing `Py::For` statement). Treated specially because there + // is no AST node holding the result of `iter(next(seq))`; we use + // the iter expression's CFG node as the stand-in. + exists(Py::For f | + f.getTarget() = this.getNode() and + result.getNode() = f.getIter() + ) + or + exists(Py::AstNode value | value = assignedValue(this.getNode()) | + result.getNode() = value and + ( + result.getBasicBlock().dominates(this.getBasicBlock()) + or + result.isImport() + or + // The default value for a parameter is evaluated in the same basic block as + // the function definition, but the parameter belongs to the basic block of the + // function, so there is no dominance relationship between the two. + exists(Py::Parameter param | this.getNode() = param.asName()) + ) + ) + } +} + +/** + * Gets the AST node that holds the value assigned to `lhs` in a binding + * context. Mirrors `Flow.qll::assigned_value`. + */ +private Py::AstNode assignedValue(Py::Expr lhs) { + // lhs = result + exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue()) + or + // lhs := result + exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue()) + or + // lhs: annotation = result + exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + or + // import result as lhs (also covers plain `import lhs`, where alias.getAsname() = lhs) + exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue()) + or + // lhs += x -> result is the (lhs + x) binary expression + exists(Py::AugAssign a, Py::BinaryExpr b | + b = a.getOperation() and result = b and lhs = b.getLeft() + ) + or + // Nested sequence assign: ..., lhs, ... = ..., result, ... + exists(Py::Assign a | nestedSequenceAssign(a.getATarget(), a.getValue(), lhs, result)) + or + // Parameter default + exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault()) +} + +/** + * Helper for nested sequence assignments such as `(a, b), c = (1, 2), 3`. + */ +private predicate nestedSequenceAssign( + Py::Expr leftParent, Py::Expr rightParent, Py::Expr left, Py::Expr right +) { + exists(int i | + leftParent.(Py::Tuple).getElt(i) = left and rightParent.(Py::Tuple).getElt(i) = right + or + leftParent.(Py::List).getElt(i) = left and rightParent.(Py::List).getElt(i) = right + ) + or + exists(Py::Expr leftMid, Py::Expr rightMid | + nestedSequenceAssign(leftParent, rightParent, leftMid, rightMid) and + nestedSequenceAssign(leftMid, rightMid, left, right) + ) +} + +/** A control flow node corresponding to a deletion (`del x`). */ +class DeletionNode extends ControlFlowNode { + DeletionNode() { this.isDelete() } +} + +/** A control flow node corresponding to a `for` loop target. */ +class ForNode extends ControlFlowNode { + ForNode() { exists(Py::For f | this.getNode() = f.getIter()) } + + /** Gets the iterable expression. */ + ControlFlowNode getIter() { + result = this and result = result // canonical "after" of the iterable + } + + /** Gets the sequence expression (alias for `getIter()`, matches legacy Flow naming). */ + ControlFlowNode getSequence() { result = this.getIter() } + + /** Gets the target (loop variable) of the `for` loop. */ + ControlFlowNode getTarget() { + exists(Py::For f | + f.getIter() = this.getNode() and + f.getTarget() = result.getNode() + ) + } + + /** Holds if `target` is the loop variable and `sequence` is the iterable. */ + predicate iterates(ControlFlowNode target, ControlFlowNode sequence) { + target = this.getTarget() and sequence = this.getSequence() + } +} + +/** A control flow node corresponding to a `raise` statement. */ +class RaiseStmtNode extends ControlFlowNode { + RaiseStmtNode() { super.getNode() instanceof Py::Raise } + + override Py::Raise getNode() { result = super.getNode() } + + /** Gets the exception expression, if any. */ + ControlFlowNode getException() { + this.getNode().getException() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } +} + +/** A control flow node corresponding to a starred expression (`*x`). */ +class StarredNode extends ControlFlowNode { + StarredNode() { this.getNode() instanceof Py::Starred } + + /** Gets the value being starred. */ + ControlFlowNode getValue() { + exists(Py::Starred s | + s = this.getNode() and + s.getValue() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an `except` clause's name binding. */ +class ExceptFlowNode extends ControlFlowNode { + ExceptFlowNode() { exists(Py::ExceptStmt e | this.getNode() = e.getName()) } + + /** Gets the CFG node for the bound `as`-name itself. */ + ControlFlowNode getName() { result = this } + + /** Gets the type expression of this exception handler. */ + ControlFlowNode getType() { + exists(Py::ExceptStmt e | + e.getName() = this.getNode() and + e.getType() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an `except*` clause's name binding. */ +class ExceptGroupFlowNode extends ControlFlowNode { + ExceptGroupFlowNode() { exists(Py::ExceptGroupStmt e | this.getNode() = e.getName()) } + + /** Gets the CFG node for the bound `as`-name itself. */ + ControlFlowNode getName() { result = this } +} + +/** A control flow node corresponding to a sequence (tuple, list). */ +abstract class SequenceNode extends ControlFlowNode { + /** Gets the `n`th element of this sequence. */ + abstract ControlFlowNode getElement(int n); + + /** Gets any element of this sequence. */ + ControlFlowNode getAnElement() { result = this.getElement(_) } +} + +/** A control flow node corresponding to a tuple literal. */ +class TupleNode extends SequenceNode { + TupleNode() { this.getNode() instanceof Py::Tuple } + + override ControlFlowNode getElement(int n) { + exists(Py::Tuple t | + t = this.getNode() and + t.getElt(n) = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a list literal. */ +class ListNode extends SequenceNode { + ListNode() { this.getNode() instanceof Py::List } + + override ControlFlowNode getElement(int n) { + exists(Py::List l | + l = this.getNode() and + l.getElt(n) = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a set literal. */ +class SetNode extends ControlFlowNode { + SetNode() { this.getNode() instanceof Py::Set } + + /** Gets the flow node for an element of the set. */ + ControlFlowNode getAnElement() { + exists(Py::Set s | + s = this.getNode() and + s.getAnElt() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to a dict literal. */ +class DictNode extends ControlFlowNode { + DictNode() { this.getNode() instanceof Py::Dict } + + /** Gets the flow node for a key of the dict. */ + ControlFlowNode getAKey() { + exists(Py::Dict d | + d = this.getNode() and + d.getAKey() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } + + /** Gets the flow node for a value of the dict. */ + ControlFlowNode getAValue() { + exists(Py::Dict d | + d = this.getNode() and + d.getAValue() = result.getNode() and + result.getBasicBlock().dominates(this.getBasicBlock()) + ) + } +} + +/** A control flow node corresponding to an iterable in a `for` loop. */ +class IterableNode extends ControlFlowNode { + IterableNode() { + this instanceof SequenceNode + or + this instanceof SetNode + } + + /** Gets the control flow node for an element of this iterable. */ + ControlFlowNode getAnElement() { + result = this.(SequenceNode).getAnElement() + or + result = this.(SetNode).getAnElement() + } +} diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll index 7000e4a77f4d..684df9563674 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll @@ -20,6 +20,8 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _) } +private predicate localFlowStepPlus(Node node1, Node node2) = fastTC(localFlowStep/2)(node1, node2) + /** * Holds if data flows from `source` to `sink` in one or more local * (intra-procedural) steps. @@ -32,7 +34,4 @@ private predicate localFlowPlus(Node source, Node sink) = fastTC(localFlowStep/2 * (intra-procedural) steps. */ pragma[inline] -predicate localFlow(Node source, Node sink) { - localFlowPlus(source, sink) or - source = sink -} \ No newline at end of file +predicate localFlow(Node source, Node sink) { source = sink or localFlowStepPlus(source, sink) } diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index 154686ec4aa9..97904c1bd7af 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.8.8 + +No user-facing changes. + ## 1.8.7 No user-facing changes. diff --git a/python/ql/src/change-notes/released/1.8.8.md b/python/ql/src/change-notes/released/1.8.8.md new file mode 100644 index 000000000000..fcbf14e0fd9b --- /dev/null +++ b/python/ql/src/change-notes/released/1.8.8.md @@ -0,0 +1,3 @@ +## 1.8.8 + +No user-facing changes. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index 353f6d821ebe..d224b6ac3595 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.8.7 +lastReleaseVersion: 1.8.8 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index c866e30b7e74..1aca14fd33ae 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 1.8.7 +version: 1.8.8 groups: - python - queries diff --git a/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected b/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected new file mode 100644 index 000000000000..91a01a3a3d93 --- /dev/null +++ b/python/ql/test/extractor-tests/syntax_error/CONSISTENCY/CfgConsistency.expected @@ -0,0 +1,4 @@ +consistencyOverview +| deadEnd | 1 | +deadEnd +| without_loop.py:7:5:7:9 | Break | diff --git a/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql new file mode 100644 index 000000000000..a507878911b1 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/BindingsTest.ql @@ -0,0 +1,32 @@ +/** + * Phase -1 of the dataflow CFG migration: verifies that every variable + * binding visible to the AST (`Name.defines(v)`) corresponds to a CFG node + * in the new CFG (`semmle.python.controlflow.internal.AstNodeImpl`). + * + * The expected tag is `cfgdefines=`. Each binding annotation in the + * test sources looks like `# $ cfgdefines=x` for a binding currently + * covered by the new CFG, or `# $ MISSING: cfgdefines=x` for a binding + * that is known to be uncovered (a "red" test case that should be + * green-flipped once the corresponding `cfg-ext-*` extension lands). + */ + +import python +import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +import utils.test.InlineExpectationsTest + +module CfgBindingsTest implements TestSig { + string getARelevantTag() { result = "cfgdefines" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Name n, Variable v, CfgImpl::ControlFlowNode cfg | + n.defines(v) and + cfg.getAstNode().asExpr() = n and + location = n.getLocation() and + element = n.toString() and + tag = "cfgdefines" and + value = v.getId() + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/bindings/annassign.py b/python/ql/test/library-tests/ControlFlow/bindings/annassign.py new file mode 100644 index 000000000000..7a9ae3ab6c79 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/annassign.py @@ -0,0 +1,13 @@ +# Annotated assignment (PEP 526). Both with and without an initializer. + +a: int = 1 # $ cfgdefines=a +b: str = "hi" # $ cfgdefines=b + +# Annotation without value: the AST records `c` as defined, +# and the new CFG now visits it via the AnnAssignStmt wrapper. +c: int # $ cfgdefines=c + +class K: # $ cfgdefines=K + field: int = 0 # $ cfgdefines=field + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/compound.py b/python/ql/test/library-tests/ControlFlow/bindings/compound.py new file mode 100644 index 000000000000..cb2f36f12ffe --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/compound.py @@ -0,0 +1,14 @@ +# Compound (tuple/list) assignment targets — actually wired in the new CFG. + +a, b = (1, 2) # $ cfgdefines=a cfgdefines=b +[c, d] = [3, 4] # $ cfgdefines=c cfgdefines=d + +# Nested unpacking. +(e, (f, g)) = (1, (2, 3)) # $ cfgdefines=e cfgdefines=f cfgdefines=g + +# Star unpacking. +h, *i = [1, 2, 3] # $ cfgdefines=h cfgdefines=i + +# Chained assignment with compound target. +j = k, l = (5, 6) # $ cfgdefines=j cfgdefines=k cfgdefines=l + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py b/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py new file mode 100644 index 000000000000..6b5f722c1f7e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/comprehension.py @@ -0,0 +1,21 @@ +# Comprehension and `for` loop targets — wired in the new CFG. +# Comprehensions are nested function scopes with a synthetic `.0` parameter +# bound to the iterable. + +# Bare-name `for` target. +for i in range(3): # $ cfgdefines=i + pass + +# Compound `for` target. +for k, v in [(1, 2)]: # $ cfgdefines=k cfgdefines=v + pass + +# Comprehension targets. +_ = [x for x in range(3)] # $ cfgdefines=_ cfgdefines=x cfgdefines=.0 +_ = {y: z for y, z in []} # $ cfgdefines=_ cfgdefines=y cfgdefines=z cfgdefines=.0 +_ = (a for a in []) # $ cfgdefines=_ cfgdefines=a cfgdefines=.0 + +# Nested comprehensions. +_ = [b for c in [] for b in c] # $ cfgdefines=_ cfgdefines=c cfgdefines=b cfgdefines=.0 + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py new file mode 100644 index 000000000000..9058f2b71165 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/dead_under_no_raise.py @@ -0,0 +1,53 @@ +# Reachability of code following a try whose body always returns. +# +# The new CFG models exception edges for raise-prone expressions when +# they appear inside a `try` (or `with`) statement, mirroring Java's +# `mayThrow`. This means the body of a `try` has both a normal +# completion edge and an exception edge to its handlers, so code +# following the try-statement is reachable via the except-handler path +# even when the try-body would otherwise always return. +# +# Code that is not reachable under either normal or exception flow +# (for example, the `else` clause of a try whose body unconditionally +# raises) remains correctly classified as dead. + + +def f(obj): # $ cfgdefines=f cfgdefines=obj + try: + return len(obj) + except TypeError: + pass + + # The try-body always returns, but `len(obj)` can raise (it is + # inside the try, so we model its exception edge). The + # `except TypeError: pass` handler falls through to here, making + # the code below reachable. + try: + hint = type(obj).__length_hint__ # $ cfgdefines=hint + except AttributeError: + return None + return hint + + +def g(): # $ cfgdefines=g + try: + raise Exception("inner") + except: + raise Exception("outer") + else: + # Unreachable: the inner try body always raises (via an explicit + # `raise`, which is modelled unconditionally), so the `else:` + # clause never runs. + hit_inner_else = True + + +def h(cache, key): # $ cfgdefines=h cfgdefines=cache cfgdefines=key + try: + return cache[key] + except KeyError: + pass + + # Same pattern as `f`: reachable via the except-handler fall-through. + value = compute(key) # $ cfgdefines=value + cache[key] = value + return value diff --git a/python/ql/test/library-tests/ControlFlow/bindings/decorated.py b/python/ql/test/library-tests/ControlFlow/bindings/decorated.py new file mode 100644 index 000000000000..9b93c166acec --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/decorated.py @@ -0,0 +1,30 @@ +# Decorated `def`/`class` — wired in the new CFG. + + +def deco(f): # $ cfgdefines=deco cfgdefines=f + return f + + +@deco +def decorated_func(): # $ cfgdefines=decorated_func + pass + + +@deco +class DecoratedClass: # $ cfgdefines=DecoratedClass + pass + + +# Stacked decorators. +@deco +@deco +def doubly(): # $ cfgdefines=doubly + pass + + +# Inside a class body. +class Outer: # $ cfgdefines=Outer + @staticmethod + def inner(): # $ cfgdefines=inner + pass + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py b/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py new file mode 100644 index 000000000000..57b6c99fe9b6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/except_handler.py @@ -0,0 +1,19 @@ +# Exception-handler name bindings. These are already wired in the new +# CFG provided the try body can raise; `raise` statements are reliably +# treated as exception sources. + +try: + raise ValueError("oops") +except ValueError as e: # $ cfgdefines=e + pass + +try: + raise TypeError("oops") +except (TypeError, KeyError) as err: # $ cfgdefines=err + pass + +# Exception groups (Python 3.11+). +try: + raise ValueError("oops") +except* ValueError as eg: # $ cfgdefines=eg + pass diff --git a/python/ql/test/library-tests/ControlFlow/bindings/imports.py b/python/ql/test/library-tests/ControlFlow/bindings/imports.py new file mode 100644 index 000000000000..c8834b5332a0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/imports.py @@ -0,0 +1,14 @@ +# Import aliases — all bound names below are now reachable via the new +# CFG's `ImportStmt` wrapper. + +import os # $ cfgdefines=os +import os.path # $ cfgdefines=os +import os as o # $ cfgdefines=o +from os import path # $ cfgdefines=path +from os import path as p # $ cfgdefines=p +from os import sep, linesep # $ cfgdefines=sep cfgdefines=linesep +from os import ( + getcwd, # $ cfgdefines=getcwd + getcwdb, # $ cfgdefines=getcwdb +) + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py b/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py new file mode 100644 index 000000000000..0868a2680d0a --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/match_pattern.py @@ -0,0 +1,24 @@ +# Match-statement pattern bindings — wired in the new CFG. + +def f(subject): # $ cfgdefines=f cfgdefines=subject + match subject: + case x: # $ cfgdefines=x + pass + case [a, b]: # $ cfgdefines=a cfgdefines=b + pass + case {"k": v}: # $ cfgdefines=v + pass + case Point(p, q): # $ cfgdefines=p cfgdefines=q + pass + case [_, *rest]: # $ cfgdefines=rest + pass + case (1 | 2) as n: # $ cfgdefines=n + pass + + +class Point: # $ cfgdefines=Point + __match_args__ = ("x", "y") # $ cfgdefines=__match_args__ + x: int # $ cfgdefines=x + y: int # $ cfgdefines=y + + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/parameters.py b/python/ql/test/library-tests/ControlFlow/bindings/parameters.py new file mode 100644 index 000000000000..7fe5e01e4c4b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/parameters.py @@ -0,0 +1,42 @@ +# Function parameters. + +def positional(a, b): # $ cfgdefines=positional cfgdefines=a cfgdefines=b + pass + + +def with_default(x=1, y=2): # $ cfgdefines=with_default cfgdefines=x cfgdefines=y + pass + + +def with_vararg(*args): # $ cfgdefines=with_vararg cfgdefines=args + pass + + +def with_kwarg(**kwargs): # $ cfgdefines=with_kwarg cfgdefines=kwargs + pass + + +def with_kwonly(*, k1, k2=5): # $ cfgdefines=with_kwonly cfgdefines=k1 cfgdefines=k2 + pass + + +def kitchen_sink(a, b=2, *args, k1, k2=5, **kw): # $ cfgdefines=kitchen_sink cfgdefines=a cfgdefines=b cfgdefines=args cfgdefines=k1 cfgdefines=k2 cfgdefines=kw + pass + + +# Methods get `self` / `cls`. +class C: # $ cfgdefines=C + def method(self, x): # $ cfgdefines=method cfgdefines=self cfgdefines=x + pass + + @classmethod + def cmethod(cls, x): # $ cfgdefines=cmethod cfgdefines=cls cfgdefines=x + pass + + +# Lambda parameter. +_ = lambda p: p + 1 # $ cfgdefines=_ cfgdefines=p + +# PEP 570 positional-only. +def pos_only(a, b, /, c): # $ cfgdefines=pos_only cfgdefines=a cfgdefines=b cfgdefines=c + pass diff --git a/python/ql/test/library-tests/ControlFlow/bindings/simple.py b/python/ql/test/library-tests/ControlFlow/bindings/simple.py new file mode 100644 index 000000000000..51cb7d828c91 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/simple.py @@ -0,0 +1,14 @@ +# Simple bindings that should already work in the new CFG. +# No MISSING annotations expected. + +x = 1 # $ cfgdefines=x +y = x + 1 # $ cfgdefines=y + +def f(): # $ cfgdefines=f + pass + +class C: # $ cfgdefines=C + pass + +# Re-assignment. +x = 2 # $ cfgdefines=x diff --git a/python/ql/test/library-tests/ControlFlow/bindings/starred.py b/python/ql/test/library-tests/ControlFlow/bindings/starred.py new file mode 100644 index 000000000000..ac38c74ef122 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/starred.py @@ -0,0 +1,4 @@ +# Starred-target edge cases — wired in the new CFG. + +# Starred target in a Tuple LHS. +*head, tail = [1, 2, 3] # $ cfgdefines=head cfgdefines=tail diff --git a/python/ql/test/library-tests/ControlFlow/bindings/type_params.py b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py new file mode 100644 index 000000000000..ae48ccf130b1 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/type_params.py @@ -0,0 +1,21 @@ +# PEP 695 type parameters (Python 3.12+). + +# PEP 695 type-param names on `def`/`class` bind in an annotation scope +# that nests the function/class body — they have no CFG node in the +# enclosing scope (matching the legacy CFG). +def func[T](x: T) -> T: # $ cfgdefines=func cfgdefines=x + return x + + +class Box[T]: # $ cfgdefines=Box + item: T # $ SPURIOUS: cfgdefines=item + + +# Multi-parameter, with bound and variadics. +def multi[T: int, *Ts, **P](x: T, *args: *Ts, **kwargs: P.kwargs) -> T: # $ cfgdefines=multi cfgdefines=x cfgdefines=args cfgdefines=kwargs + return x + + +# `type` statement (PEP 695). +type Alias[T] = list[T] # $ cfgdefines=Alias cfgdefines=T + diff --git a/python/ql/test/library-tests/ControlFlow/bindings/walrus.py b/python/ql/test/library-tests/ControlFlow/bindings/walrus.py new file mode 100644 index 000000000000..d370fd342dcd --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/walrus.py @@ -0,0 +1,9 @@ +# Walrus edge cases — wired in the new CFG. + +# Walrus in expression context. +if (y := 5) > 0: # $ cfgdefines=y + pass + +# Walrus in a comprehension. The comprehension introduces a synthetic +# `.0` parameter bound to the iterable. +_ = [w for _ in range(3) if (w := 1)] # $ cfgdefines=_ cfgdefines=w cfgdefines=.0 diff --git a/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py b/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py new file mode 100644 index 000000000000..5fffe46c5d40 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/bindings/with_stmt.py @@ -0,0 +1,21 @@ +# `with cm() as x:` bindings — wired in the new CFG. + +class CM: # $ cfgdefines=CM + def __enter__(self): return self # $ cfgdefines=__enter__ cfgdefines=self + def __exit__(self, *a): pass # $ cfgdefines=__exit__ cfgdefines=self cfgdefines=a + +with CM() as x: # $ cfgdefines=x + pass + +# Multiple items. +with CM() as a, CM() as b: # $ cfgdefines=a cfgdefines=b + pass + +# Parenthesised form (Python 3.10+). +with (CM() as p, CM() as q): # $ cfgdefines=p cfgdefines=q + pass + +# Compound target in `with`. +with CM() as (m, n): # $ cfgdefines=m cfgdefines=n + pass + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected new file mode 100644 index 000000000000..9dc286490613 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.expected @@ -0,0 +1,13 @@ +| test_boolean.py:9:10:9:43 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 1) | test_boolean.py:9:59:9:59 | IntegerLiteral | Timestamp 2 | test_boolean.py:7:1:7:27 | Function test_and_both_sides | test_and_both_sides | +| test_boolean.py:15:10:15:43 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 0) | test_boolean.py:15:50:15:50 | IntegerLiteral | Timestamp 1 | test_boolean.py:13:1:13:30 | Function test_and_short_circuit | test_and_short_circuit | +| test_boolean.py:21:10:21:42 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 0) | test_boolean.py:21:49:21:49 | IntegerLiteral | Timestamp 1 | test_boolean.py:19:1:19:29 | Function test_or_short_circuit | test_or_short_circuit | +| test_boolean.py:27:10:27:34 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 1) | test_boolean.py:27:50:27:50 | IntegerLiteral | Timestamp 2 | test_boolean.py:25:1:25:26 | Function test_or_both_sides | test_or_both_sides | +| test_boolean.py:40:10:40:61 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 2) | test_boolean.py:40:86:40:86 | IntegerLiteral | Timestamp 3 | test_boolean.py:38:1:38:24 | Function test_chained_and | test_chained_and | +| test_boolean.py:46:10:46:61 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 2) | test_boolean.py:46:86:46:86 | IntegerLiteral | Timestamp 3 | test_boolean.py:44:1:44:23 | Function test_chained_or | test_chained_or | +| test_boolean.py:52:10:52:95 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 3) | test_boolean.py:52:120:52:120 | IntegerLiteral | Timestamp 4 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_boolean.py:52:11:52:47 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 1) | test_boolean.py:52:63:52:63 | IntegerLiteral | Timestamp 2 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_boolean.py:52:78:52:79 | IntegerLiteral | $@ in $@ has no consecutive predecessor (expected 2) | test_boolean.py:52:85:52:85 | IntegerLiteral | Timestamp 3 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_comparison.py:37:6:37:41 | Compare | $@ in $@ has no consecutive predecessor (expected 1) | test_comparison.py:37:48:37:48 | IntegerLiteral | Timestamp 2 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | +| test_if.py:96:9:96:9 | x | $@ in $@ has no consecutive predecessor (expected 1) | test_if.py:96:15:96:15 | IntegerLiteral | Timestamp 2 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | +| test_if.py:96:9:96:29 | BoolExpr | $@ in $@ has no consecutive predecessor (expected 3) | test_if.py:96:36:96:36 | IntegerLiteral | Timestamp 4 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | +| test_if.py:99:13:99:13 | IntegerLiteral | $@ in $@ has no consecutive predecessor (expected 4) | test_if.py:99:19:99:19 | IntegerLiteral | Timestamp 5 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql new file mode 100644 index 000000000000..6d90605d685f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutivePredecessorTimestamps.ql @@ -0,0 +1,22 @@ +/** + * Checks that each annotated node (except the minimum timestamp) has a + * predecessor annotation with timestamp `a - 1`. This is the reverse of + * ConsecutiveTimestamps: it catches nodes that are reachable but arrived + * at from the wrong place (skipping an intermediate node). + * + * Only applies to functions where all annotations are in the function's + * own scope (excludes tests with generators, async, comprehensions, or + * lambdas that have annotations in nested scopes). + */ + +import OldCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutivePredecessorTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive predecessor (expected " + (a - 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected index ed22c971ecbc..c354396586e7 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/ConsecutiveTimestamps.expected @@ -7,6 +7,7 @@ | test_boolean.py:52:11:52:47 | BoolExpr | $@ in $@ has no consecutive successor (expected 3) | test_boolean.py:52:63:52:63 | IntegerLiteral | Timestamp 2 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | | test_boolean.py:52:27:52:31 | False | $@ in $@ has no consecutive successor (expected 2) | test_boolean.py:52:37:52:37 | IntegerLiteral | Timestamp 1 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | | test_boolean.py:52:78:52:79 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 4) | test_boolean.py:52:85:52:85 | IntegerLiteral | Timestamp 3 | test_boolean.py:50:1:50:25 | Function test_mixed_and_or | test_mixed_and_or | +| test_comparison.py:37:17:37:17 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 2) | test_comparison.py:37:23:37:23 | IntegerLiteral | Timestamp 1 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | | test_if.py:95:9:95:13 | False | $@ in $@ has no consecutive successor (expected 2) | test_if.py:95:19:95:19 | IntegerLiteral | Timestamp 1 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | | test_if.py:96:9:96:29 | BoolExpr | $@ in $@ has no consecutive successor (expected 5) | test_if.py:96:36:96:36 | IntegerLiteral | Timestamp 4 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | | test_if.py:96:22:96:22 | y | $@ in $@ has no consecutive successor (expected 4) | test_if.py:96:28:96:28 | IntegerLiteral | Timestamp 3 | test_if.py:93:1:93:34 | Function test_if_compound_condition | test_if_compound_condition | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql new file mode 100644 index 000000000000..883b266c82eb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAllLiveReachable.ql @@ -0,0 +1,13 @@ +/** New-CFG version of AllLiveReachable. */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TestFunction f +where allLiveReachable(a, f) +select a, "Unreachable live annotation; entry of $@ does not reach this node", f, f.getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql new file mode 100644 index 000000000000..bf97a0793222 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgAnnotationHasCfgNode.ql @@ -0,0 +1,17 @@ +/** + * New-CFG version of AnnotationHasCfgNode. + * + * Checks that every timer annotation has a corresponding CFG node. + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils::CfgTests + +from TimerAnnotation ann +where annotationWithoutCfgNode(ann) +select ann, "Annotation in $@ has no CFG node", ann.getTestFunction(), + ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql new file mode 100644 index 000000000000..e12ab8ff5ef6 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockAnnotationGap.ql @@ -0,0 +1,24 @@ +/** + * New-CFG version of BasicBlockAnnotationGap. + * + * Checks that within a basic block, if a node is annotated then its + * successor is also annotated (or excluded). A gap in annotations + * within a basic block indicates a missing annotation, since there + * are no branches to justify the gap. + * + * Nodes with exceptional successors are excluded, as the exception + * edge leaves the basic block and the normal successor may be dead. + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, CfgNode succ +where basicBlockAnnotationGap(a, succ) +select a, "Annotated node followed by unannotated $@ in the same basic block", succ, + succ.getNode().toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql new file mode 100644 index 000000000000..b8254a8e8646 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBasicBlockOrdering.ql @@ -0,0 +1,19 @@ +/** + * New-CFG version of BasicBlockOrdering. + * + * Checks that within a single basic block, annotations appear in + * increasing minimum-timestamp order. + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int minA, int minB +where basicBlockOrdering(a, b, minA, minB) +select a, "Basic block ordering: $@ appears before $@", a.getTimestampExpr(minA), + "timestamp " + minA, b.getTimestampExpr(minB), "timestamp " + minB diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql new file mode 100644 index 000000000000..2dc8ae144dcd --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgBranchTimestamps.ql @@ -0,0 +1,79 @@ +/** + * New-CFG version of BranchTimestamps. + * + * Checks that when a node has both a true and false successor, the + * live timestamps on one branch are marked as dead on the other. + * This ensures that boolean branches are fully annotated with dead() + * markers for the paths not taken. + * + * Limitation: the `@ t[ts, ...]` / `dead(ts)` annotation scheme can only + * model branch-dead-ness for plain boolean control flow that reconverges + * linearly after the split — i.e. `if`-with-else and `if`-expression. + * It cannot model: + * + * * loops (`while` / `for`): body timestamps repeat across iterations, + * so the loop-exit annotation can't list them as dead; + * * `match` statements: each `case` body is a syntactically distinct + * sub-tree, and the branches don't reconverge through a common + * annotation point in the timeline; + * * `try` / `with` and `raise` / `assert`: exception edges are modeled + * as true/false but flow to syntactically distinct handlers, with no + * reconvergence in the linear annotation order; + * * short-circuit `and` / `or` (`BoolExpr`): the branches reconverge at + * the BoolExpr's after-node, so timestamps on one branch are live + * downstream of the other rather than dead; + * * `if` without an `else` clause, and `if`/`elif` chains: the false + * branch reconverges with the true branch at the post-if statement + * (no-else) or fans out across multiple elif-test annotations, + * neither of which fit the binary annotation scheme. + * + * Branch nodes inside those constructs are therefore whitelisted out + * below. The check still fires (and is useful) for plain `if`/`else` + * and conditional-expression branching. + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +/** + * Holds if `f` contains a construct whose branches the linear-timestamp + * annotation scheme cannot describe (see file-level comment). + */ +private predicate hasUnmodellableBranching(Function f) { + exists(AstNode bad | + bad.getScope() = f and + ( + bad instanceof While + or + bad instanceof For + or + bad instanceof MatchStmt + or + bad instanceof Try + or + bad instanceof With + or + bad instanceof Raise + or + bad instanceof Assert + or + bad instanceof BoolExpr + or + bad instanceof If and + (not exists(bad.(If).getAnOrelse()) or bad.(If).isElif()) + ) + ) +} + +from TimerCfgNode node, int ts, string branch +where + missingBranchTimestamp(node, ts, branch) and + not hasUnmodellableBranching(node.getTestFunction()) +select node, + "Timestamp " + ts + " on true/false branch is missing a dead() annotation on the " + branch + + " successor in $@", node.getTestFunction(), node.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected new file mode 100644 index 000000000000..0c9e31f37713 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.expected @@ -0,0 +1 @@ +| test_comparison.py:37:6:37:41 | Compare | $@ in $@ has no consecutive predecessor (expected 1) | test_comparison.py:37:48:37:48 | IntegerLiteral | Timestamp 2 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql new file mode 100644 index 000000000000..0eb8ad5a414e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutivePredecessorTimestamps.ql @@ -0,0 +1,21 @@ +/** + * New-CFG version of ConsecutivePredecessorTimestamps. + * + * Checks that each annotated node (except the minimum timestamp) has + * a predecessor annotation with timestamp `a - 1`. This is the reverse + * of ConsecutiveTimestamps: it catches nodes that are reachable but + * arrived at from the wrong place (skipping an intermediate node). + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutivePredecessorTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive predecessor (expected " + (a - 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected new file mode 100644 index 000000000000..6fdcfc40c4a5 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.expected @@ -0,0 +1 @@ +| test_comparison.py:37:17:37:17 | IntegerLiteral | $@ in $@ has no consecutive successor (expected 2) | test_comparison.py:37:23:37:23 | IntegerLiteral | Timestamp 1 | test_comparison.py:32:1:32:32 | Function test_three_short_circuit | test_three_short_circuit | diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql new file mode 100644 index 000000000000..8fc13c9acba9 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgConsecutiveTimestamps.ql @@ -0,0 +1,27 @@ +/** + * New-CFG version of ConsecutiveTimestamps. + * + * Checks that consecutive annotated nodes have consecutive timestamps: + * for each annotation with timestamp `a`, some CFG node for that annotation + * must have a next annotation containing `a + 1`. + * + * Handles CFG splitting (e.g., finally blocks duplicated for normal/exceptional + * flow) by checking that at least one split has the required successor. + * + * Only applies to functions where all annotations are in the function's + * own scope (excludes tests with generators, async, comprehensions, or + * lambdas that have annotations in nested scopes). + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerAnnotation ann, int a +where consecutiveTimestamps(ann, a) +select ann, "$@ in $@ has no consecutive successor (expected " + (a + 1) + ")", + ann.getTimestampExpr(a), "Timestamp " + a, ann.getTestFunction(), ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll new file mode 100644 index 000000000000..ae27e8f16a0e --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgImpl.qll @@ -0,0 +1,118 @@ +/** + * Implementation of the evaluation-order CFG signature using the new + * shared control flow graph from AstNodeImpl. + */ + +private import python as Py +import TimerUtils +private import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +private import codeql.controlflow.SuccessorType + +private class NewControlFlowNode = CfgImpl::ControlFlowNode; + +private class NewBasicBlock = CfgImpl::BasicBlock; + +/** New (shared) CFG implementation of the evaluation-order signature. */ +module NewCfg implements EvalOrderCfgSig { + class CfgNode instanceof NewControlFlowNode { + // We must pick a *unique* representative CFG node for each AST node. The + // shared CFG has several nodes per AST node (before / in-post-order / after + // / after-value splits), but the timer test framework keys annotations on + // `getNode()` and assumes one CFG node per annotated AST node. Without a + // filter, an annotated `f()` would map to both `f()` and `After f()`, which + // breaks two framework invariants: (1) the "no shared reachable" check + // requires that two distinct nodes sharing a timestamp be mutually + // unreachable (true/false branches of a condition), but `Before f()`, + // `f()` and `After f()` share the annotation's timestamp *and* lie on one + // linear path; and (2) the annotation walk (`nextTimerAnnotation`) halts at + // the first reachable representative, so a second node for the same AST + // node would stall the walk on the same timestamp instead of advancing to + // the next evaluation event. + // + // We use the "after" node (`isAfter`) rather than the canonical `injects` + // node, because `injects` represents short-circuit / conditional + // expressions (`and`/`or`/`not`/ternary) by their *before* node, placing + // them ahead of their operands — wrong for evaluation order. `isAfter` + // instead picks the post-evaluation node: the merged before/after node for + // simple leaves, the `TAfterNode` for post-order expressions, and the + // `AfterValueNode`(s) for pre-order conditionals, all positioned after the + // operands. The two value-split nodes of a conditional are genuinely + // distinct evaluation outcomes (handled by `getATrueSuccessor` / + // `getAFalseSuccessor`), so they do not violate the uniqueness assumption. + CfgNode() { NewControlFlowNode.super.isAfter(_) } + + string toString() { result = NewControlFlowNode.super.toString() } + + Py::Location getLocation() { result = NewControlFlowNode.super.getLocation() } + + Py::AstNode getNode() { + result = CfgImpl::astNodeToPyNode(NewControlFlowNode.super.getAstNode()) + } + + CfgNode getASuccessor() { nextCfgNode(this, result) } + + CfgNode getATrueSuccessor() { + NewControlFlowNode.super.isAfterTrue(_) and + // Only where there's also a false branch (true boolean split) + exists(NewControlFlowNode other | other.isAfterFalse(NewControlFlowNode.super.getAstNode())) and + nextCfgNodeFrom(this, result) + } + + CfgNode getAFalseSuccessor() { + NewControlFlowNode.super.isAfterFalse(_) and + // Only where there's also a true branch (true boolean split) + exists(NewControlFlowNode other | other.isAfterTrue(NewControlFlowNode.super.getAstNode())) and + nextCfgNodeFrom(this, result) + } + + CfgNode getAnExceptionalSuccessor() { + exists(NewControlFlowNode mid | + mid = NewControlFlowNode.super.getAnExceptionSuccessor() and + nextCfgNodeFrom(mid, result) + ) + } + + Py::Scope getScope() { result = NewControlFlowNode.super.getEnclosingCallable().asScope() } + + BasicBlock getBasicBlock() { exists(NewBasicBlock bb | bb.getNode(_) = this and result = bb) } + } + + /** + * Holds if `next` is the nearest CfgNode reachable from `n` via + * one or more raw CFG successor edges, skipping non-CfgNode intermediaries. + */ + private predicate nextCfgNodeFrom(NewControlFlowNode n, CfgNode next) { + next = n.getASuccessor() + or + exists(NewControlFlowNode mid | + mid = n.getASuccessor() and + not mid instanceof CfgNode and + nextCfgNodeFrom(mid, next) + ) + } + + /** + * Holds if `next` is the nearest CfgNode successor of `n`, + * skipping synthetic intermediate nodes. + */ + private predicate nextCfgNode(CfgNode n, CfgNode next) { nextCfgNodeFrom(n, next) } + + class BasicBlock instanceof NewBasicBlock { + string toString() { result = NewBasicBlock.super.toString() } + + CfgNode getNode(int n) { result = NewBasicBlock.super.getNode(n) } + + predicate reaches(BasicBlock bb) { this = bb or this.strictlyReaches(bb) } + + predicate strictlyReaches(BasicBlock bb) { NewBasicBlock.super.getASuccessor+() = bb } + + predicate strictlyDominates(BasicBlock bb) { NewBasicBlock.super.strictlyDominates(bb) } + } + + CfgNode scopeGetEntryNode(Py::Scope s) { + exists(CfgImpl::ControlFlow::EntryNode entry | + entry.getEnclosingCallable().asScope() = s and + nextCfgNodeFrom(entry, result) + ) + } +} diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql new file mode 100644 index 000000000000..db324e6ee76b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNeverReachable.ql @@ -0,0 +1,19 @@ +/** + * New-CFG version of NeverReachable. + * + * Checks that expressions annotated with `t.never` either have no CFG + * node, or if they do, that the node is not reachable from its scope's + * entry (including within the same basic block). + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils::CfgTests + +from TimerAnnotation ann +where neverReachable(ann) +select ann, "Node annotated with t.never is reachable in $@", ann.getTestFunction(), + ann.getTestFunction().getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql new file mode 100644 index 000000000000..8cb0dfb143b0 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBackwardFlow.ql @@ -0,0 +1,20 @@ +/** + * New-CFG version of NoBackwardFlow. + * + * Checks that time never flows backward between consecutive timer annotations + * in the CFG. For each pair of consecutive annotated nodes (A -> B), there must + * exist timestamps a in A and b in B with a < b. + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int minA, int maxB +where noBackwardFlow(a, b, minA, maxB) +select a, "Backward flow: $@ flows to $@ (max timestamp $@)", a.getTimestampExpr(minA), + minA.toString(), b, b.getNode().toString(), b.getTimestampExpr(maxB), maxB.toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql new file mode 100644 index 000000000000..c0fc86b5130b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoBasicBlock.ql @@ -0,0 +1,17 @@ +/** + * New-CFG version of NoBasicBlock. + * + * Checks that every annotated CFG node belongs to a basic block. + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from CfgNode n, TestFunction f +where noBasicBlock(n, f) +select n, "CFG node in $@ does not belong to any basic block", f, f.getName() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql new file mode 100644 index 000000000000..dd174d6d913c --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgNoSharedReachable.ql @@ -0,0 +1,19 @@ +/** + * New-CFG version of NoSharedReachable. + * + * Checks that two annotations sharing a timestamp value are on + * mutually exclusive CFG paths (neither can reach the other). + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int ts +where noSharedReachable(a, b, ts) +select a, "Shared timestamp $@ but this node reaches $@", a.getTimestampExpr(ts), ts.toString(), b, + b.getNode().toString() diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql new file mode 100644 index 000000000000..e7f4a12ff813 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/NewCfgStrictForward.ql @@ -0,0 +1,20 @@ +/** + * New-CFG version of StrictForward. + * + * Stronger version of NoBackwardFlow: for consecutive annotated nodes + * A -> B that both have a single timestamp (non-loop code) and B does + * NOT dominate A (forward edge), requires max(A) < min(B). + */ + +import python +import NewCfgImpl + +private module Utils = EvalOrderCfgUtils; + +private import Utils +private import Utils::CfgTests + +from TimerCfgNode a, TimerCfgNode b, int maxA, int minB +where strictForward(a, b, maxA, minB) +select a, "Strict forward violation: $@ flows to $@", a.getTimestampExpr(maxA), "timestamp " + maxA, + b.getTimestampExpr(minB), "timestamp " + minB diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py new file mode 100644 index 000000000000..978663171663 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_comparison.py @@ -0,0 +1,37 @@ +"""Comparisons and evaluation order. + +Comparison operands are evaluated left-to-right, followed by the comparison +node itself. Annotations record the *run-time* evaluation order, so this file +self-validates under CPython (``python3 test_comparison.py``). + +Python short-circuits *chained* comparisons (in ``a < b < c`` the operand ``c`` +is skipped once ``a < b`` is false), whereas the control-flow graph +conservatively evaluates every operand. That divergence cannot be expressed in +a single annotation, so the affected CFG queries report it (captured in the +ConsecutiveTimestamps and NewCfgConsecutivePredecessorTimestamps .expected +files). +""" + +from timer import test, dead + + +@test +def test_two(t): + # Both operands, then the comparison. + (1 @ t[0] < 0 @ t[1]) @ t[2] + + +@test +def test_three(t): + # Chained comparison, all comparisons hold: operands left-to-right, then + # the comparison. Run time and CFG agree. + (1 @ t[0] < 2 @ t[1] < 3 @ t[2]) @ t[3] + + +@test +def test_three_short_circuit(t): + # ``1 > 2`` is false, so at run time Python short-circuits and never + # evaluates ``3``; the comparison is reached at timestamp 2. The CFG still + # evaluates ``3`` (dead at run time), which is why the CFG queries report a + # gap around this comparison. + (1 @ t[0] > 2 @ t[1] < 3 @ t[dead(2)]) @ t[2] diff --git a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py index 8880aaaef348..a6eb6c7d5cac 100644 --- a/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py +++ b/python/ql/test/library-tests/ControlFlow/evaluation-order/test_if.py @@ -85,7 +85,7 @@ def test_nested_if_else(t): else: z = 2 @ t[dead(4)] else: - z = 3 @ t[dead(4)] + z = 3 @ t[dead(3), dead(4)] w = 0 @ t[5] diff --git a/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql new file mode 100644 index 000000000000..4ab2ef5be8fb --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/StoreLoadTest.ql @@ -0,0 +1,41 @@ +/** + * Inline-expectations test for the store/load/delete/parameter + * classification predicates on the new-CFG facade. + * + * Each tag fires when the corresponding predicate (`isLoad`, + * `isStore`, `isDelete`, `isParameter`, `isAugLoad`, `isAugStore`) + * holds on the canonical CFG node wrapping a `Py::Name` with the + * given identifier. Subscript and attribute stores are not covered + * by these tags — only the `Name`-typed targets/loads they involve. + */ + +import python +import semmle.python.controlflow.internal.Cfg as Cfg +import utils.test.InlineExpectationsTest + +module StoreLoadTest implements TestSig { + string getARelevantTag() { result = ["load", "store", "delete", "param", "augload", "augstore"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Cfg::NameNode n | + location = n.getLocation() and + element = n.toString() and + value = n.getId() and + ( + n.isLoad() and not n.isAugLoad() and tag = "load" + or + n.isStore() and not n.isAugStore() and tag = "store" + or + n.isDelete() and tag = "delete" + or + n.isParameter() and tag = "param" + or + n.isAugLoad() and tag = "augload" + or + n.isAugStore() and tag = "augstore" + ) + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/store-load/test.py b/python/ql/test/library-tests/ControlFlow/store-load/test.py new file mode 100644 index 000000000000..dfca45a0b47b --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/store-load/test.py @@ -0,0 +1,56 @@ +# Store/load/delete/parameter classification on the new-CFG facade. +# +# Each annotated location carries the (sorted, deduplicated) set of +# kinds the CFG facade reports there. Comparing against the legacy +# 'semmle.python.Flow' classification is done by the comparison query +# 'StoreLoadParity.ql' — annotations here are only the positive +# assertions for the new facade. +# +# Tags: +# load= -- isLoad() fires on the Name +# store= -- isStore() fires +# delete= -- isDelete() fires +# param= -- isParameter() fires +# augload= -- isAugLoad() fires (the LHS of x += ... when read) +# augstore= -- isAugStore() fires (the LHS of x += ... when written) + + +# --- plain load / store / delete --- + +x = 1 # $ store=x +y = x + 1 # $ store=y load=x +print(y) # $ load=print load=y +del x # $ delete=x + + +# --- function definitions (parameters) --- + +def f(a, b=2, *args, c, **kwargs): # $ store=f param=a param=b param=args param=c param=kwargs + return a + b + c # $ load=a load=b load=c + + +# --- augmented assignment splits one Name into load + store halves --- + +def aug(): # $ store=aug + n = 0 # $ store=n + n += 1 # $ augload=n augstore=n + return n # $ load=n + + +# --- subscript / attribute stores --- + +class C: # $ store=C + pass + + +def stores(obj, container, idx): # $ store=stores param=obj param=container param=idx + obj.attr = 1 # $ load=obj + container[idx] = 2 # $ load=container load=idx + return obj # $ load=obj + + +# --- tuple unpacking --- + +def unpack(pair): # $ store=unpack param=pair + a, b = pair # $ store=a store=b load=pair + return a + b # $ load=a load=b diff --git a/ql/Cargo.lock b/ql/Cargo.lock index 5c65d88de6a7..d6ea9ea343ef 100644 --- a/ql/Cargo.lock +++ b/ql/Cargo.lock @@ -1017,6 +1017,7 @@ dependencies = [ "tree-sitter-python", "tree-sitter-ruby", "yeast-macros", + "yeast-schema", ] [[package]] @@ -1028,6 +1029,15 @@ dependencies = [ "syn", ] +[[package]] +name = "yeast-schema" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "serde_yaml", +] + [[package]] name = "zstd" version = "0.13.3" diff --git a/ql/extractor/src/extractor.rs b/ql/extractor/src/extractor.rs index 66096442e85f..8383d8424eee 100644 --- a/ql/extractor/src/extractor.rs +++ b/ql/extractor/src/extractor.rs @@ -29,28 +29,24 @@ pub fn run(options: Options) -> std::io::Result<()> { prefix: "ql", ts_language: tree_sitter_ql::LANGUAGE.into(), node_types: tree_sitter_ql::NODE_TYPES, - desugar: None, file_globs: vec!["*.ql".into(), "*.qll".into()], }, simple::LanguageSpec { prefix: "dbscheme", ts_language: tree_sitter_ql_dbscheme::LANGUAGE.into(), node_types: tree_sitter_ql_dbscheme::NODE_TYPES, - desugar: None, file_globs: vec!["*.dbscheme".into()], }, simple::LanguageSpec { prefix: "json", ts_language: tree_sitter_json::LANGUAGE.into(), node_types: tree_sitter_json::NODE_TYPES, - desugar: None, file_globs: vec!["*.json".into(), "*.jsonl".into(), "*.jsonc".into()], }, simple::LanguageSpec { prefix: "blame", ts_language: tree_sitter_blame::LANGUAGE.into(), node_types: tree_sitter_blame::NODE_TYPES, - desugar: None, file_globs: vec!["*.blame".into()], }, ], diff --git a/ql/extractor/src/generator.rs b/ql/extractor/src/generator.rs index 96ce5319dd19..7f8ca718344c 100644 --- a/ql/extractor/src/generator.rs +++ b/ql/extractor/src/generator.rs @@ -44,6 +44,7 @@ pub fn run(options: Options) -> std::io::Result<()> { languages, options.dbscheme, options.library, + false, // do not use facade AST "run 'scripts/create-extractor-pack.sh' in ql/", ) } diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index e2aedc401f7a..51424106719d 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -25,8 +25,10 @@ private predicate discardLocation(@location_default loc) { overlay[local] module QL { + private module F = QL; + /** The base class for all AST nodes */ - private class AstNodeImpl extends @ql_ast_node { + class AstNode extends @ql_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -34,13 +36,13 @@ module QL { final L::Location getLocation() { ql_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { ql_ast_node_parent(this, result, _) } + final F::AstNode getParent() { ql_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { ql_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -49,10 +51,8 @@ module QL { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @ql_token, AstNodeImpl { + class Token extends @ql_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { ql_tokeninfo(this, _, result) } @@ -63,10 +63,8 @@ module QL { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @ql_reserved_word, TokenImpl { + class ReservedWord extends @ql_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -92,21 +90,21 @@ module QL { } /** A class representing `add_expr` nodes. */ - final class AddExpr extends @ql_add_expr, AstNodeImpl { + class AddExpr extends @ql_add_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AddExpr" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_add_expr_def(this, result, _, _) } + final F::AstNode getLeft() { ql_add_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_add_expr_def(this, _, result, _) } + final F::AstNode getRight() { ql_add_expr_def(this, _, result, _) } /** Gets the child of this node. */ - final Addop getChild() { ql_add_expr_def(this, _, _, result) } + final F::Addop getChild() { ql_add_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_add_expr_def(this, result, _, _) or ql_add_expr_def(this, _, result, _) or ql_add_expr_def(this, _, _, result) @@ -114,211 +112,237 @@ module QL { } /** A class representing `addop` tokens. */ - final class Addop extends @ql_token_addop, TokenImpl { + class Addop extends @ql_token_addop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Addop" } } /** A class representing `aggId` tokens. */ - final class AggId extends @ql_token_agg_id, TokenImpl { + class AggId extends @ql_token_agg_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AggId" } } /** A class representing `aggregate` nodes. */ - final class Aggregate extends @ql_aggregate, AstNodeImpl { + class Aggregate extends @ql_aggregate, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Aggregate" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_aggregate_child(this, i, result) } + final F::AstNode getChild(int i) { ql_aggregate_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_aggregate_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_aggregate_child(this, _, result) } } /** A class representing `annotArg` nodes. */ - final class AnnotArg extends @ql_annot_arg, AstNodeImpl { + class AnnotArg extends @ql_annot_arg, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AnnotArg" } /** Gets the child of this node. */ - final AstNode getChild() { ql_annot_arg_def(this, result) } + final F::AstNode getChild() { ql_annot_arg_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_annot_arg_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_annot_arg_def(this, result) } } /** A class representing `annotName` tokens. */ - final class AnnotName extends @ql_token_annot_name, TokenImpl { + class AnnotName extends @ql_token_annot_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AnnotName" } } /** A class representing `annotation` nodes. */ - final class Annotation extends @ql_annotation, AstNodeImpl { + class Annotation extends @ql_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Annotation" } /** Gets the node corresponding to the field `args`. */ - final AstNode getArgs(int i) { ql_annotation_args(this, i, result) } + final F::AstNode getArgs(int i) { ql_annotation_args(this, i, result) } + + /** Gets the node corresponding to the field `args`. */ + final F::AstNode getAnArgs() { result = this.getArgs(_) } /** Gets the node corresponding to the field `name`. */ - final AnnotName getName() { ql_annotation_def(this, result) } + final F::AnnotName getName() { ql_annotation_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_annotation_args(this, _, result) or ql_annotation_def(this, result) } } /** A class representing `aritylessPredicateExpr` nodes. */ - final class AritylessPredicateExpr extends @ql_arityless_predicate_expr, AstNodeImpl { + class AritylessPredicateExpr extends @ql_arityless_predicate_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AritylessPredicateExpr" } /** Gets the node corresponding to the field `name`. */ - final LiteralId getName() { ql_arityless_predicate_expr_def(this, result) } + final F::LiteralId getName() { ql_arityless_predicate_expr_def(this, result) } /** Gets the node corresponding to the field `qualifier`. */ - final ModuleExpr getQualifier() { ql_arityless_predicate_expr_qualifier(this, result) } + final F::ModuleExpr getQualifier() { ql_arityless_predicate_expr_qualifier(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_arityless_predicate_expr_def(this, result) or ql_arityless_predicate_expr_qualifier(this, result) } } /** A class representing `asExpr` nodes. */ - final class AsExpr extends @ql_as_expr, AstNodeImpl { + class AsExpr extends @ql_as_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AsExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_as_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_as_expr_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_as_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_as_expr_child(this, _, result) } } /** A class representing `asExprs` nodes. */ - final class AsExprs extends @ql_as_exprs, AstNodeImpl { + class AsExprs extends @ql_as_exprs, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AsExprs" } /** Gets the `i`th child of this node. */ - final AsExpr getChild(int i) { ql_as_exprs_child(this, i, result) } + final F::AsExpr getChild(int i) { ql_as_exprs_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AsExpr getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_as_exprs_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_as_exprs_child(this, _, result) } } /** A class representing `block_comment` tokens. */ - final class BlockComment extends @ql_token_block_comment, TokenImpl { + class BlockComment extends @ql_token_block_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockComment" } } /** A class representing `body` nodes. */ - final class Body extends @ql_body, AstNodeImpl { + class Body extends @ql_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Body" } /** Gets the child of this node. */ - final AstNode getChild() { ql_body_def(this, result) } + final F::AstNode getChild() { ql_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_body_def(this, result) } } /** A class representing `bool` nodes. */ - final class Bool extends @ql_bool, AstNodeImpl { + class Bool extends @ql_bool, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Bool" } /** Gets the child of this node. */ - final AstNode getChild() { ql_bool_def(this, result) } + final F::AstNode getChild() { ql_bool_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_bool_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_bool_def(this, result) } } /** A class representing `call_body` nodes. */ - final class CallBody extends @ql_call_body, AstNodeImpl { + class CallBody extends @ql_call_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallBody" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_call_body_child(this, i, result) } + final F::AstNode getChild(int i) { ql_call_body_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_call_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_call_body_child(this, _, result) } } /** A class representing `call_or_unqual_agg_expr` nodes. */ - final class CallOrUnqualAggExpr extends @ql_call_or_unqual_agg_expr, AstNodeImpl { + class CallOrUnqualAggExpr extends @ql_call_or_unqual_agg_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallOrUnqualAggExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_call_or_unqual_agg_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_call_or_unqual_agg_expr_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_call_or_unqual_agg_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ql_call_or_unqual_agg_expr_child(this, _, result) + } } /** A class representing `charpred` nodes. */ - final class Charpred extends @ql_charpred, AstNodeImpl { + class Charpred extends @ql_charpred, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Charpred" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ql_charpred_def(this, result, _) } + final F::AstNode getBody() { ql_charpred_def(this, result, _) } /** Gets the child of this node. */ - final ClassName getChild() { ql_charpred_def(this, _, result) } + final F::ClassName getChild() { ql_charpred_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_charpred_def(this, result, _) or ql_charpred_def(this, _, result) } } /** A class representing `classMember` nodes. */ - final class ClassMember extends @ql_class_member, AstNodeImpl { + class ClassMember extends @ql_class_member, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassMember" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_class_member_child(this, i, result) } + final F::AstNode getChild(int i) { ql_class_member_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_class_member_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_class_member_child(this, _, result) } } /** A class representing `className` tokens. */ - final class ClassName extends @ql_token_class_name, TokenImpl { + class ClassName extends @ql_token_class_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassName" } } /** A class representing `classlessPredicate` nodes. */ - final class ClasslessPredicate extends @ql_classless_predicate, AstNodeImpl { + class ClasslessPredicate extends @ql_classless_predicate, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClasslessPredicate" } /** Gets the node corresponding to the field `name`. */ - final PredicateName getName() { ql_classless_predicate_def(this, result, _) } + final F::PredicateName getName() { ql_classless_predicate_def(this, result, _) } /** Gets the node corresponding to the field `returnType`. */ - final AstNode getReturnType() { ql_classless_predicate_def(this, _, result) } + final F::AstNode getReturnType() { ql_classless_predicate_def(this, _, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_classless_predicate_child(this, i, result) } + final F::AstNode getChild(int i) { ql_classless_predicate_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_classless_predicate_def(this, result, _) or ql_classless_predicate_def(this, _, result) or ql_classless_predicate_child(this, _, result) @@ -326,27 +350,27 @@ module QL { } /** A class representing `closure` tokens. */ - final class Closure extends @ql_token_closure, TokenImpl { + class Closure extends @ql_token_closure, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Closure" } } /** A class representing `comp_term` nodes. */ - final class CompTerm extends @ql_comp_term, AstNodeImpl { + class CompTerm extends @ql_comp_term, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CompTerm" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_comp_term_def(this, result, _, _) } + final F::AstNode getLeft() { ql_comp_term_def(this, result, _, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_comp_term_def(this, _, result, _) } + final F::AstNode getRight() { ql_comp_term_def(this, _, result, _) } /** Gets the child of this node. */ - final Compop getChild() { ql_comp_term_def(this, _, _, result) } + final F::Compop getChild() { ql_comp_term_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_comp_term_def(this, result, _, _) or ql_comp_term_def(this, _, result, _) or ql_comp_term_def(this, _, _, result) @@ -354,47 +378,56 @@ module QL { } /** A class representing `compop` tokens. */ - final class Compop extends @ql_token_compop, TokenImpl { + class Compop extends @ql_token_compop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Compop" } } /** A class representing `conjunction` nodes. */ - final class Conjunction extends @ql_conjunction, AstNodeImpl { + class Conjunction extends @ql_conjunction, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Conjunction" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_conjunction_def(this, result, _) } + final F::AstNode getLeft() { ql_conjunction_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_conjunction_def(this, _, result) } + final F::AstNode getRight() { ql_conjunction_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_conjunction_def(this, result, _) or ql_conjunction_def(this, _, result) } } /** A class representing `dataclass` nodes. */ - final class Dataclass extends @ql_dataclass, AstNodeImpl { + class Dataclass extends @ql_dataclass, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dataclass" } /** Gets the node corresponding to the field `extends`. */ - final AstNode getExtends(int i) { ql_dataclass_extends(this, i, result) } + final F::AstNode getExtends(int i) { ql_dataclass_extends(this, i, result) } + + /** Gets the node corresponding to the field `extends`. */ + final F::AstNode getAnExtends() { result = this.getExtends(_) } + + /** Gets the node corresponding to the field `instanceof`. */ + final F::AstNode getInstanceof(int i) { ql_dataclass_instanceof(this, i, result) } /** Gets the node corresponding to the field `instanceof`. */ - final AstNode getInstanceof(int i) { ql_dataclass_instanceof(this, i, result) } + final F::AstNode getAnInstanceof() { result = this.getInstanceof(_) } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_dataclass_def(this, result) } + final F::ClassName getName() { ql_dataclass_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_dataclass_child(this, i, result) } + final F::AstNode getChild(int i) { ql_dataclass_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_dataclass_extends(this, _, result) or ql_dataclass_instanceof(this, _, result) or ql_dataclass_def(this, result) or @@ -403,119 +436,125 @@ module QL { } /** A class representing `datatype` nodes. */ - final class Datatype extends @ql_datatype, AstNodeImpl { + class Datatype extends @ql_datatype, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Datatype" } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_datatype_def(this, result, _) } + final F::ClassName getName() { ql_datatype_def(this, result, _) } /** Gets the child of this node. */ - final DatatypeBranches getChild() { ql_datatype_def(this, _, result) } + final F::DatatypeBranches getChild() { ql_datatype_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_datatype_def(this, result, _) or ql_datatype_def(this, _, result) } } /** A class representing `datatypeBranch` nodes. */ - final class DatatypeBranch extends @ql_datatype_branch, AstNodeImpl { + class DatatypeBranch extends @ql_datatype_branch, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DatatypeBranch" } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_datatype_branch_def(this, result) } + final F::ClassName getName() { ql_datatype_branch_def(this, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getChild(int i) { ql_datatype_branch_child(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_datatype_branch_child(this, i, result) } + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_datatype_branch_def(this, result) or ql_datatype_branch_child(this, _, result) } } /** A class representing `datatypeBranches` nodes. */ - final class DatatypeBranches extends @ql_datatype_branches, AstNodeImpl { + class DatatypeBranches extends @ql_datatype_branches, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DatatypeBranches" } /** Gets the `i`th child of this node. */ - final DatatypeBranch getChild(int i) { ql_datatype_branches_child(this, i, result) } + final F::DatatypeBranch getChild(int i) { ql_datatype_branches_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::DatatypeBranch getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_datatype_branches_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_datatype_branches_child(this, _, result) } } /** A class representing `dbtype` tokens. */ - final class Dbtype extends @ql_token_dbtype, TokenImpl { + class Dbtype extends @ql_token_dbtype, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dbtype" } } /** A class representing `direction` tokens. */ - final class Direction extends @ql_token_direction, TokenImpl { + class Direction extends @ql_token_direction, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Direction" } } /** A class representing `disjunction` nodes. */ - final class Disjunction extends @ql_disjunction, AstNodeImpl { + class Disjunction extends @ql_disjunction, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Disjunction" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_disjunction_def(this, result, _) } + final F::AstNode getLeft() { ql_disjunction_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_disjunction_def(this, _, result) } + final F::AstNode getRight() { ql_disjunction_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_disjunction_def(this, result, _) or ql_disjunction_def(this, _, result) } } /** A class representing `empty` tokens. */ - final class Empty extends @ql_token_empty, TokenImpl { + class Empty extends @ql_token_empty, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Empty" } } /** A class representing `expr_aggregate_body` nodes. */ - final class ExprAggregateBody extends @ql_expr_aggregate_body, AstNodeImpl { + class ExprAggregateBody extends @ql_expr_aggregate_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprAggregateBody" } /** Gets the node corresponding to the field `asExprs`. */ - final AsExprs getAsExprs() { ql_expr_aggregate_body_def(this, result) } + final F::AsExprs getAsExprs() { ql_expr_aggregate_body_def(this, result) } /** Gets the node corresponding to the field `orderBys`. */ - final OrderBys getOrderBys() { ql_expr_aggregate_body_order_bys(this, result) } + final F::OrderBys getOrderBys() { ql_expr_aggregate_body_order_bys(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_expr_aggregate_body_def(this, result) or ql_expr_aggregate_body_order_bys(this, result) } } /** A class representing `expr_annotation` nodes. */ - final class ExprAnnotation extends @ql_expr_annotation, AstNodeImpl { + class ExprAnnotation extends @ql_expr_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprAnnotation" } /** Gets the node corresponding to the field `annot_arg`. */ - final AnnotName getAnnotArg() { ql_expr_annotation_def(this, result, _, _) } + final F::AnnotName getAnnotArg() { ql_expr_annotation_def(this, result, _, _) } /** Gets the node corresponding to the field `name`. */ - final AnnotName getName() { ql_expr_annotation_def(this, _, result, _) } + final F::AnnotName getName() { ql_expr_annotation_def(this, _, result, _) } /** Gets the child of this node. */ - final AstNode getChild() { ql_expr_annotation_def(this, _, _, result) } + final F::AstNode getChild() { ql_expr_annotation_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_expr_annotation_def(this, result, _, _) or ql_expr_annotation_def(this, _, result, _) or ql_expr_annotation_def(this, _, _, result) @@ -523,48 +562,51 @@ module QL { } /** A class representing `false` tokens. */ - final class False extends @ql_token_false, TokenImpl { + class False extends @ql_token_false, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "False" } } /** A class representing `field` nodes. */ - final class Field extends @ql_field, AstNodeImpl { + class Field extends @ql_field, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Field" } /** Gets the child of this node. */ - final VarDecl getChild() { ql_field_def(this, result) } + final F::VarDecl getChild() { ql_field_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_field_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_field_def(this, result) } } /** A class representing `float` tokens. */ - final class Float extends @ql_token_float, TokenImpl { + class Float extends @ql_token_float, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Float" } } /** A class representing `full_aggregate_body` nodes. */ - final class FullAggregateBody extends @ql_full_aggregate_body, AstNodeImpl { + class FullAggregateBody extends @ql_full_aggregate_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FullAggregateBody" } /** Gets the node corresponding to the field `asExprs`. */ - final AsExprs getAsExprs() { ql_full_aggregate_body_as_exprs(this, result) } + final F::AsExprs getAsExprs() { ql_full_aggregate_body_as_exprs(this, result) } /** Gets the node corresponding to the field `guard`. */ - final AstNode getGuard() { ql_full_aggregate_body_guard(this, result) } + final F::AstNode getGuard() { ql_full_aggregate_body_guard(this, result) } /** Gets the node corresponding to the field `orderBys`. */ - final OrderBys getOrderBys() { ql_full_aggregate_body_order_bys(this, result) } + final F::OrderBys getOrderBys() { ql_full_aggregate_body_order_bys(this, result) } /** Gets the `i`th child of this node. */ - final VarDecl getChild(int i) { ql_full_aggregate_body_child(this, i, result) } + final F::VarDecl getChild(int i) { ql_full_aggregate_body_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::VarDecl getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_full_aggregate_body_as_exprs(this, result) or ql_full_aggregate_body_guard(this, result) or ql_full_aggregate_body_order_bys(this, result) or @@ -573,38 +615,41 @@ module QL { } /** A class representing `higherOrderTerm` nodes. */ - final class HigherOrderTerm extends @ql_higher_order_term, AstNodeImpl { + class HigherOrderTerm extends @ql_higher_order_term, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HigherOrderTerm" } /** Gets the node corresponding to the field `name`. */ - final LiteralId getName() { ql_higher_order_term_def(this, result) } + final F::LiteralId getName() { ql_higher_order_term_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_higher_order_term_child(this, i, result) } + final F::AstNode getChild(int i) { ql_higher_order_term_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_higher_order_term_def(this, result) or ql_higher_order_term_child(this, _, result) } } /** A class representing `if_term` nodes. */ - final class IfTerm extends @ql_if_term, AstNodeImpl { + class IfTerm extends @ql_if_term, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfTerm" } /** Gets the node corresponding to the field `cond`. */ - final AstNode getCond() { ql_if_term_def(this, result, _, _) } + final F::AstNode getCond() { ql_if_term_def(this, result, _, _) } /** Gets the node corresponding to the field `first`. */ - final AstNode getFirst() { ql_if_term_def(this, _, result, _) } + final F::AstNode getFirst() { ql_if_term_def(this, _, result, _) } /** Gets the node corresponding to the field `second`. */ - final AstNode getSecond() { ql_if_term_def(this, _, _, result) } + final F::AstNode getSecond() { ql_if_term_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_if_term_def(this, result, _, _) or ql_if_term_def(this, _, result, _) or ql_if_term_def(this, _, _, result) @@ -612,126 +657,138 @@ module QL { } /** A class representing `implication` nodes. */ - final class Implication extends @ql_implication, AstNodeImpl { + class Implication extends @ql_implication, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Implication" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_implication_def(this, result, _) } + final F::AstNode getLeft() { ql_implication_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_implication_def(this, _, result) } + final F::AstNode getRight() { ql_implication_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_implication_def(this, result, _) or ql_implication_def(this, _, result) } } /** A class representing `importDirective` nodes. */ - final class ImportDirective extends @ql_import_directive, AstNodeImpl { + class ImportDirective extends @ql_import_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportDirective" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_import_directive_child(this, i, result) } + final F::AstNode getChild(int i) { ql_import_directive_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_import_directive_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_import_directive_child(this, _, result) } } /** A class representing `importModuleExpr` nodes. */ - final class ImportModuleExpr extends @ql_import_module_expr, AstNodeImpl { + class ImportModuleExpr extends @ql_import_module_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportModuleExpr" } /** Gets the node corresponding to the field `qualName`. */ - final SimpleId getQualName(int i) { ql_import_module_expr_qual_name(this, i, result) } + final F::SimpleId getQualName(int i) { ql_import_module_expr_qual_name(this, i, result) } + + /** Gets the node corresponding to the field `qualName`. */ + final F::SimpleId getAQualName() { result = this.getQualName(_) } /** Gets the child of this node. */ - final ModuleExpr getChild() { ql_import_module_expr_def(this, result) } + final F::ModuleExpr getChild() { ql_import_module_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_import_module_expr_qual_name(this, _, result) or ql_import_module_expr_def(this, result) } } /** A class representing `in_expr` nodes. */ - final class InExpr extends @ql_in_expr, AstNodeImpl { + class InExpr extends @ql_in_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InExpr" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_in_expr_def(this, result, _) } + final F::AstNode getLeft() { ql_in_expr_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_in_expr_def(this, _, result) } + final F::AstNode getRight() { ql_in_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_in_expr_def(this, result, _) or ql_in_expr_def(this, _, result) } } /** A class representing `instance_of` nodes. */ - final class InstanceOf extends @ql_instance_of, AstNodeImpl { + class InstanceOf extends @ql_instance_of, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InstanceOf" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_instance_of_child(this, i, result) } + final F::AstNode getChild(int i) { ql_instance_of_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_instance_of_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_instance_of_child(this, _, result) } } /** A class representing `integer` tokens. */ - final class Integer extends @ql_token_integer, TokenImpl { + class Integer extends @ql_token_integer, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Integer" } } /** A class representing `line_comment` tokens. */ - final class LineComment extends @ql_token_line_comment, TokenImpl { + class LineComment extends @ql_token_line_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LineComment" } } /** A class representing `literal` nodes. */ - final class Literal extends @ql_literal, AstNodeImpl { + class Literal extends @ql_literal, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Literal" } /** Gets the child of this node. */ - final AstNode getChild() { ql_literal_def(this, result) } + final F::AstNode getChild() { ql_literal_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_literal_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_literal_def(this, result) } } /** A class representing `literalId` tokens. */ - final class LiteralId extends @ql_token_literal_id, TokenImpl { + class LiteralId extends @ql_token_literal_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LiteralId" } } /** A class representing `memberPredicate` nodes. */ - final class MemberPredicate extends @ql_member_predicate, AstNodeImpl { + class MemberPredicate extends @ql_member_predicate, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberPredicate" } /** Gets the node corresponding to the field `name`. */ - final PredicateName getName() { ql_member_predicate_def(this, result, _) } + final F::PredicateName getName() { ql_member_predicate_def(this, result, _) } /** Gets the node corresponding to the field `returnType`. */ - final AstNode getReturnType() { ql_member_predicate_def(this, _, result) } + final F::AstNode getReturnType() { ql_member_predicate_def(this, _, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getChild(int i) { ql_member_predicate_child(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_member_predicate_child(this, i, result) } + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_member_predicate_def(this, result, _) or ql_member_predicate_def(this, _, result) or ql_member_predicate_child(this, _, result) @@ -739,24 +796,33 @@ module QL { } /** A class representing `module` nodes. */ - final class Module extends @ql_module, AstNodeImpl { + class Module extends @ql_module, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Module" } /** Gets the node corresponding to the field `implements`. */ - final SignatureExpr getImplements(int i) { ql_module_implements(this, i, result) } + final F::SignatureExpr getImplements(int i) { ql_module_implements(this, i, result) } + + /** Gets the node corresponding to the field `implements`. */ + final F::SignatureExpr getAnImplements() { result = this.getImplements(_) } /** Gets the node corresponding to the field `name`. */ - final ModuleName getName() { ql_module_def(this, result) } + final F::ModuleName getName() { ql_module_def(this, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final F::ModuleParam getParameter(int i) { ql_module_parameter(this, i, result) } /** Gets the node corresponding to the field `parameter`. */ - final ModuleParam getParameter(int i) { ql_module_parameter(this, i, result) } + final F::ModuleParam getAParameter() { result = this.getParameter(_) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_module_child(this, i, result) } + final F::AstNode getChild(int i) { ql_module_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_implements(this, _, result) or ql_module_def(this, result) or ql_module_parameter(this, _, result) or @@ -765,108 +831,114 @@ module QL { } /** A class representing `moduleAliasBody` nodes. */ - final class ModuleAliasBody extends @ql_module_alias_body, AstNodeImpl { + class ModuleAliasBody extends @ql_module_alias_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleAliasBody" } /** Gets the child of this node. */ - final ModuleExpr getChild() { ql_module_alias_body_def(this, result) } + final F::ModuleExpr getChild() { ql_module_alias_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_module_alias_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_module_alias_body_def(this, result) } } /** A class representing `moduleExpr` nodes. */ - final class ModuleExpr extends @ql_module_expr, AstNodeImpl { + class ModuleExpr extends @ql_module_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleExpr" } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ql_module_expr_name(this, result) } + final F::AstNode getName() { ql_module_expr_name(this, result) } /** Gets the child of this node. */ - final AstNode getChild() { ql_module_expr_def(this, result) } + final F::AstNode getChild() { ql_module_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_expr_name(this, result) or ql_module_expr_def(this, result) } } /** A class representing `moduleInstantiation` nodes. */ - final class ModuleInstantiation extends @ql_module_instantiation, AstNodeImpl { + class ModuleInstantiation extends @ql_module_instantiation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleInstantiation" } /** Gets the node corresponding to the field `name`. */ - final ModuleName getName() { ql_module_instantiation_def(this, result) } + final F::ModuleName getName() { ql_module_instantiation_def(this, result) } /** Gets the `i`th child of this node. */ - final SignatureExpr getChild(int i) { ql_module_instantiation_child(this, i, result) } + final F::SignatureExpr getChild(int i) { ql_module_instantiation_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::SignatureExpr getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_instantiation_def(this, result) or ql_module_instantiation_child(this, _, result) } } /** A class representing `moduleMember` nodes. */ - final class ModuleMember extends @ql_module_member, AstNodeImpl { + class ModuleMember extends @ql_module_member, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleMember" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_module_member_child(this, i, result) } + final F::AstNode getChild(int i) { ql_module_member_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_module_member_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_module_member_child(this, _, result) } } /** A class representing `moduleName` nodes. */ - final class ModuleName extends @ql_module_name, AstNodeImpl { + class ModuleName extends @ql_module_name, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleName" } /** Gets the child of this node. */ - final SimpleId getChild() { ql_module_name_def(this, result) } + final F::SimpleId getChild() { ql_module_name_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_module_name_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_module_name_def(this, result) } } /** A class representing `moduleParam` nodes. */ - final class ModuleParam extends @ql_module_param, AstNodeImpl { + class ModuleParam extends @ql_module_param, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ModuleParam" } /** Gets the node corresponding to the field `parameter`. */ - final SimpleId getParameter() { ql_module_param_def(this, result, _) } + final F::SimpleId getParameter() { ql_module_param_def(this, result, _) } /** Gets the node corresponding to the field `signature`. */ - final SignatureExpr getSignature() { ql_module_param_def(this, _, result) } + final F::SignatureExpr getSignature() { ql_module_param_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_module_param_def(this, result, _) or ql_module_param_def(this, _, result) } } /** A class representing `mul_expr` nodes. */ - final class MulExpr extends @ql_mul_expr, AstNodeImpl { + class MulExpr extends @ql_mul_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MulExpr" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ql_mul_expr_def(this, result, _, _) } + final F::AstNode getLeft() { ql_mul_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ql_mul_expr_def(this, _, result, _) } + final F::AstNode getRight() { ql_mul_expr_def(this, _, result, _) } /** Gets the child of this node. */ - final Mulop getChild() { ql_mul_expr_def(this, _, _, result) } + final F::Mulop getChild() { ql_mul_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_mul_expr_def(this, result, _, _) or ql_mul_expr_def(this, _, result, _) or ql_mul_expr_def(this, _, _, result) @@ -874,179 +946,203 @@ module QL { } /** A class representing `mulop` tokens. */ - final class Mulop extends @ql_token_mulop, TokenImpl { + class Mulop extends @ql_token_mulop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Mulop" } } /** A class representing `negation` nodes. */ - final class Negation extends @ql_negation, AstNodeImpl { + class Negation extends @ql_negation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Negation" } /** Gets the child of this node. */ - final AstNode getChild() { ql_negation_def(this, result) } + final F::AstNode getChild() { ql_negation_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_negation_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_negation_def(this, result) } } /** A class representing `orderBy` nodes. */ - final class OrderBy extends @ql_order_by, AstNodeImpl { + class OrderBy extends @ql_order_by, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrderBy" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_order_by_child(this, i, result) } + final F::AstNode getChild(int i) { ql_order_by_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_order_by_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_order_by_child(this, _, result) } } /** A class representing `orderBys` nodes. */ - final class OrderBys extends @ql_order_bys, AstNodeImpl { + class OrderBys extends @ql_order_bys, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrderBys" } /** Gets the `i`th child of this node. */ - final OrderBy getChild(int i) { ql_order_bys_child(this, i, result) } + final F::OrderBy getChild(int i) { ql_order_bys_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::OrderBy getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_order_bys_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_order_bys_child(this, _, result) } } /** A class representing `par_expr` nodes. */ - final class ParExpr extends @ql_par_expr, AstNodeImpl { + class ParExpr extends @ql_par_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ParExpr" } /** Gets the child of this node. */ - final AstNode getChild() { ql_par_expr_def(this, result) } + final F::AstNode getChild() { ql_par_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_par_expr_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_par_expr_def(this, result) } } /** A class representing `predicate` tokens. */ - final class Predicate extends @ql_token_predicate, TokenImpl { + class Predicate extends @ql_token_predicate, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Predicate" } } /** A class representing `predicateAliasBody` nodes. */ - final class PredicateAliasBody extends @ql_predicate_alias_body, AstNodeImpl { + class PredicateAliasBody extends @ql_predicate_alias_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PredicateAliasBody" } /** Gets the child of this node. */ - final PredicateExpr getChild() { ql_predicate_alias_body_def(this, result) } + final F::PredicateExpr getChild() { ql_predicate_alias_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_predicate_alias_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_predicate_alias_body_def(this, result) } } /** A class representing `predicateExpr` nodes. */ - final class PredicateExpr extends @ql_predicate_expr, AstNodeImpl { + class PredicateExpr extends @ql_predicate_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PredicateExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_predicate_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_predicate_expr_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_predicate_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_predicate_expr_child(this, _, result) } } /** A class representing `predicateName` tokens. */ - final class PredicateName extends @ql_token_predicate_name, TokenImpl { + class PredicateName extends @ql_token_predicate_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PredicateName" } } /** A class representing `prefix_cast` nodes. */ - final class PrefixCast extends @ql_prefix_cast, AstNodeImpl { + class PrefixCast extends @ql_prefix_cast, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrefixCast" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_prefix_cast_child(this, i, result) } + final F::AstNode getChild(int i) { ql_prefix_cast_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_prefix_cast_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_prefix_cast_child(this, _, result) } } /** A class representing `primitiveType` tokens. */ - final class PrimitiveType extends @ql_token_primitive_type, TokenImpl { + class PrimitiveType extends @ql_token_primitive_type, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrimitiveType" } } /** A class representing `ql` nodes. */ - final class Ql extends @ql_ql, AstNodeImpl { + class Ql extends @ql_ql, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Ql" } /** Gets the `i`th child of this node. */ - final ModuleMember getChild(int i) { ql_ql_child(this, i, result) } + final F::ModuleMember getChild(int i) { ql_ql_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::ModuleMember getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_ql_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_ql_child(this, _, result) } } /** A class representing `qldoc` tokens. */ - final class Qldoc extends @ql_token_qldoc, TokenImpl { + class Qldoc extends @ql_token_qldoc, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Qldoc" } } /** A class representing `qualifiedRhs` nodes. */ - final class QualifiedRhs extends @ql_qualified_rhs, AstNodeImpl { + class QualifiedRhs extends @ql_qualified_rhs, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "QualifiedRhs" } /** Gets the node corresponding to the field `name`. */ - final PredicateName getName() { ql_qualified_rhs_name(this, result) } + final F::PredicateName getName() { ql_qualified_rhs_name(this, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getChild(int i) { ql_qualified_rhs_child(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_qualified_rhs_child(this, i, result) } + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_qualified_rhs_name(this, result) or ql_qualified_rhs_child(this, _, result) } } /** A class representing `qualified_expr` nodes. */ - final class QualifiedExpr extends @ql_qualified_expr, AstNodeImpl { + class QualifiedExpr extends @ql_qualified_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "QualifiedExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_qualified_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_qualified_expr_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_qualified_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_qualified_expr_child(this, _, result) } } /** A class representing `quantified` nodes. */ - final class Quantified extends @ql_quantified, AstNodeImpl { + class Quantified extends @ql_quantified, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Quantified" } /** Gets the node corresponding to the field `expr`. */ - final AstNode getExpr() { ql_quantified_expr(this, result) } + final F::AstNode getExpr() { ql_quantified_expr(this, result) } /** Gets the node corresponding to the field `formula`. */ - final AstNode getFormula() { ql_quantified_formula(this, result) } + final F::AstNode getFormula() { ql_quantified_formula(this, result) } /** Gets the node corresponding to the field `range`. */ - final AstNode getRange() { ql_quantified_range(this, result) } + final F::AstNode getRange() { ql_quantified_range(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_quantified_child(this, i, result) } + final F::AstNode getChild(int i) { ql_quantified_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_quantified_expr(this, result) or ql_quantified_formula(this, result) or ql_quantified_range(this, result) or @@ -1055,74 +1151,80 @@ module QL { } /** A class representing `quantifier` tokens. */ - final class Quantifier extends @ql_token_quantifier, TokenImpl { + class Quantifier extends @ql_token_quantifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Quantifier" } } /** A class representing `range` nodes. */ - final class Range extends @ql_range, AstNodeImpl { + class Range extends @ql_range, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Range" } /** Gets the node corresponding to the field `lower`. */ - final AstNode getLower() { ql_range_def(this, result, _) } + final F::AstNode getLower() { ql_range_def(this, result, _) } /** Gets the node corresponding to the field `upper`. */ - final AstNode getUpper() { ql_range_def(this, _, result) } + final F::AstNode getUpper() { ql_range_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_range_def(this, result, _) or ql_range_def(this, _, result) } } /** A class representing `result` tokens. */ - final class Result extends @ql_token_result, TokenImpl { + class Result extends @ql_token_result, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Result" } } /** A class representing `select` nodes. */ - final class Select extends @ql_select, AstNodeImpl { + class Select extends @ql_select, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Select" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_select_child(this, i, result) } + final F::AstNode getChild(int i) { ql_select_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_select_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_select_child(this, _, result) } } /** A class representing `set_literal` nodes. */ - final class SetLiteral extends @ql_set_literal, AstNodeImpl { + class SetLiteral extends @ql_set_literal, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SetLiteral" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_set_literal_child(this, i, result) } + final F::AstNode getChild(int i) { ql_set_literal_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_set_literal_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_set_literal_child(this, _, result) } } /** A class representing `signatureExpr` nodes. */ - final class SignatureExpr extends @ql_signature_expr, AstNodeImpl { + class SignatureExpr extends @ql_signature_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SignatureExpr" } /** Gets the node corresponding to the field `mod_expr`. */ - final ModuleExpr getModExpr() { ql_signature_expr_mod_expr(this, result) } + final F::ModuleExpr getModExpr() { ql_signature_expr_mod_expr(this, result) } /** Gets the node corresponding to the field `predicate`. */ - final PredicateExpr getPredicate() { ql_signature_expr_predicate(this, result) } + final F::PredicateExpr getPredicate() { ql_signature_expr_predicate(this, result) } /** Gets the node corresponding to the field `type_expr`. */ - final TypeExpr getTypeExpr() { ql_signature_expr_type_expr(this, result) } + final F::TypeExpr getTypeExpr() { ql_signature_expr_type_expr(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_signature_expr_mod_expr(this, result) or ql_signature_expr_predicate(this, result) or ql_signature_expr_type_expr(this, result) @@ -1130,93 +1232,96 @@ module QL { } /** A class representing `simpleId` tokens. */ - final class SimpleId extends @ql_token_simple_id, TokenImpl { + class SimpleId extends @ql_token_simple_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SimpleId" } } /** A class representing `specialId` tokens. */ - final class SpecialId extends @ql_token_special_id, TokenImpl { + class SpecialId extends @ql_token_special_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SpecialId" } } /** A class representing `special_call` nodes. */ - final class SpecialCall extends @ql_special_call, AstNodeImpl { + class SpecialCall extends @ql_special_call, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SpecialCall" } /** Gets the child of this node. */ - final SpecialId getChild() { ql_special_call_def(this, result) } + final F::SpecialId getChild() { ql_special_call_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_special_call_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_special_call_def(this, result) } } /** A class representing `string` tokens. */ - final class String extends @ql_token_string, TokenImpl { + class String extends @ql_token_string, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } } /** A class representing `super` tokens. */ - final class Super extends @ql_token_super, TokenImpl { + class Super extends @ql_token_super, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Super" } } /** A class representing `super_ref` nodes. */ - final class SuperRef extends @ql_super_ref, AstNodeImpl { + class SuperRef extends @ql_super_ref, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SuperRef" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_super_ref_child(this, i, result) } + final F::AstNode getChild(int i) { ql_super_ref_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_super_ref_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_super_ref_child(this, _, result) } } /** A class representing `this` tokens. */ - final class This extends @ql_token_this, TokenImpl { + class This extends @ql_token_this, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "This" } } /** A class representing `true` tokens. */ - final class True extends @ql_token_true, TokenImpl { + class True extends @ql_token_true, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } /** A class representing `typeAliasBody` nodes. */ - final class TypeAliasBody extends @ql_type_alias_body, AstNodeImpl { + class TypeAliasBody extends @ql_type_alias_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeAliasBody" } /** Gets the child of this node. */ - final TypeExpr getChild() { ql_type_alias_body_def(this, result) } + final F::TypeExpr getChild() { ql_type_alias_body_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_type_alias_body_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_type_alias_body_def(this, result) } } /** A class representing `typeExpr` nodes. */ - final class TypeExpr extends @ql_type_expr, AstNodeImpl { + class TypeExpr extends @ql_type_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeExpr" } /** Gets the node corresponding to the field `name`. */ - final ClassName getName() { ql_type_expr_name(this, result) } + final F::ClassName getName() { ql_type_expr_name(this, result) } /** Gets the node corresponding to the field `qualifier`. */ - final ModuleExpr getQualifier() { ql_type_expr_qualifier(this, result) } + final F::ModuleExpr getQualifier() { ql_type_expr_qualifier(this, result) } /** Gets the child of this node. */ - final AstNode getChild() { ql_type_expr_child(this, result) } + final F::AstNode getChild() { ql_type_expr_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_type_expr_name(this, result) or ql_type_expr_qualifier(this, result) or ql_type_expr_child(this, result) @@ -1224,57 +1329,69 @@ module QL { } /** A class representing `typeUnionBody` nodes. */ - final class TypeUnionBody extends @ql_type_union_body, AstNodeImpl { + class TypeUnionBody extends @ql_type_union_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeUnionBody" } /** Gets the `i`th child of this node. */ - final TypeExpr getChild(int i) { ql_type_union_body_child(this, i, result) } + final F::TypeExpr getChild(int i) { ql_type_union_body_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::TypeExpr getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_type_union_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_type_union_body_child(this, _, result) } } /** A class representing `unary_expr` nodes. */ - final class UnaryExpr extends @ql_unary_expr, AstNodeImpl { + class UnaryExpr extends @ql_unary_expr, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnaryExpr" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_unary_expr_child(this, i, result) } + final F::AstNode getChild(int i) { ql_unary_expr_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_unary_expr_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_unary_expr_child(this, _, result) } } /** A class representing `underscore` tokens. */ - final class Underscore extends @ql_token_underscore, TokenImpl { + class Underscore extends @ql_token_underscore, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Underscore" } } /** A class representing `unop` tokens. */ - final class Unop extends @ql_token_unop, TokenImpl { + class Unop extends @ql_token_unop, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unop" } } /** A class representing `unqual_agg_body` nodes. */ - final class UnqualAggBody extends @ql_unqual_agg_body, AstNodeImpl { + class UnqualAggBody extends @ql_unqual_agg_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnqualAggBody" } /** Gets the node corresponding to the field `asExprs`. */ - final AstNode getAsExprs(int i) { ql_unqual_agg_body_as_exprs(this, i, result) } + final F::AstNode getAsExprs(int i) { ql_unqual_agg_body_as_exprs(this, i, result) } + + /** Gets the node corresponding to the field `asExprs`. */ + final F::AstNode getAnAsExprs() { result = this.getAsExprs(_) } /** Gets the node corresponding to the field `guard`. */ - final AstNode getGuard() { ql_unqual_agg_body_guard(this, result) } + final F::AstNode getGuard() { ql_unqual_agg_body_guard(this, result) } + + /** Gets the `i`th child of this node. */ + final F::VarDecl getChild(int i) { ql_unqual_agg_body_child(this, i, result) } /** Gets the `i`th child of this node. */ - final VarDecl getChild(int i) { ql_unqual_agg_body_child(this, i, result) } + final F::VarDecl getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ql_unqual_agg_body_as_exprs(this, _, result) or ql_unqual_agg_body_guard(this, result) or ql_unqual_agg_body_child(this, _, result) @@ -1282,45 +1399,48 @@ module QL { } /** A class representing `varDecl` nodes. */ - final class VarDecl extends @ql_var_decl, AstNodeImpl { + class VarDecl extends @ql_var_decl, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VarDecl" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ql_var_decl_child(this, i, result) } + final F::AstNode getChild(int i) { ql_var_decl_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_var_decl_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ql_var_decl_child(this, _, result) } } /** A class representing `varName` nodes. */ - final class VarName extends @ql_var_name, AstNodeImpl { + class VarName extends @ql_var_name, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VarName" } /** Gets the child of this node. */ - final SimpleId getChild() { ql_var_name_def(this, result) } + final F::SimpleId getChild() { ql_var_name_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_var_name_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_var_name_def(this, result) } } /** A class representing `variable` nodes. */ - final class Variable extends @ql_variable, AstNodeImpl { + class Variable extends @ql_variable, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Variable" } /** Gets the child of this node. */ - final AstNode getChild() { ql_variable_def(this, result) } + final F::AstNode getChild() { ql_variable_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ql_variable_def(this, result) } + final override F::AstNode getAFieldOrChild() { ql_variable_def(this, result) } } /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(AddExpr).getLeft() and i = -1 and name = "getLeft" or result = node.(AddExpr).getRight() and i = -1 and name = "getRight" @@ -1556,10 +1676,218 @@ module QL { } } +module QLFinal { + private module F = QL; + + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class AddExpr = F::AddExpr; + + final class Addop = F::Addop; + + final class AggId = F::AggId; + + final class Aggregate = F::Aggregate; + + final class AnnotArg = F::AnnotArg; + + final class AnnotName = F::AnnotName; + + final class Annotation = F::Annotation; + + final class AritylessPredicateExpr = F::AritylessPredicateExpr; + + final class AsExpr = F::AsExpr; + + final class AsExprs = F::AsExprs; + + final class BlockComment = F::BlockComment; + + final class Body = F::Body; + + final class Bool = F::Bool; + + final class CallBody = F::CallBody; + + final class CallOrUnqualAggExpr = F::CallOrUnqualAggExpr; + + final class Charpred = F::Charpred; + + final class ClassMember = F::ClassMember; + + final class ClassName = F::ClassName; + + final class ClasslessPredicate = F::ClasslessPredicate; + + final class Closure = F::Closure; + + final class CompTerm = F::CompTerm; + + final class Compop = F::Compop; + + final class Conjunction = F::Conjunction; + + final class Dataclass = F::Dataclass; + + final class Datatype = F::Datatype; + + final class DatatypeBranch = F::DatatypeBranch; + + final class DatatypeBranches = F::DatatypeBranches; + + final class Dbtype = F::Dbtype; + + final class Direction = F::Direction; + + final class Disjunction = F::Disjunction; + + final class Empty = F::Empty; + + final class ExprAggregateBody = F::ExprAggregateBody; + + final class ExprAnnotation = F::ExprAnnotation; + + final class False = F::False; + + final class Field = F::Field; + + final class Float = F::Float; + + final class FullAggregateBody = F::FullAggregateBody; + + final class HigherOrderTerm = F::HigherOrderTerm; + + final class IfTerm = F::IfTerm; + + final class Implication = F::Implication; + + final class ImportDirective = F::ImportDirective; + + final class ImportModuleExpr = F::ImportModuleExpr; + + final class InExpr = F::InExpr; + + final class InstanceOf = F::InstanceOf; + + final class Integer = F::Integer; + + final class LineComment = F::LineComment; + + final class Literal = F::Literal; + + final class LiteralId = F::LiteralId; + + final class MemberPredicate = F::MemberPredicate; + + final class Module = F::Module; + + final class ModuleAliasBody = F::ModuleAliasBody; + + final class ModuleExpr = F::ModuleExpr; + + final class ModuleInstantiation = F::ModuleInstantiation; + + final class ModuleMember = F::ModuleMember; + + final class ModuleName = F::ModuleName; + + final class ModuleParam = F::ModuleParam; + + final class MulExpr = F::MulExpr; + + final class Mulop = F::Mulop; + + final class Negation = F::Negation; + + final class OrderBy = F::OrderBy; + + final class OrderBys = F::OrderBys; + + final class ParExpr = F::ParExpr; + + final class Predicate = F::Predicate; + + final class PredicateAliasBody = F::PredicateAliasBody; + + final class PredicateExpr = F::PredicateExpr; + + final class PredicateName = F::PredicateName; + + final class PrefixCast = F::PrefixCast; + + final class PrimitiveType = F::PrimitiveType; + + final class Ql = F::Ql; + + final class Qldoc = F::Qldoc; + + final class QualifiedRhs = F::QualifiedRhs; + + final class QualifiedExpr = F::QualifiedExpr; + + final class Quantified = F::Quantified; + + final class Quantifier = F::Quantifier; + + final class Range = F::Range; + + final class Result = F::Result; + + final class Select = F::Select; + + final class SetLiteral = F::SetLiteral; + + final class SignatureExpr = F::SignatureExpr; + + final class SimpleId = F::SimpleId; + + final class SpecialId = F::SpecialId; + + final class SpecialCall = F::SpecialCall; + + final class String = F::String; + + final class Super = F::Super; + + final class SuperRef = F::SuperRef; + + final class This = F::This; + + final class True = F::True; + + final class TypeAliasBody = F::TypeAliasBody; + + final class TypeExpr = F::TypeExpr; + + final class TypeUnionBody = F::TypeUnionBody; + + final class UnaryExpr = F::UnaryExpr; + + final class Underscore = F::Underscore; + + final class Unop = F::Unop; + + final class UnqualAggBody = F::UnqualAggBody; + + final class VarDecl = F::VarDecl; + + final class VarName = F::VarName; + + final class Variable = F::Variable; +} + overlay[local] module Dbscheme { + private module F = Dbscheme; + /** The base class for all AST nodes */ - private class AstNodeImpl extends @dbscheme_ast_node { + class AstNode extends @dbscheme_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -1567,13 +1895,13 @@ module Dbscheme { final L::Location getLocation() { dbscheme_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { dbscheme_ast_node_parent(this, result, _) } + final F::AstNode getParent() { dbscheme_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { dbscheme_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -1582,10 +1910,8 @@ module Dbscheme { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @dbscheme_token, AstNodeImpl { + class Token extends @dbscheme_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { dbscheme_tokeninfo(this, _, result) } @@ -1596,10 +1922,8 @@ module Dbscheme { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @dbscheme_reserved_word, TokenImpl { + class ReservedWord extends @dbscheme_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -1625,91 +1949,102 @@ module Dbscheme { } /** A class representing `annotName` tokens. */ - final class AnnotName extends @dbscheme_token_annot_name, TokenImpl { + class AnnotName extends @dbscheme_token_annot_name, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AnnotName" } } /** A class representing `annotation` nodes. */ - final class Annotation extends @dbscheme_annotation, AstNodeImpl { + class Annotation extends @dbscheme_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Annotation" } /** Gets the node corresponding to the field `argsAnnotation`. */ - final ArgsAnnotation getArgsAnnotation() { dbscheme_annotation_args_annotation(this, result) } + final F::ArgsAnnotation getArgsAnnotation() { + dbscheme_annotation_args_annotation(this, result) + } /** Gets the node corresponding to the field `simpleAnnotation`. */ - final AnnotName getSimpleAnnotation() { dbscheme_annotation_simple_annotation(this, result) } + final F::AnnotName getSimpleAnnotation() { dbscheme_annotation_simple_annotation(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_annotation_args_annotation(this, result) or dbscheme_annotation_simple_annotation(this, result) } } /** A class representing `argsAnnotation` nodes. */ - final class ArgsAnnotation extends @dbscheme_args_annotation, AstNodeImpl { + class ArgsAnnotation extends @dbscheme_args_annotation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArgsAnnotation" } /** Gets the node corresponding to the field `name`. */ - final AnnotName getName() { dbscheme_args_annotation_def(this, result) } + final F::AnnotName getName() { dbscheme_args_annotation_def(this, result) } + + /** Gets the `i`th child of this node. */ + final F::SimpleId getChild(int i) { dbscheme_args_annotation_child(this, i, result) } /** Gets the `i`th child of this node. */ - final SimpleId getChild(int i) { dbscheme_args_annotation_child(this, i, result) } + final F::SimpleId getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_args_annotation_def(this, result) or dbscheme_args_annotation_child(this, _, result) } } /** A class representing `block_comment` tokens. */ - final class BlockComment extends @dbscheme_token_block_comment, TokenImpl { + class BlockComment extends @dbscheme_token_block_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockComment" } } /** A class representing `boolean` tokens. */ - final class Boolean extends @dbscheme_token_boolean, TokenImpl { + class Boolean extends @dbscheme_token_boolean, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Boolean" } } /** A class representing `branch` nodes. */ - final class Branch extends @dbscheme_branch, AstNodeImpl { + class Branch extends @dbscheme_branch, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Branch" } /** Gets the node corresponding to the field `qldoc`. */ - final Qldoc getQldoc() { dbscheme_branch_qldoc(this, result) } + final F::Qldoc getQldoc() { dbscheme_branch_qldoc(this, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getChild(int i) { dbscheme_branch_child(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { dbscheme_branch_child(this, i, result) } + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_branch_qldoc(this, result) or dbscheme_branch_child(this, _, result) } } /** A class representing `caseDecl` nodes. */ - final class CaseDecl extends @dbscheme_case_decl, AstNodeImpl { + class CaseDecl extends @dbscheme_case_decl, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CaseDecl" } /** Gets the node corresponding to the field `base`. */ - final Dbtype getBase() { dbscheme_case_decl_def(this, result, _) } + final F::Dbtype getBase() { dbscheme_case_decl_def(this, result, _) } /** Gets the node corresponding to the field `discriminator`. */ - final SimpleId getDiscriminator() { dbscheme_case_decl_def(this, _, result) } + final F::SimpleId getDiscriminator() { dbscheme_case_decl_def(this, _, result) } /** Gets the `i`th child of this node. */ - final Branch getChild(int i) { dbscheme_case_decl_child(this, i, result) } + final F::Branch getChild(int i) { dbscheme_case_decl_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::Branch getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_case_decl_def(this, result, _) or dbscheme_case_decl_def(this, _, result) or dbscheme_case_decl_child(this, _, result) @@ -1717,42 +2052,42 @@ module Dbscheme { } /** A class representing `colType` nodes. */ - final class ColType extends @dbscheme_col_type, AstNodeImpl { + class ColType extends @dbscheme_col_type, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ColType" } /** Gets the child of this node. */ - final AstNode getChild() { dbscheme_col_type_def(this, result) } + final F::AstNode getChild() { dbscheme_col_type_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_col_type_def(this, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_col_type_def(this, result) } } /** A class representing `column` nodes. */ - final class Column extends @dbscheme_column, AstNodeImpl { + class Column extends @dbscheme_column, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Column" } /** Gets the node corresponding to the field `colName`. */ - final SimpleId getColName() { dbscheme_column_def(this, result, _, _) } + final F::SimpleId getColName() { dbscheme_column_def(this, result, _, _) } /** Gets the node corresponding to the field `colType`. */ - final ColType getColType() { dbscheme_column_def(this, _, result, _) } + final F::ColType getColType() { dbscheme_column_def(this, _, result, _) } /** Gets the node corresponding to the field `isRef`. */ - final Ref getIsRef() { dbscheme_column_is_ref(this, result) } + final F::Ref getIsRef() { dbscheme_column_is_ref(this, result) } /** Gets the node corresponding to the field `isUnique`. */ - final Unique getIsUnique() { dbscheme_column_is_unique(this, result) } + final F::Unique getIsUnique() { dbscheme_column_is_unique(this, result) } /** Gets the node corresponding to the field `qldoc`. */ - final Qldoc getQldoc() { dbscheme_column_qldoc(this, result) } + final F::Qldoc getQldoc() { dbscheme_column_qldoc(this, result) } /** Gets the node corresponding to the field `reprType`. */ - final ReprType getReprType() { dbscheme_column_def(this, _, _, result) } + final F::ReprType getReprType() { dbscheme_column_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_column_def(this, result, _, _) or dbscheme_column_def(this, _, result, _) or dbscheme_column_is_ref(this, result) or @@ -1763,155 +2098,167 @@ module Dbscheme { } /** A class representing `date` tokens. */ - final class Date extends @dbscheme_token_date, TokenImpl { + class Date extends @dbscheme_token_date, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Date" } } /** A class representing `dbscheme` nodes. */ - final class Dbscheme extends @dbscheme_dbscheme, AstNodeImpl { + class Dbscheme extends @dbscheme_dbscheme, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dbscheme" } /** Gets the `i`th child of this node. */ - final Entry getChild(int i) { dbscheme_dbscheme_child(this, i, result) } + final F::Entry getChild(int i) { dbscheme_dbscheme_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::Entry getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_dbscheme_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_dbscheme_child(this, _, result) } } /** A class representing `dbtype` tokens. */ - final class Dbtype extends @dbscheme_token_dbtype, TokenImpl { + class Dbtype extends @dbscheme_token_dbtype, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Dbtype" } } /** A class representing `entry` nodes. */ - final class Entry extends @dbscheme_entry, AstNodeImpl { + class Entry extends @dbscheme_entry, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Entry" } /** Gets the child of this node. */ - final AstNode getChild() { dbscheme_entry_def(this, result) } + final F::AstNode getChild() { dbscheme_entry_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_entry_def(this, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_entry_def(this, result) } } /** A class representing `float` tokens. */ - final class Float extends @dbscheme_token_float, TokenImpl { + class Float extends @dbscheme_token_float, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Float" } } /** A class representing `int` tokens. */ - final class Int extends @dbscheme_token_int, TokenImpl { + class Int extends @dbscheme_token_int, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Int" } } /** A class representing `integer` tokens. */ - final class Integer extends @dbscheme_token_integer, TokenImpl { + class Integer extends @dbscheme_token_integer, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Integer" } } /** A class representing `line_comment` tokens. */ - final class LineComment extends @dbscheme_token_line_comment, TokenImpl { + class LineComment extends @dbscheme_token_line_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LineComment" } } /** A class representing `qldoc` tokens. */ - final class Qldoc extends @dbscheme_token_qldoc, TokenImpl { + class Qldoc extends @dbscheme_token_qldoc, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Qldoc" } } /** A class representing `ref` tokens. */ - final class Ref extends @dbscheme_token_ref, TokenImpl { + class Ref extends @dbscheme_token_ref, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Ref" } } /** A class representing `reprType` nodes. */ - final class ReprType extends @dbscheme_repr_type, AstNodeImpl { + class ReprType extends @dbscheme_repr_type, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReprType" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { dbscheme_repr_type_child(this, i, result) } + final F::AstNode getChild(int i) { dbscheme_repr_type_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_repr_type_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_repr_type_child(this, _, result) } } /** A class representing `simpleId` tokens. */ - final class SimpleId extends @dbscheme_token_simple_id, TokenImpl { + class SimpleId extends @dbscheme_token_simple_id, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SimpleId" } } /** A class representing `string` tokens. */ - final class String extends @dbscheme_token_string, TokenImpl { + class String extends @dbscheme_token_string, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } } /** A class representing `table` nodes. */ - final class Table extends @dbscheme_table, AstNodeImpl { + class Table extends @dbscheme_table, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Table" } /** Gets the node corresponding to the field `tableName`. */ - final TableName getTableName() { dbscheme_table_def(this, result) } + final F::TableName getTableName() { dbscheme_table_def(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { dbscheme_table_child(this, i, result) } + final F::AstNode getChild(int i) { dbscheme_table_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_table_def(this, result) or dbscheme_table_child(this, _, result) } } /** A class representing `tableName` nodes. */ - final class TableName extends @dbscheme_table_name, AstNodeImpl { + class TableName extends @dbscheme_table_name, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TableName" } /** Gets the child of this node. */ - final SimpleId getChild() { dbscheme_table_name_def(this, result) } + final F::SimpleId getChild() { dbscheme_table_name_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { dbscheme_table_name_def(this, result) } + final override F::AstNode getAFieldOrChild() { dbscheme_table_name_def(this, result) } } /** A class representing `unionDecl` nodes. */ - final class UnionDecl extends @dbscheme_union_decl, AstNodeImpl { + class UnionDecl extends @dbscheme_union_decl, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnionDecl" } /** Gets the node corresponding to the field `base`. */ - final Dbtype getBase() { dbscheme_union_decl_def(this, result) } + final F::Dbtype getBase() { dbscheme_union_decl_def(this, result) } /** Gets the `i`th child of this node. */ - final Dbtype getChild(int i) { dbscheme_union_decl_child(this, i, result) } + final F::Dbtype getChild(int i) { dbscheme_union_decl_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::Dbtype getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { dbscheme_union_decl_def(this, result) or dbscheme_union_decl_child(this, _, result) } } /** A class representing `unique` tokens. */ - final class Unique extends @dbscheme_token_unique, TokenImpl { + class Unique extends @dbscheme_token_unique, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unique" } } /** A class representing `varchar` tokens. */ - final class Varchar extends @dbscheme_token_varchar, TokenImpl { + class Varchar extends @dbscheme_token_varchar, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Varchar" } } @@ -1919,7 +2266,7 @@ module Dbscheme { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(Annotation).getArgsAnnotation() and i = -1 and name = "getArgsAnnotation" or result = node.(Annotation).getSimpleAnnotation() and i = -1 and name = "getSimpleAnnotation" @@ -1971,10 +2318,78 @@ module Dbscheme { } } +module DbschemeFinal { + private module F = Dbscheme; + + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class AnnotName = F::AnnotName; + + final class Annotation = F::Annotation; + + final class ArgsAnnotation = F::ArgsAnnotation; + + final class BlockComment = F::BlockComment; + + final class Boolean = F::Boolean; + + final class Branch = F::Branch; + + final class CaseDecl = F::CaseDecl; + + final class ColType = F::ColType; + + final class Column = F::Column; + + final class Date = F::Date; + + final class Dbscheme = F::Dbscheme; + + final class Dbtype = F::Dbtype; + + final class Entry = F::Entry; + + final class Float = F::Float; + + final class Int = F::Int; + + final class Integer = F::Integer; + + final class LineComment = F::LineComment; + + final class Qldoc = F::Qldoc; + + final class Ref = F::Ref; + + final class ReprType = F::ReprType; + + final class SimpleId = F::SimpleId; + + final class String = F::String; + + final class Table = F::Table; + + final class TableName = F::TableName; + + final class UnionDecl = F::UnionDecl; + + final class Unique = F::Unique; + + final class Varchar = F::Varchar; +} + overlay[local] module Blame { + private module F = Blame; + /** The base class for all AST nodes */ - private class AstNodeImpl extends @blame_ast_node { + class AstNode extends @blame_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -1982,13 +2397,13 @@ module Blame { final L::Location getLocation() { blame_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { blame_ast_node_parent(this, result, _) } + final F::AstNode getParent() { blame_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { blame_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -1997,10 +2412,8 @@ module Blame { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @blame_token, AstNodeImpl { + class Token extends @blame_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { blame_tokeninfo(this, _, result) } @@ -2011,10 +2424,8 @@ module Blame { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @blame_reserved_word, TokenImpl { + class ReservedWord extends @blame_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -2040,70 +2451,79 @@ module Blame { } /** A class representing `blame_entry` nodes. */ - final class BlameEntry extends @blame_blame_entry, AstNodeImpl { + class BlameEntry extends @blame_blame_entry, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlameEntry" } /** Gets the node corresponding to the field `date`. */ - final Date getDate() { blame_blame_entry_def(this, result) } + final F::Date getDate() { blame_blame_entry_def(this, result) } + + /** Gets the node corresponding to the field `line`. */ + final F::Number getLine(int i) { blame_blame_entry_line(this, i, result) } /** Gets the node corresponding to the field `line`. */ - final Number getLine(int i) { blame_blame_entry_line(this, i, result) } + final F::Number getALine() { result = this.getLine(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { blame_blame_entry_def(this, result) or blame_blame_entry_line(this, _, result) } } /** A class representing `blame_info` nodes. */ - final class BlameInfo extends @blame_blame_info, AstNodeImpl { + class BlameInfo extends @blame_blame_info, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlameInfo" } /** Gets the node corresponding to the field `file_entry`. */ - final FileEntry getFileEntry(int i) { blame_blame_info_file_entry(this, i, result) } + final F::FileEntry getFileEntry(int i) { blame_blame_info_file_entry(this, i, result) } + + /** Gets the node corresponding to the field `file_entry`. */ + final F::FileEntry getAFileEntry() { result = this.getFileEntry(_) } /** Gets the node corresponding to the field `today`. */ - final Date getToday() { blame_blame_info_def(this, result) } + final F::Date getToday() { blame_blame_info_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { blame_blame_info_file_entry(this, _, result) or blame_blame_info_def(this, result) } } /** A class representing `date` tokens. */ - final class Date extends @blame_token_date, TokenImpl { + class Date extends @blame_token_date, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Date" } } /** A class representing `file_entry` nodes. */ - final class FileEntry extends @blame_file_entry, AstNodeImpl { + class FileEntry extends @blame_file_entry, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FileEntry" } /** Gets the node corresponding to the field `blame_entry`. */ - final BlameEntry getBlameEntry(int i) { blame_file_entry_blame_entry(this, i, result) } + final F::BlameEntry getBlameEntry(int i) { blame_file_entry_blame_entry(this, i, result) } + + /** Gets the node corresponding to the field `blame_entry`. */ + final F::BlameEntry getABlameEntry() { result = this.getBlameEntry(_) } /** Gets the node corresponding to the field `file_name`. */ - final Filename getFileName() { blame_file_entry_def(this, result) } + final F::Filename getFileName() { blame_file_entry_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { blame_file_entry_blame_entry(this, _, result) or blame_file_entry_def(this, result) } } /** A class representing `filename` tokens. */ - final class Filename extends @blame_token_filename, TokenImpl { + class Filename extends @blame_token_filename, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Filename" } } /** A class representing `number` tokens. */ - final class Number extends @blame_token_number, TokenImpl { + class Number extends @blame_token_number, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Number" } } @@ -2111,7 +2531,7 @@ module Blame { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(BlameEntry).getDate() and i = -1 and name = "getDate" or result = node.(BlameEntry).getLine(i) and name = "getLine" @@ -2127,10 +2547,36 @@ module Blame { } } +module BlameFinal { + private module F = Blame; + + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class BlameEntry = F::BlameEntry; + + final class BlameInfo = F::BlameInfo; + + final class Date = F::Date; + + final class FileEntry = F::FileEntry; + + final class Filename = F::Filename; + + final class Number = F::Number; +} + overlay[local] module JSON { + private module F = JSON; + /** The base class for all AST nodes */ - private class AstNodeImpl extends @json_ast_node { + class AstNode extends @json_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -2138,13 +2584,13 @@ module JSON { final L::Location getLocation() { json_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { json_ast_node_parent(this, result, _) } + final F::AstNode getParent() { json_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { json_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -2153,10 +2599,8 @@ module JSON { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @json_token, AstNodeImpl { + class Token extends @json_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { json_tokeninfo(this, _, result) } @@ -2167,10 +2611,8 @@ module JSON { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @json_reserved_word, TokenImpl { + class ReservedWord extends @json_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -2195,111 +2637,123 @@ module JSON { ) } - final class UnderscoreValue extends @json_underscore_value, AstNodeImpl { } + class UnderscoreValue extends @json_underscore_value, F::AstNode { } /** A class representing `array` nodes. */ - final class Array extends @json_array, AstNodeImpl { + class Array extends @json_array, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Array" } /** Gets the `i`th child of this node. */ - final UnderscoreValue getChild(int i) { json_array_child(this, i, result) } + final F::UnderscoreValue getChild(int i) { json_array_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::UnderscoreValue getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_array_child(this, _, result) } } /** A class representing `comment` tokens. */ - final class Comment extends @json_token_comment, TokenImpl { + class Comment extends @json_token_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Comment" } } /** A class representing `document` nodes. */ - final class Document extends @json_document, AstNodeImpl { + class Document extends @json_document, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Document" } /** Gets the `i`th child of this node. */ - final UnderscoreValue getChild(int i) { json_document_child(this, i, result) } + final F::UnderscoreValue getChild(int i) { json_document_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::UnderscoreValue getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_document_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_document_child(this, _, result) } } /** A class representing `escape_sequence` tokens. */ - final class EscapeSequence extends @json_token_escape_sequence, TokenImpl { + class EscapeSequence extends @json_token_escape_sequence, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EscapeSequence" } } /** A class representing `false` tokens. */ - final class False extends @json_token_false, TokenImpl { + class False extends @json_token_false, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "False" } } /** A class representing `null` tokens. */ - final class Null extends @json_token_null, TokenImpl { + class Null extends @json_token_null, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Null" } } /** A class representing `number` tokens. */ - final class Number extends @json_token_number, TokenImpl { + class Number extends @json_token_number, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Number" } } /** A class representing `object` nodes. */ - final class Object extends @json_object, AstNodeImpl { + class Object extends @json_object, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Object" } /** Gets the `i`th child of this node. */ - final Pair getChild(int i) { json_object_child(this, i, result) } + final F::Pair getChild(int i) { json_object_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::Pair getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_object_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_object_child(this, _, result) } } /** A class representing `pair` nodes. */ - final class Pair extends @json_pair, AstNodeImpl { + class Pair extends @json_pair, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Pair" } /** Gets the node corresponding to the field `key`. */ - final String getKey() { json_pair_def(this, result, _) } + final F::String getKey() { json_pair_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreValue getValue() { json_pair_def(this, _, result) } + final F::UnderscoreValue getValue() { json_pair_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { json_pair_def(this, result, _) or json_pair_def(this, _, result) } } /** A class representing `string` nodes. */ - final class String extends @json_string__, AstNodeImpl { + class String extends @json_string__, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { json_string_child(this, i, result) } + final F::AstNode getChild(int i) { json_string_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { json_string_child(this, _, result) } } /** A class representing `string_content` tokens. */ - final class StringContent extends @json_token_string_content, TokenImpl { + class StringContent extends @json_token_string_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringContent" } } /** A class representing `true` tokens. */ - final class True extends @json_token_true, TokenImpl { + class True extends @json_token_true, F::Token, F::UnderscoreValue { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } @@ -2307,7 +2761,7 @@ module JSON { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(Array).getChild(i) and name = "getChild" or result = node.(Document).getChild(i) and name = "getChild" @@ -2322,3 +2776,41 @@ module JSON { } } } + +module JSONFinal { + private module F = JSON; + + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class UnderscoreValue = F::UnderscoreValue; + + final class Array = F::Array; + + final class Comment = F::Comment; + + final class Document = F::Document; + + final class EscapeSequence = F::EscapeSequence; + + final class False = F::False; + + final class Null = F::Null; + + final class Number = F::Number; + + final class Object = F::Object; + + final class Pair = F::Pair; + + final class String = F::String; + + final class StringContent = F::StringContent; + + final class True = F::True; +} diff --git a/ruby/extractor/src/extractor.rs b/ruby/extractor/src/extractor.rs index d418c144bfc9..3749609e7885 100644 --- a/ruby/extractor/src/extractor.rs +++ b/ruby/extractor/src/extractor.rs @@ -94,7 +94,9 @@ pub fn run(options: Options) -> std::io::Result<()> { node_types::read_node_types_str("erb", tree_sitter_embedded_template::NODE_TYPES)?; let lines: std::io::Result> = std::io::BufReader::new(file_list).lines().collect(); let lines = lines?; - let source_root = std::env::current_dir().ok().and_then(|d| d.canonicalize().ok()); + let source_root = std::env::current_dir() + .ok() + .and_then(|d| d.canonicalize().ok()); lines .par_iter() .try_for_each(|line| { @@ -126,7 +128,6 @@ pub fn run(options: Options) -> std::io::Result<()> { &path, &source, &[], - None, ); let (ranges, line_breaks) = scan_erb( @@ -215,7 +216,6 @@ pub fn run(options: Options) -> std::io::Result<()> { &path, &source, &code_ranges, - None, ); std::fs::create_dir_all(src_archive_file.parent().unwrap())?; if needs_conversion { diff --git a/ruby/extractor/src/generator.rs b/ruby/extractor/src/generator.rs index 0430afd103e7..0fc6f9d5cc74 100644 --- a/ruby/extractor/src/generator.rs +++ b/ruby/extractor/src/generator.rs @@ -34,6 +34,7 @@ pub fn run(options: Options) -> std::io::Result<()> { languages, options.dbscheme, options.library, + false, // do not use facade AST "run 'make dbscheme' in ql/ruby/", ) } diff --git a/ruby/ql/integration-tests/subst/file.expected b/ruby/ql/integration-tests/subst/file.expected index 47b324fea9e9..2962c283b484 100644 --- a/ruby/ql/integration-tests/subst/file.expected +++ b/ruby/ql/integration-tests/subst/file.expected @@ -1,2 +1,2 @@ -| code/test.rb:0:0:0:0 | code/test.rb | | +| code/test.rb:0:0:0:0 | code/test.rb | relative | | file://:0:0:0:0 | | | diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index d79eaed159e4..55c64cb527cb 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 6.0.3 + +### Minor Analysis Improvements + +* Parameters of methods exported by vendored gems are no longer treated as flow sources, since such methods are only called from within the codebase. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` in codebases that vendor their dependencies. + ## 6.0.2 No user-facing changes. diff --git a/ruby/ql/lib/change-notes/released/6.0.3.md b/ruby/ql/lib/change-notes/released/6.0.3.md new file mode 100644 index 000000000000..81e3925ea383 --- /dev/null +++ b/ruby/ql/lib/change-notes/released/6.0.3.md @@ -0,0 +1,5 @@ +## 6.0.3 + +### Minor Analysis Improvements + +* Removed library input to vendored gems from the set of taint sources. This should reduce false positives for `rb/polynomial-redos`, `rb/regex/badly-anchored-regexp`, `rb/unsafe-code-construction`, `rb/html-constructed-from-input`, and `rb/shell-command-constructed-from-input` whenever vendoring is used. diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 70437ec53b89..304c17ad4092 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 6.0.2 +lastReleaseVersion: 6.0.3 diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll index 13ae1923b105..0d442a5dda88 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll @@ -25,8 +25,10 @@ private predicate discardLocation(@location_default loc) { overlay[local] module Ruby { + private module F = Ruby; + /** The base class for all AST nodes */ - private class AstNodeImpl extends @ruby_ast_node { + class AstNode extends @ruby_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -34,13 +36,13 @@ module Ruby { final L::Location getLocation() { ruby_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { ruby_ast_node_parent(this, result, _) } + final F::AstNode getParent() { ruby_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { ruby_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -49,10 +51,8 @@ module Ruby { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @ruby_token, AstNodeImpl { + class Token extends @ruby_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { ruby_tokeninfo(this, _, result) } @@ -63,10 +63,8 @@ module Ruby { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @ruby_reserved_word, TokenImpl { + class ReservedWord extends @ruby_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -91,202 +89,236 @@ module Ruby { ) } - final class UnderscoreArg extends @ruby_underscore_arg, AstNodeImpl { } + class UnderscoreArg extends @ruby_underscore_arg, F::UnderscoreExpression { } - final class UnderscoreCallOperator extends @ruby_underscore_call_operator, AstNodeImpl { } + class UnderscoreCallOperator extends @ruby_underscore_call_operator, F::AstNode { } - final class UnderscoreExpression extends @ruby_underscore_expression, AstNodeImpl { } + class UnderscoreExpression extends @ruby_underscore_expression, F::UnderscoreStatement { } - final class UnderscoreLhs extends @ruby_underscore_lhs, AstNodeImpl { } + class UnderscoreLhs extends @ruby_underscore_lhs, F::UnderscorePrimary { } - final class UnderscoreMethodName extends @ruby_underscore_method_name, AstNodeImpl { } + class UnderscoreMethodName extends @ruby_underscore_method_name, F::AstNode { } - final class UnderscoreNonlocalVariable extends @ruby_underscore_nonlocal_variable, AstNodeImpl { } - - final class UnderscorePatternConstant extends @ruby_underscore_pattern_constant, AstNodeImpl { } + class UnderscoreNonlocalVariable extends @ruby_underscore_nonlocal_variable, + F::UnderscoreMethodName, F::UnderscoreVariable + { } - final class UnderscorePatternExpr extends @ruby_underscore_pattern_expr, AstNodeImpl { } + class UnderscorePatternConstant extends @ruby_underscore_pattern_constant, + F::UnderscorePatternExprBasic + { } - final class UnderscorePatternExprBasic extends @ruby_underscore_pattern_expr_basic, AstNodeImpl { - } + class UnderscorePatternExpr extends @ruby_underscore_pattern_expr, F::UnderscorePatternTopExprBody + { } - final class UnderscorePatternPrimitive extends @ruby_underscore_pattern_primitive, AstNodeImpl { } + class UnderscorePatternExprBasic extends @ruby_underscore_pattern_expr_basic, + F::UnderscorePatternExpr + { } - final class UnderscorePatternTopExprBody extends @ruby_underscore_pattern_top_expr_body, - AstNodeImpl + class UnderscorePatternPrimitive extends @ruby_underscore_pattern_primitive, + F::UnderscorePatternExprBasic { } - final class UnderscorePrimary extends @ruby_underscore_primary, AstNodeImpl { } + class UnderscorePatternTopExprBody extends @ruby_underscore_pattern_top_expr_body, F::AstNode { } - final class UnderscoreSimpleNumeric extends @ruby_underscore_simple_numeric, AstNodeImpl { } + class UnderscorePrimary extends @ruby_underscore_primary, F::UnderscoreArg { } - final class UnderscoreStatement extends @ruby_underscore_statement, AstNodeImpl { } + class UnderscoreSimpleNumeric extends @ruby_underscore_simple_numeric, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { } + + class UnderscoreStatement extends @ruby_underscore_statement, F::AstNode { } - final class UnderscoreVariable extends @ruby_underscore_variable, AstNodeImpl { } + class UnderscoreVariable extends @ruby_underscore_variable, F::UnderscoreLhs { } /** A class representing `alias` nodes. */ - final class Alias extends @ruby_alias, AstNodeImpl { + class Alias extends @ruby_alias, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Alias" } /** Gets the node corresponding to the field `alias`. */ - final UnderscoreMethodName getAlias() { ruby_alias_def(this, result, _) } + final F::UnderscoreMethodName getAlias() { ruby_alias_def(this, result, _) } /** Gets the node corresponding to the field `name`. */ - final UnderscoreMethodName getName() { ruby_alias_def(this, _, result) } + final F::UnderscoreMethodName getName() { ruby_alias_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_alias_def(this, result, _) or ruby_alias_def(this, _, result) } } /** A class representing `alternative_pattern` nodes. */ - final class AlternativePattern extends @ruby_alternative_pattern, AstNodeImpl { + class AlternativePattern extends @ruby_alternative_pattern, F::UnderscorePatternExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AlternativePattern" } /** Gets the node corresponding to the field `alternatives`. */ - final UnderscorePatternExprBasic getAlternatives(int i) { + final F::UnderscorePatternExprBasic getAlternatives(int i) { ruby_alternative_pattern_alternatives(this, i, result) } + /** Gets the node corresponding to the field `alternatives`. */ + final F::UnderscorePatternExprBasic getAnAlternatives() { result = this.getAlternatives(_) } + /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_alternative_pattern_alternatives(this, _, result) } } /** A class representing `argument_list` nodes. */ - final class ArgumentList extends @ruby_argument_list, AstNodeImpl { + class ArgumentList extends @ruby_argument_list, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArgumentList" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_argument_list_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_argument_list_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_argument_list_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_argument_list_child(this, _, result) } } /** A class representing `array` nodes. */ - final class Array extends @ruby_array, AstNodeImpl { + class Array extends @ruby_array, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Array" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_array_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_array_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_array_child(this, _, result) } } /** A class representing `array_pattern` nodes. */ - final class ArrayPattern extends @ruby_array_pattern, AstNodeImpl { + class ArrayPattern extends @ruby_array_pattern, F::UnderscorePatternExprBasic, + F::UnderscorePatternTopExprBody + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArrayPattern" } /** Gets the node corresponding to the field `class`. */ - final UnderscorePatternConstant getClass() { ruby_array_pattern_class(this, result) } + final F::UnderscorePatternConstant getClass() { ruby_array_pattern_class(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_array_pattern_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_array_pattern_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_array_pattern_class(this, result) or ruby_array_pattern_child(this, _, result) } } /** A class representing `as_pattern` nodes. */ - final class AsPattern extends @ruby_as_pattern, AstNodeImpl { + class AsPattern extends @ruby_as_pattern, F::UnderscorePatternExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AsPattern" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_as_pattern_def(this, result, _) } + final F::Identifier getName() { ruby_as_pattern_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscorePatternExpr getValue() { ruby_as_pattern_def(this, _, result) } + final F::UnderscorePatternExpr getValue() { ruby_as_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_as_pattern_def(this, result, _) or ruby_as_pattern_def(this, _, result) } } /** A class representing `assignment` nodes. */ - final class Assignment extends @ruby_assignment, AstNodeImpl { + class Assignment extends @ruby_assignment, F::UnderscoreArg, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Assignment" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ruby_assignment_def(this, result, _) } + final F::AstNode getLeft() { ruby_assignment_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ruby_assignment_def(this, _, result) } + final F::AstNode getRight() { ruby_assignment_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_assignment_def(this, result, _) or ruby_assignment_def(this, _, result) } } /** A class representing `bare_string` nodes. */ - final class BareString extends @ruby_bare_string, AstNodeImpl { + class BareString extends @ruby_bare_string, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BareString" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_bare_string_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_bare_string_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_bare_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_bare_string_child(this, _, result) } } /** A class representing `bare_symbol` nodes. */ - final class BareSymbol extends @ruby_bare_symbol, AstNodeImpl { + class BareSymbol extends @ruby_bare_symbol, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BareSymbol" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_bare_symbol_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_bare_symbol_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_bare_symbol_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_bare_symbol_child(this, _, result) } } /** A class representing `begin` nodes. */ - final class Begin extends @ruby_begin, AstNodeImpl { + class Begin extends @ruby_begin, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Begin" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_begin_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_begin_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_begin_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_begin_child(this, _, result) } } /** A class representing `begin_block` nodes. */ - final class BeginBlock extends @ruby_begin_block, AstNodeImpl { + class BeginBlock extends @ruby_begin_block, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BeginBlock" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_begin_block_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_begin_block_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_begin_block_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_begin_block_child(this, _, result) } } /** A class representing `binary` nodes. */ - final class Binary extends @ruby_binary, AstNodeImpl { + class Binary extends @ruby_binary, F::UnderscoreArg, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Binary" } /** Gets the node corresponding to the field `left`. */ - final AstNode getLeft() { ruby_binary_def(this, result, _, _) } + final F::AstNode getLeft() { ruby_binary_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -344,130 +376,142 @@ module Ruby { } /** Gets the node corresponding to the field `right`. */ - final UnderscoreExpression getRight() { ruby_binary_def(this, _, _, result) } + final F::UnderscoreExpression getRight() { ruby_binary_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_binary_def(this, result, _, _) or ruby_binary_def(this, _, _, result) } } /** A class representing `block` nodes. */ - final class Block extends @ruby_block, AstNodeImpl { + class Block extends @ruby_block, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Block" } /** Gets the node corresponding to the field `body`. */ - final BlockBody getBody() { ruby_block_body(this, result) } + final F::BlockBody getBody() { ruby_block_body(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final BlockParameters getParameters() { ruby_block_parameters(this, result) } + final F::BlockParameters getParameters() { ruby_block_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_block_body(this, result) or ruby_block_parameters(this, result) } } /** A class representing `block_argument` nodes. */ - final class BlockArgument extends @ruby_block_argument, AstNodeImpl { + class BlockArgument extends @ruby_block_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockArgument" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_block_argument_child(this, result) } + final F::UnderscoreArg getChild() { ruby_block_argument_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_argument_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_block_argument_child(this, result) } } /** A class representing `block_body` nodes. */ - final class BlockBody extends @ruby_block_body, AstNodeImpl { + class BlockBody extends @ruby_block_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockBody" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_block_body_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_block_body_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_block_body_child(this, _, result) } } /** A class representing `block_parameter` nodes. */ - final class BlockParameter extends @ruby_block_parameter, AstNodeImpl { + class BlockParameter extends @ruby_block_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_block_parameter_name(this, result) } + final F::Identifier getName() { ruby_block_parameter_name(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_block_parameter_name(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_block_parameter_name(this, result) } } /** A class representing `block_parameters` nodes. */ - final class BlockParameters extends @ruby_block_parameters, AstNodeImpl { + class BlockParameters extends @ruby_block_parameters, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BlockParameters" } /** Gets the node corresponding to the field `locals`. */ - final Identifier getLocals(int i) { ruby_block_parameters_locals(this, i, result) } + final F::Identifier getLocals(int i) { ruby_block_parameters_locals(this, i, result) } + + /** Gets the node corresponding to the field `locals`. */ + final F::Identifier getALocals() { result = this.getLocals(_) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_block_parameters_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_block_parameters_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_block_parameters_locals(this, _, result) or ruby_block_parameters_child(this, _, result) } } /** A class representing `body_statement` nodes. */ - final class BodyStatement extends @ruby_body_statement, AstNodeImpl { + class BodyStatement extends @ruby_body_statement, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BodyStatement" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_body_statement_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_body_statement_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_body_statement_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_body_statement_child(this, _, result) } } /** A class representing `break` nodes. */ - final class Break extends @ruby_break, AstNodeImpl { + class Break extends @ruby_break, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Break" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_break_child(this, result) } + final F::ArgumentList getChild() { ruby_break_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_break_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_break_child(this, result) } } /** A class representing `call` nodes. */ - final class Call extends @ruby_call, AstNodeImpl { + class Call extends @ruby_call, F::UnderscoreExpression, F::UnderscoreLhs, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Call" } /** Gets the node corresponding to the field `arguments`. */ - final ArgumentList getArguments() { ruby_call_arguments(this, result) } + final F::ArgumentList getArguments() { ruby_call_arguments(this, result) } /** Gets the node corresponding to the field `block`. */ - final AstNode getBlock() { ruby_call_block(this, result) } + final F::AstNode getBlock() { ruby_call_block(this, result) } /** Gets the node corresponding to the field `method`. */ - final AstNode getMethod() { ruby_call_method(this, result) } + final F::AstNode getMethod() { ruby_call_method(this, result) } /** Gets the node corresponding to the field `operator`. */ - final UnderscoreCallOperator getOperator() { ruby_call_operator(this, result) } + final F::UnderscoreCallOperator getOperator() { ruby_call_operator(this, result) } /** Gets the node corresponding to the field `receiver`. */ - final UnderscorePrimary getReceiver() { ruby_call_receiver(this, result) } + final F::UnderscorePrimary getReceiver() { ruby_call_receiver(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_call_arguments(this, result) or ruby_call_block(this, result) or ruby_call_method(this, result) or @@ -477,38 +521,44 @@ module Ruby { } /** A class representing `case` nodes. */ - final class Case extends @ruby_case__, AstNodeImpl { + class Case extends @ruby_case__, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Case" } /** Gets the node corresponding to the field `value`. */ - final UnderscoreStatement getValue() { ruby_case_value(this, result) } + final F::UnderscoreStatement getValue() { ruby_case_value(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_case_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_case_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_case_value(this, result) or ruby_case_child(this, _, result) } } /** A class representing `case_match` nodes. */ - final class CaseMatch extends @ruby_case_match, AstNodeImpl { + class CaseMatch extends @ruby_case_match, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CaseMatch" } /** Gets the node corresponding to the field `clauses`. */ - final InClause getClauses(int i) { ruby_case_match_clauses(this, i, result) } + final F::InClause getClauses(int i) { ruby_case_match_clauses(this, i, result) } + + /** Gets the node corresponding to the field `clauses`. */ + final F::InClause getAClauses() { result = this.getClauses(_) } /** Gets the node corresponding to the field `else`. */ - final Else getElse() { ruby_case_match_else(this, result) } + final F::Else getElse() { ruby_case_match_else(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreStatement getValue() { ruby_case_match_def(this, result) } + final F::UnderscoreStatement getValue() { ruby_case_match_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_case_match_clauses(this, _, result) or ruby_case_match_else(this, result) or ruby_case_match_def(this, result) @@ -516,39 +566,42 @@ module Ruby { } /** A class representing `chained_string` nodes. */ - final class ChainedString extends @ruby_chained_string, AstNodeImpl { + class ChainedString extends @ruby_chained_string, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ChainedString" } /** Gets the `i`th child of this node. */ - final String getChild(int i) { ruby_chained_string_child(this, i, result) } + final F::String getChild(int i) { ruby_chained_string_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::String getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_chained_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_chained_string_child(this, _, result) } } /** A class representing `character` tokens. */ - final class Character extends @ruby_token_character, TokenImpl { + class Character extends @ruby_token_character, F::Token, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Character" } } /** A class representing `class` nodes. */ - final class Class extends @ruby_class, AstNodeImpl { + class Class extends @ruby_class, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Class" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_class_body(this, result) } + final F::BodyStatement getBody() { ruby_class_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_class_def(this, result) } + final F::AstNode getName() { ruby_class_def(this, result) } /** Gets the node corresponding to the field `superclass`. */ - final Superclass getSuperclass() { ruby_class_superclass(this, result) } + final F::Superclass getSuperclass() { ruby_class_superclass(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_class_body(this, result) or ruby_class_def(this, result) or ruby_class_superclass(this, result) @@ -556,45 +609,45 @@ module Ruby { } /** A class representing `class_variable` tokens. */ - final class ClassVariable extends @ruby_token_class_variable, TokenImpl { + class ClassVariable extends @ruby_token_class_variable, F::Token, F::UnderscoreNonlocalVariable { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassVariable" } } /** A class representing `comment` tokens. */ - final class Comment extends @ruby_token_comment, TokenImpl { + class Comment extends @ruby_token_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Comment" } } /** A class representing `complex` nodes. */ - final class Complex extends @ruby_complex, AstNodeImpl { + class Complex extends @ruby_complex, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Complex" } /** Gets the child of this node. */ - final AstNode getChild() { ruby_complex_def(this, result) } + final F::AstNode getChild() { ruby_complex_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_complex_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_complex_def(this, result) } } /** A class representing `conditional` nodes. */ - final class Conditional extends @ruby_conditional, AstNodeImpl { + class Conditional extends @ruby_conditional, F::UnderscoreArg { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Conditional" } /** Gets the node corresponding to the field `alternative`. */ - final UnderscoreArg getAlternative() { ruby_conditional_def(this, result, _, _) } + final F::UnderscoreArg getAlternative() { ruby_conditional_def(this, result, _, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreArg getCondition() { ruby_conditional_def(this, _, result, _) } + final F::UnderscoreArg getCondition() { ruby_conditional_def(this, _, result, _) } /** Gets the node corresponding to the field `consequence`. */ - final UnderscoreArg getConsequence() { ruby_conditional_def(this, _, _, result) } + final F::UnderscoreArg getConsequence() { ruby_conditional_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_conditional_def(this, result, _, _) or ruby_conditional_def(this, _, result, _) or ruby_conditional_def(this, _, _, result) @@ -602,94 +655,115 @@ module Ruby { } /** A class representing `constant` tokens. */ - final class Constant extends @ruby_token_constant, TokenImpl { + class Constant extends @ruby_token_constant, F::Token, F::UnderscoreMethodName, + F::UnderscorePatternConstant, F::UnderscoreVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Constant" } } /** A class representing `delimited_symbol` nodes. */ - final class DelimitedSymbol extends @ruby_delimited_symbol, AstNodeImpl { + class DelimitedSymbol extends @ruby_delimited_symbol, F::UnderscoreMethodName, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DelimitedSymbol" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_delimited_symbol_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_delimited_symbol_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_delimited_symbol_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_delimited_symbol_child(this, _, result) } } /** A class representing `destructured_left_assignment` nodes. */ - final class DestructuredLeftAssignment extends @ruby_destructured_left_assignment, AstNodeImpl { + class DestructuredLeftAssignment extends @ruby_destructured_left_assignment, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructuredLeftAssignment" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_destructured_left_assignment_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_destructured_left_assignment_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_destructured_left_assignment_child(this, _, result) } } /** A class representing `destructured_parameter` nodes. */ - final class DestructuredParameter extends @ruby_destructured_parameter, AstNodeImpl { + class DestructuredParameter extends @ruby_destructured_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructuredParameter" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_destructured_parameter_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_destructured_parameter_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_destructured_parameter_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ruby_destructured_parameter_child(this, _, result) + } } /** A class representing `do` nodes. */ - final class Do extends @ruby_do, AstNodeImpl { + class Do extends @ruby_do, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Do" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_do_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_do_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_do_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_do_child(this, _, result) } } /** A class representing `do_block` nodes. */ - final class DoBlock extends @ruby_do_block, AstNodeImpl { + class DoBlock extends @ruby_do_block, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DoBlock" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_do_block_body(this, result) } + final F::BodyStatement getBody() { ruby_do_block_body(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final BlockParameters getParameters() { ruby_do_block_parameters(this, result) } + final F::BlockParameters getParameters() { ruby_do_block_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_do_block_body(this, result) or ruby_do_block_parameters(this, result) } } /** A class representing `element_reference` nodes. */ - final class ElementReference extends @ruby_element_reference, AstNodeImpl { + class ElementReference extends @ruby_element_reference, F::UnderscoreLhs { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ElementReference" } /** Gets the node corresponding to the field `block`. */ - final AstNode getBlock() { ruby_element_reference_block(this, result) } + final F::AstNode getBlock() { ruby_element_reference_block(this, result) } /** Gets the node corresponding to the field `object`. */ - final UnderscorePrimary getObject() { ruby_element_reference_def(this, result) } + final F::UnderscorePrimary getObject() { ruby_element_reference_def(this, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getChild(int i) { ruby_element_reference_child(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_element_reference_child(this, i, result) } + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_element_reference_block(this, result) or ruby_element_reference_def(this, result) or ruby_element_reference_child(this, _, result) @@ -697,33 +771,36 @@ module Ruby { } /** A class representing `else` nodes. */ - final class Else extends @ruby_else, AstNodeImpl { + class Else extends @ruby_else, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Else" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_else_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_else_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_else_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_else_child(this, _, result) } } /** A class representing `elsif` nodes. */ - final class Elsif extends @ruby_elsif, AstNodeImpl { + class Elsif extends @ruby_elsif, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Elsif" } /** Gets the node corresponding to the field `alternative`. */ - final AstNode getAlternative() { ruby_elsif_alternative(this, result) } + final F::AstNode getAlternative() { ruby_elsif_alternative(this, result) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_elsif_def(this, result) } + final F::UnderscoreStatement getCondition() { ruby_elsif_def(this, result) } /** Gets the node corresponding to the field `consequence`. */ - final Then getConsequence() { ruby_elsif_consequence(this, result) } + final F::Then getConsequence() { ruby_elsif_consequence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_elsif_alternative(this, result) or ruby_elsif_def(this, result) or ruby_elsif_consequence(this, result) @@ -731,136 +808,152 @@ module Ruby { } /** A class representing `empty_statement` tokens. */ - final class EmptyStatement extends @ruby_token_empty_statement, TokenImpl { + class EmptyStatement extends @ruby_token_empty_statement, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EmptyStatement" } } /** A class representing `encoding` tokens. */ - final class Encoding extends @ruby_token_encoding, TokenImpl { + class Encoding extends @ruby_token_encoding, F::Token, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Encoding" } } /** A class representing `end_block` nodes. */ - final class EndBlock extends @ruby_end_block, AstNodeImpl { + class EndBlock extends @ruby_end_block, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EndBlock" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_end_block_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_end_block_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_end_block_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_end_block_child(this, _, result) } } /** A class representing `ensure` nodes. */ - final class Ensure extends @ruby_ensure, AstNodeImpl { + class Ensure extends @ruby_ensure, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Ensure" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_ensure_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_ensure_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_ensure_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_ensure_child(this, _, result) } } /** A class representing `escape_sequence` tokens. */ - final class EscapeSequence extends @ruby_token_escape_sequence, TokenImpl { + class EscapeSequence extends @ruby_token_escape_sequence, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EscapeSequence" } } /** A class representing `exception_variable` nodes. */ - final class ExceptionVariable extends @ruby_exception_variable, AstNodeImpl { + class ExceptionVariable extends @ruby_exception_variable, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExceptionVariable" } /** Gets the child of this node. */ - final UnderscoreLhs getChild() { ruby_exception_variable_def(this, result) } + final F::UnderscoreLhs getChild() { ruby_exception_variable_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_exception_variable_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_exception_variable_def(this, result) } } /** A class representing `exceptions` nodes. */ - final class Exceptions extends @ruby_exceptions, AstNodeImpl { + class Exceptions extends @ruby_exceptions, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Exceptions" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_exceptions_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_exceptions_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_exceptions_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_exceptions_child(this, _, result) } } /** A class representing `expression_reference_pattern` nodes. */ - final class ExpressionReferencePattern extends @ruby_expression_reference_pattern, AstNodeImpl { + class ExpressionReferencePattern extends @ruby_expression_reference_pattern, + F::UnderscorePatternExprBasic + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExpressionReferencePattern" } /** Gets the node corresponding to the field `value`. */ - final UnderscoreExpression getValue() { ruby_expression_reference_pattern_def(this, result) } + final F::UnderscoreExpression getValue() { ruby_expression_reference_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_expression_reference_pattern_def(this, result) } } /** A class representing `false` tokens. */ - final class False extends @ruby_token_false, TokenImpl { + class False extends @ruby_token_false, F::Token, F::UnderscoreLhs, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "False" } } /** A class representing `file` tokens. */ - final class File extends @ruby_token_file, TokenImpl { + class File extends @ruby_token_file, F::Token, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "File" } } /** A class representing `find_pattern` nodes. */ - final class FindPattern extends @ruby_find_pattern, AstNodeImpl { + class FindPattern extends @ruby_find_pattern, F::UnderscorePatternExprBasic, + F::UnderscorePatternTopExprBody + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FindPattern" } /** Gets the node corresponding to the field `class`. */ - final UnderscorePatternConstant getClass() { ruby_find_pattern_class(this, result) } + final F::UnderscorePatternConstant getClass() { ruby_find_pattern_class(this, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_find_pattern_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_find_pattern_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_find_pattern_class(this, result) or ruby_find_pattern_child(this, _, result) } } /** A class representing `float` tokens. */ - final class Float extends @ruby_token_float, TokenImpl { + class Float extends @ruby_token_float, F::Token, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Float" } } /** A class representing `for` nodes. */ - final class For extends @ruby_for, AstNodeImpl { + class For extends @ruby_for, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "For" } /** Gets the node corresponding to the field `body`. */ - final Do getBody() { ruby_for_def(this, result, _, _) } + final F::Do getBody() { ruby_for_def(this, result, _, _) } /** Gets the node corresponding to the field `pattern`. */ - final AstNode getPattern() { ruby_for_def(this, _, result, _) } + final F::AstNode getPattern() { ruby_for_def(this, _, result, _) } /** Gets the node corresponding to the field `value`. */ - final In getValue() { ruby_for_def(this, _, _, result) } + final F::In getValue() { ruby_for_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_for_def(this, result, _, _) or ruby_for_def(this, _, result, _) or ruby_for_def(this, _, _, result) @@ -868,140 +961,155 @@ module Ruby { } /** A class representing `forward_argument` tokens. */ - final class ForwardArgument extends @ruby_token_forward_argument, TokenImpl { + class ForwardArgument extends @ruby_token_forward_argument, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForwardArgument" } } /** A class representing `forward_parameter` tokens. */ - final class ForwardParameter extends @ruby_token_forward_parameter, TokenImpl { + class ForwardParameter extends @ruby_token_forward_parameter, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForwardParameter" } } /** A class representing `global_variable` tokens. */ - final class GlobalVariable extends @ruby_token_global_variable, TokenImpl { + class GlobalVariable extends @ruby_token_global_variable, F::Token, F::UnderscoreNonlocalVariable { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GlobalVariable" } } /** A class representing `hash` nodes. */ - final class Hash extends @ruby_hash, AstNodeImpl { + class Hash extends @ruby_hash, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Hash" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_hash_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_hash_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_hash_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_hash_child(this, _, result) } } /** A class representing `hash_key_symbol` tokens. */ - final class HashKeySymbol extends @ruby_token_hash_key_symbol, TokenImpl { + class HashKeySymbol extends @ruby_token_hash_key_symbol, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashKeySymbol" } } /** A class representing `hash_pattern` nodes. */ - final class HashPattern extends @ruby_hash_pattern, AstNodeImpl { + class HashPattern extends @ruby_hash_pattern, F::UnderscorePatternExprBasic, + F::UnderscorePatternTopExprBody + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashPattern" } /** Gets the node corresponding to the field `class`. */ - final UnderscorePatternConstant getClass() { ruby_hash_pattern_class(this, result) } + final F::UnderscorePatternConstant getClass() { ruby_hash_pattern_class(this, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getChild(int i) { ruby_hash_pattern_child(this, i, result) } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_hash_pattern_child(this, i, result) } + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_hash_pattern_class(this, result) or ruby_hash_pattern_child(this, _, result) } } /** A class representing `hash_splat_argument` nodes. */ - final class HashSplatArgument extends @ruby_hash_splat_argument, AstNodeImpl { + class HashSplatArgument extends @ruby_hash_splat_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashSplatArgument" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_hash_splat_argument_child(this, result) } + final F::UnderscoreArg getChild() { ruby_hash_splat_argument_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_hash_splat_argument_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_hash_splat_argument_child(this, result) } } /** A class representing `hash_splat_nil` tokens. */ - final class HashSplatNil extends @ruby_token_hash_splat_nil, TokenImpl { + class HashSplatNil extends @ruby_token_hash_splat_nil, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashSplatNil" } } /** A class representing `hash_splat_parameter` nodes. */ - final class HashSplatParameter extends @ruby_hash_splat_parameter, AstNodeImpl { + class HashSplatParameter extends @ruby_hash_splat_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HashSplatParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_hash_splat_parameter_name(this, result) } + final F::Identifier getName() { ruby_hash_splat_parameter_name(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_hash_splat_parameter_name(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_hash_splat_parameter_name(this, result) } } /** A class representing `heredoc_beginning` tokens. */ - final class HeredocBeginning extends @ruby_token_heredoc_beginning, TokenImpl { + class HeredocBeginning extends @ruby_token_heredoc_beginning, F::Token, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocBeginning" } } /** A class representing `heredoc_body` nodes. */ - final class HeredocBody extends @ruby_heredoc_body, AstNodeImpl { + class HeredocBody extends @ruby_heredoc_body, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocBody" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_heredoc_body_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_heredoc_body_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_heredoc_body_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_heredoc_body_child(this, _, result) } } /** A class representing `heredoc_content` tokens. */ - final class HeredocContent extends @ruby_token_heredoc_content, TokenImpl { + class HeredocContent extends @ruby_token_heredoc_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocContent" } } /** A class representing `heredoc_end` tokens. */ - final class HeredocEnd extends @ruby_token_heredoc_end, TokenImpl { + class HeredocEnd extends @ruby_token_heredoc_end, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "HeredocEnd" } } /** A class representing `identifier` tokens. */ - final class Identifier extends @ruby_token_identifier, TokenImpl { + class Identifier extends @ruby_token_identifier, F::Token, F::UnderscoreMethodName, + F::UnderscorePatternExprBasic, F::UnderscoreVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Identifier" } } /** A class representing `if` nodes. */ - final class If extends @ruby_if, AstNodeImpl { + class If extends @ruby_if, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "If" } /** Gets the node corresponding to the field `alternative`. */ - final AstNode getAlternative() { ruby_if_alternative(this, result) } + final F::AstNode getAlternative() { ruby_if_alternative(this, result) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_if_def(this, result) } + final F::UnderscoreStatement getCondition() { ruby_if_def(this, result) } /** Gets the node corresponding to the field `consequence`. */ - final Then getConsequence() { ruby_if_consequence(this, result) } + final F::Then getConsequence() { ruby_if_consequence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_if_alternative(this, result) or ruby_if_def(this, result) or ruby_if_consequence(this, result) @@ -1009,62 +1117,62 @@ module Ruby { } /** A class representing `if_guard` nodes. */ - final class IfGuard extends @ruby_if_guard, AstNodeImpl { + class IfGuard extends @ruby_if_guard, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfGuard" } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_if_guard_def(this, result) } + final F::UnderscoreExpression getCondition() { ruby_if_guard_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_if_guard_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_if_guard_def(this, result) } } /** A class representing `if_modifier` nodes. */ - final class IfModifier extends @ruby_if_modifier, AstNodeImpl { + class IfModifier extends @ruby_if_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_if_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_if_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_if_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_if_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_if_modifier_def(this, result, _) or ruby_if_modifier_def(this, _, result) } } /** A class representing `in` nodes. */ - final class In extends @ruby_in, AstNodeImpl { + class In extends @ruby_in, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "In" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_in_def(this, result) } + final F::UnderscoreArg getChild() { ruby_in_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_in_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_in_def(this, result) } } /** A class representing `in_clause` nodes. */ - final class InClause extends @ruby_in_clause, AstNodeImpl { + class InClause extends @ruby_in_clause, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InClause" } /** Gets the node corresponding to the field `body`. */ - final Then getBody() { ruby_in_clause_body(this, result) } + final F::Then getBody() { ruby_in_clause_body(this, result) } /** Gets the node corresponding to the field `guard`. */ - final AstNode getGuard() { ruby_in_clause_guard(this, result) } + final F::AstNode getGuard() { ruby_in_clause_guard(this, result) } /** Gets the node corresponding to the field `pattern`. */ - final UnderscorePatternTopExprBody getPattern() { ruby_in_clause_def(this, result) } + final F::UnderscorePatternTopExprBody getPattern() { ruby_in_clause_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_in_clause_body(this, result) or ruby_in_clause_guard(this, result) or ruby_in_clause_def(this, result) @@ -1072,143 +1180,156 @@ module Ruby { } /** A class representing `instance_variable` tokens. */ - final class InstanceVariable extends @ruby_token_instance_variable, TokenImpl { + class InstanceVariable extends @ruby_token_instance_variable, F::Token, + F::UnderscoreNonlocalVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InstanceVariable" } } /** A class representing `integer` tokens. */ - final class Integer extends @ruby_token_integer, TokenImpl { + class Integer extends @ruby_token_integer, F::Token, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Integer" } } /** A class representing `interpolation` nodes. */ - final class Interpolation extends @ruby_interpolation, AstNodeImpl { + class Interpolation extends @ruby_interpolation, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Interpolation" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_interpolation_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_interpolation_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_interpolation_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_interpolation_child(this, _, result) } } /** A class representing `keyword_parameter` nodes. */ - final class KeywordParameter extends @ruby_keyword_parameter, AstNodeImpl { + class KeywordParameter extends @ruby_keyword_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeywordParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_keyword_parameter_def(this, result) } + final F::Identifier getName() { ruby_keyword_parameter_def(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_keyword_parameter_value(this, result) } + final F::UnderscoreArg getValue() { ruby_keyword_parameter_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_keyword_parameter_def(this, result) or ruby_keyword_parameter_value(this, result) } } /** A class representing `keyword_pattern` nodes. */ - final class KeywordPattern extends @ruby_keyword_pattern, AstNodeImpl { + class KeywordPattern extends @ruby_keyword_pattern, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeywordPattern" } /** Gets the node corresponding to the field `key`. */ - final AstNode getKey() { ruby_keyword_pattern_def(this, result) } + final F::AstNode getKey() { ruby_keyword_pattern_def(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscorePatternExpr getValue() { ruby_keyword_pattern_value(this, result) } + final F::UnderscorePatternExpr getValue() { ruby_keyword_pattern_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_keyword_pattern_def(this, result) or ruby_keyword_pattern_value(this, result) } } /** A class representing `lambda` nodes. */ - final class Lambda extends @ruby_lambda, AstNodeImpl { + class Lambda extends @ruby_lambda, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Lambda" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_lambda_def(this, result) } + final F::AstNode getBody() { ruby_lambda_def(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final LambdaParameters getParameters() { ruby_lambda_parameters(this, result) } + final F::LambdaParameters getParameters() { ruby_lambda_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_lambda_def(this, result) or ruby_lambda_parameters(this, result) } } /** A class representing `lambda_parameters` nodes. */ - final class LambdaParameters extends @ruby_lambda_parameters, AstNodeImpl { + class LambdaParameters extends @ruby_lambda_parameters, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LambdaParameters" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_lambda_parameters_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_lambda_parameters_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_lambda_parameters_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_lambda_parameters_child(this, _, result) } } /** A class representing `left_assignment_list` nodes. */ - final class LeftAssignmentList extends @ruby_left_assignment_list, AstNodeImpl { + class LeftAssignmentList extends @ruby_left_assignment_list, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LeftAssignmentList" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_left_assignment_list_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_left_assignment_list_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_left_assignment_list_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ruby_left_assignment_list_child(this, _, result) + } } /** A class representing `line` tokens. */ - final class Line extends @ruby_token_line, TokenImpl { + class Line extends @ruby_token_line, F::Token, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Line" } } /** A class representing `match_pattern` nodes. */ - final class MatchPattern extends @ruby_match_pattern, AstNodeImpl { + class MatchPattern extends @ruby_match_pattern, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MatchPattern" } /** Gets the node corresponding to the field `pattern`. */ - final UnderscorePatternTopExprBody getPattern() { ruby_match_pattern_def(this, result, _) } + final F::UnderscorePatternTopExprBody getPattern() { ruby_match_pattern_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_match_pattern_def(this, _, result) } + final F::UnderscoreArg getValue() { ruby_match_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_match_pattern_def(this, result, _) or ruby_match_pattern_def(this, _, result) } } /** A class representing `method` nodes. */ - final class Method extends @ruby_method, AstNodeImpl { + class Method extends @ruby_method, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Method" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_method_body(this, result) } + final F::AstNode getBody() { ruby_method_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final UnderscoreMethodName getName() { ruby_method_def(this, result) } + final F::UnderscoreMethodName getName() { ruby_method_def(this, result) } /** Gets the node corresponding to the field `parameters`. */ - final MethodParameters getParameters() { ruby_method_parameters(this, result) } + final F::MethodParameters getParameters() { ruby_method_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_method_body(this, result) or ruby_method_def(this, result) or ruby_method_parameters(this, result) @@ -1216,65 +1337,70 @@ module Ruby { } /** A class representing `method_parameters` nodes. */ - final class MethodParameters extends @ruby_method_parameters, AstNodeImpl { + class MethodParameters extends @ruby_method_parameters, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MethodParameters" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_method_parameters_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_method_parameters_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_method_parameters_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_method_parameters_child(this, _, result) } } /** A class representing `module` nodes. */ - final class Module extends @ruby_module, AstNodeImpl { + class Module extends @ruby_module, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Module" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_module_body(this, result) } + final F::BodyStatement getBody() { ruby_module_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_module_def(this, result) } + final F::AstNode getName() { ruby_module_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_module_body(this, result) or ruby_module_def(this, result) } } /** A class representing `next` nodes. */ - final class Next extends @ruby_next, AstNodeImpl { + class Next extends @ruby_next, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Next" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_next_child(this, result) } + final F::ArgumentList getChild() { ruby_next_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_next_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_next_child(this, result) } } /** A class representing `nil` tokens. */ - final class Nil extends @ruby_token_nil, TokenImpl { + class Nil extends @ruby_token_nil, F::Token, F::UnderscoreLhs, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Nil" } } /** A class representing `operator` tokens. */ - final class Operator extends @ruby_token_operator, TokenImpl { + class Operator extends @ruby_token_operator, F::Token, F::UnderscoreMethodName { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Operator" } } /** A class representing `operator_assignment` nodes. */ - final class OperatorAssignment extends @ruby_operator_assignment, AstNodeImpl { + class OperatorAssignment extends @ruby_operator_assignment, F::UnderscoreArg, + F::UnderscoreExpression + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OperatorAssignment" } /** Gets the node corresponding to the field `left`. */ - final UnderscoreLhs getLeft() { ruby_operator_assignment_def(this, result, _, _) } + final F::UnderscoreLhs getLeft() { ruby_operator_assignment_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -1308,109 +1434,115 @@ module Ruby { } /** Gets the node corresponding to the field `right`. */ - final AstNode getRight() { ruby_operator_assignment_def(this, _, _, result) } + final F::AstNode getRight() { ruby_operator_assignment_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_operator_assignment_def(this, result, _, _) or ruby_operator_assignment_def(this, _, _, result) } } /** A class representing `optional_parameter` nodes. */ - final class OptionalParameter extends @ruby_optional_parameter, AstNodeImpl { + class OptionalParameter extends @ruby_optional_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OptionalParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_optional_parameter_def(this, result, _) } + final F::Identifier getName() { ruby_optional_parameter_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_optional_parameter_def(this, _, result) } + final F::UnderscoreArg getValue() { ruby_optional_parameter_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_optional_parameter_def(this, result, _) or ruby_optional_parameter_def(this, _, result) } } /** A class representing `pair` nodes. */ - final class Pair extends @ruby_pair, AstNodeImpl { + class Pair extends @ruby_pair, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Pair" } /** Gets the node corresponding to the field `key`. */ - final AstNode getKey() { ruby_pair_def(this, result) } + final F::AstNode getKey() { ruby_pair_def(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_pair_value(this, result) } + final F::UnderscoreArg getValue() { ruby_pair_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_pair_def(this, result) or ruby_pair_value(this, result) } } /** A class representing `parenthesized_pattern` nodes. */ - final class ParenthesizedPattern extends @ruby_parenthesized_pattern, AstNodeImpl { + class ParenthesizedPattern extends @ruby_parenthesized_pattern, F::UnderscorePatternExprBasic { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ParenthesizedPattern" } /** Gets the child of this node. */ - final UnderscorePatternExpr getChild() { ruby_parenthesized_pattern_def(this, result) } + final F::UnderscorePatternExpr getChild() { ruby_parenthesized_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_parenthesized_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_parenthesized_pattern_def(this, result) } } /** A class representing `parenthesized_statements` nodes. */ - final class ParenthesizedStatements extends @ruby_parenthesized_statements, AstNodeImpl { + class ParenthesizedStatements extends @ruby_parenthesized_statements, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ParenthesizedStatements" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_parenthesized_statements_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_parenthesized_statements_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_parenthesized_statements_child(this, _, result) } } /** A class representing `pattern` nodes. */ - final class Pattern extends @ruby_pattern, AstNodeImpl { + class Pattern extends @ruby_pattern, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Pattern" } /** Gets the child of this node. */ - final AstNode getChild() { ruby_pattern_def(this, result) } + final F::AstNode getChild() { ruby_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_pattern_def(this, result) } } /** A class representing `program` nodes. */ - final class Program extends @ruby_program, AstNodeImpl { + class Program extends @ruby_program, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Program" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_program_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_program_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_program_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_program_child(this, _, result) } } /** A class representing `range` nodes. */ - final class Range extends @ruby_range, AstNodeImpl { + class Range extends @ruby_range, F::UnderscoreArg, F::UnderscorePatternExprBasic { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Range" } /** Gets the node corresponding to the field `begin`. */ - final AstNode getBegin() { ruby_range_begin(this, result) } + final F::AstNode getBegin() { ruby_range_begin(this, result) } /** Gets the node corresponding to the field `end`. */ - final AstNode getEnd() { ruby_range_end(this, result) } + final F::AstNode getEnd() { ruby_range_end(this, result) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -1422,63 +1554,66 @@ module Ruby { } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_range_begin(this, result) or ruby_range_end(this, result) } } /** A class representing `rational` nodes. */ - final class Rational extends @ruby_rational, AstNodeImpl { + class Rational extends @ruby_rational, F::UnderscoreSimpleNumeric { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Rational" } /** Gets the child of this node. */ - final AstNode getChild() { ruby_rational_def(this, result) } + final F::AstNode getChild() { ruby_rational_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_rational_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_rational_def(this, result) } } /** A class representing `redo` nodes. */ - final class Redo extends @ruby_redo, AstNodeImpl { + class Redo extends @ruby_redo, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Redo" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_redo_child(this, result) } + final F::ArgumentList getChild() { ruby_redo_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_redo_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_redo_child(this, result) } } /** A class representing `regex` nodes. */ - final class Regex extends @ruby_regex, AstNodeImpl { + class Regex extends @ruby_regex, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Regex" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_regex_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_regex_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_regex_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_regex_child(this, _, result) } } /** A class representing `rescue` nodes. */ - final class Rescue extends @ruby_rescue, AstNodeImpl { + class Rescue extends @ruby_rescue, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Rescue" } /** Gets the node corresponding to the field `body`. */ - final Then getBody() { ruby_rescue_body(this, result) } + final F::Then getBody() { ruby_rescue_body(this, result) } /** Gets the node corresponding to the field `exceptions`. */ - final Exceptions getExceptions() { ruby_rescue_exceptions(this, result) } + final F::Exceptions getExceptions() { ruby_rescue_exceptions(this, result) } /** Gets the node corresponding to the field `variable`. */ - final ExceptionVariable getVariable() { ruby_rescue_variable(this, result) } + final F::ExceptionVariable getVariable() { ruby_rescue_variable(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_rescue_body(this, result) or ruby_rescue_exceptions(this, result) or ruby_rescue_variable(this, result) @@ -1486,147 +1621,158 @@ module Ruby { } /** A class representing `rescue_modifier` nodes. */ - final class RescueModifier extends @ruby_rescue_modifier, AstNodeImpl { + class RescueModifier extends @ruby_rescue_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RescueModifier" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_rescue_modifier_def(this, result, _) } + final F::AstNode getBody() { ruby_rescue_modifier_def(this, result, _) } /** Gets the node corresponding to the field `handler`. */ - final UnderscoreExpression getHandler() { ruby_rescue_modifier_def(this, _, result) } + final F::UnderscoreExpression getHandler() { ruby_rescue_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_rescue_modifier_def(this, result, _) or ruby_rescue_modifier_def(this, _, result) } } /** A class representing `rest_assignment` nodes. */ - final class RestAssignment extends @ruby_rest_assignment, AstNodeImpl { + class RestAssignment extends @ruby_rest_assignment, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RestAssignment" } /** Gets the child of this node. */ - final UnderscoreLhs getChild() { ruby_rest_assignment_child(this, result) } + final F::UnderscoreLhs getChild() { ruby_rest_assignment_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_rest_assignment_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_rest_assignment_child(this, result) } } /** A class representing `retry` nodes. */ - final class Retry extends @ruby_retry, AstNodeImpl { + class Retry extends @ruby_retry, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Retry" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_retry_child(this, result) } + final F::ArgumentList getChild() { ruby_retry_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_retry_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_retry_child(this, result) } } /** A class representing `return` nodes. */ - final class Return extends @ruby_return, AstNodeImpl { + class Return extends @ruby_return, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Return" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_return_child(this, result) } + final F::ArgumentList getChild() { ruby_return_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_return_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_return_child(this, result) } } /** A class representing `right_assignment_list` nodes. */ - final class RightAssignmentList extends @ruby_right_assignment_list, AstNodeImpl { + class RightAssignmentList extends @ruby_right_assignment_list, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RightAssignmentList" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_right_assignment_list_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_right_assignment_list_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_right_assignment_list_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { + ruby_right_assignment_list_child(this, _, result) + } } /** A class representing `scope_resolution` nodes. */ - final class ScopeResolution extends @ruby_scope_resolution, AstNodeImpl { + class ScopeResolution extends @ruby_scope_resolution, F::UnderscoreLhs, + F::UnderscorePatternConstant + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ScopeResolution" } /** Gets the node corresponding to the field `name`. */ - final Constant getName() { ruby_scope_resolution_def(this, result) } + final F::Constant getName() { ruby_scope_resolution_def(this, result) } /** Gets the node corresponding to the field `scope`. */ - final AstNode getScope() { ruby_scope_resolution_scope(this, result) } + final F::AstNode getScope() { ruby_scope_resolution_scope(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_scope_resolution_def(this, result) or ruby_scope_resolution_scope(this, result) } } /** A class representing `self` tokens. */ - final class Self extends @ruby_token_self, TokenImpl { + class Self extends @ruby_token_self, F::Token, F::UnderscorePatternPrimitive, + F::UnderscoreVariable + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Self" } } /** A class representing `setter` nodes. */ - final class Setter extends @ruby_setter, AstNodeImpl { + class Setter extends @ruby_setter, F::UnderscoreMethodName { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Setter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_setter_def(this, result) } + final F::Identifier getName() { ruby_setter_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_setter_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_setter_def(this, result) } } /** A class representing `simple_symbol` tokens. */ - final class SimpleSymbol extends @ruby_token_simple_symbol, TokenImpl { + class SimpleSymbol extends @ruby_token_simple_symbol, F::Token, F::UnderscoreMethodName, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SimpleSymbol" } } /** A class representing `singleton_class` nodes. */ - final class SingletonClass extends @ruby_singleton_class, AstNodeImpl { + class SingletonClass extends @ruby_singleton_class, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SingletonClass" } /** Gets the node corresponding to the field `body`. */ - final BodyStatement getBody() { ruby_singleton_class_body(this, result) } + final F::BodyStatement getBody() { ruby_singleton_class_body(this, result) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_singleton_class_def(this, result) } + final F::UnderscoreArg getValue() { ruby_singleton_class_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_singleton_class_body(this, result) or ruby_singleton_class_def(this, result) } } /** A class representing `singleton_method` nodes. */ - final class SingletonMethod extends @ruby_singleton_method, AstNodeImpl { + class SingletonMethod extends @ruby_singleton_method, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SingletonMethod" } /** Gets the node corresponding to the field `body`. */ - final AstNode getBody() { ruby_singleton_method_body(this, result) } + final F::AstNode getBody() { ruby_singleton_method_body(this, result) } /** Gets the node corresponding to the field `name`. */ - final UnderscoreMethodName getName() { ruby_singleton_method_def(this, result, _) } + final F::UnderscoreMethodName getName() { ruby_singleton_method_def(this, result, _) } /** Gets the node corresponding to the field `object`. */ - final AstNode getObject() { ruby_singleton_method_def(this, _, result) } + final F::AstNode getObject() { ruby_singleton_method_def(this, _, result) } /** Gets the node corresponding to the field `parameters`. */ - final MethodParameters getParameters() { ruby_singleton_method_parameters(this, result) } + final F::MethodParameters getParameters() { ruby_singleton_method_parameters(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_singleton_method_body(this, result) or ruby_singleton_method_def(this, result, _) or ruby_singleton_method_def(this, _, result) or @@ -1635,143 +1781,160 @@ module Ruby { } /** A class representing `splat_argument` nodes. */ - final class SplatArgument extends @ruby_splat_argument, AstNodeImpl { + class SplatArgument extends @ruby_splat_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SplatArgument" } /** Gets the child of this node. */ - final UnderscoreArg getChild() { ruby_splat_argument_child(this, result) } + final F::UnderscoreArg getChild() { ruby_splat_argument_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_splat_argument_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_splat_argument_child(this, result) } } /** A class representing `splat_parameter` nodes. */ - final class SplatParameter extends @ruby_splat_parameter, AstNodeImpl { + class SplatParameter extends @ruby_splat_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SplatParameter" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { ruby_splat_parameter_name(this, result) } + final F::Identifier getName() { ruby_splat_parameter_name(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_splat_parameter_name(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_splat_parameter_name(this, result) } } /** A class representing `string` nodes. */ - final class String extends @ruby_string__, AstNodeImpl { + class String extends @ruby_string__, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "String" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_string_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_string_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_string_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_string_child(this, _, result) } } /** A class representing `string_array` nodes. */ - final class StringArray extends @ruby_string_array, AstNodeImpl { + class StringArray extends @ruby_string_array, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringArray" } /** Gets the `i`th child of this node. */ - final BareString getChild(int i) { ruby_string_array_child(this, i, result) } + final F::BareString getChild(int i) { ruby_string_array_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::BareString getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_string_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_string_array_child(this, _, result) } } /** A class representing `string_content` tokens. */ - final class StringContent extends @ruby_token_string_content, TokenImpl { + class StringContent extends @ruby_token_string_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringContent" } } /** A class representing `subshell` nodes. */ - final class Subshell extends @ruby_subshell, AstNodeImpl { + class Subshell extends @ruby_subshell, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Subshell" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_subshell_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_subshell_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_subshell_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_subshell_child(this, _, result) } } /** A class representing `super` tokens. */ - final class Super extends @ruby_token_super, TokenImpl { + class Super extends @ruby_token_super, F::Token, F::UnderscoreVariable { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Super" } } /** A class representing `superclass` nodes. */ - final class Superclass extends @ruby_superclass, AstNodeImpl { + class Superclass extends @ruby_superclass, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Superclass" } /** Gets the child of this node. */ - final UnderscoreExpression getChild() { ruby_superclass_def(this, result) } + final F::UnderscoreExpression getChild() { ruby_superclass_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_superclass_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_superclass_def(this, result) } } /** A class representing `symbol_array` nodes. */ - final class SymbolArray extends @ruby_symbol_array, AstNodeImpl { + class SymbolArray extends @ruby_symbol_array, F::UnderscorePatternPrimitive, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SymbolArray" } /** Gets the `i`th child of this node. */ - final BareSymbol getChild(int i) { ruby_symbol_array_child(this, i, result) } + final F::BareSymbol getChild(int i) { ruby_symbol_array_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::BareSymbol getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_symbol_array_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_symbol_array_child(this, _, result) } } /** A class representing `test_pattern` nodes. */ - final class TestPattern extends @ruby_test_pattern, AstNodeImpl { + class TestPattern extends @ruby_test_pattern, F::UnderscoreExpression { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TestPattern" } /** Gets the node corresponding to the field `pattern`. */ - final UnderscorePatternTopExprBody getPattern() { ruby_test_pattern_def(this, result, _) } + final F::UnderscorePatternTopExprBody getPattern() { ruby_test_pattern_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final UnderscoreArg getValue() { ruby_test_pattern_def(this, _, result) } + final F::UnderscoreArg getValue() { ruby_test_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_test_pattern_def(this, result, _) or ruby_test_pattern_def(this, _, result) } } /** A class representing `then` nodes. */ - final class Then extends @ruby_then, AstNodeImpl { + class Then extends @ruby_then, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Then" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { ruby_then_child(this, i, result) } + final F::AstNode getChild(int i) { ruby_then_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_then_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_then_child(this, _, result) } } /** A class representing `true` tokens. */ - final class True extends @ruby_token_true, TokenImpl { + class True extends @ruby_token_true, F::Token, F::UnderscoreLhs, F::UnderscorePatternPrimitive { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "True" } } /** A class representing `unary` nodes. */ - final class Unary extends @ruby_unary, AstNodeImpl { + class Unary extends @ruby_unary, F::UnderscoreArg, F::UnderscoreExpression, + F::UnderscorePatternPrimitive, F::UnderscorePrimary + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unary" } /** Gets the node corresponding to the field `operand`. */ - final AstNode getOperand() { ruby_unary_def(this, result, _) } + final F::AstNode getOperand() { ruby_unary_def(this, result, _) } /** Gets the node corresponding to the field `operator`. */ final string getOperator() { @@ -1791,43 +1954,46 @@ module Ruby { } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_unary_def(this, result, _) } + final override F::AstNode getAFieldOrChild() { ruby_unary_def(this, result, _) } } /** A class representing `undef` nodes. */ - final class Undef extends @ruby_undef, AstNodeImpl { + class Undef extends @ruby_undef, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Undef" } /** Gets the `i`th child of this node. */ - final UnderscoreMethodName getChild(int i) { ruby_undef_child(this, i, result) } + final F::UnderscoreMethodName getChild(int i) { ruby_undef_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::UnderscoreMethodName getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_undef_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { ruby_undef_child(this, _, result) } } /** A class representing `uninterpreted` tokens. */ - final class Uninterpreted extends @ruby_token_uninterpreted, TokenImpl { + class Uninterpreted extends @ruby_token_uninterpreted, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Uninterpreted" } } /** A class representing `unless` nodes. */ - final class Unless extends @ruby_unless, AstNodeImpl { + class Unless extends @ruby_unless, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Unless" } /** Gets the node corresponding to the field `alternative`. */ - final AstNode getAlternative() { ruby_unless_alternative(this, result) } + final F::AstNode getAlternative() { ruby_unless_alternative(this, result) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_unless_def(this, result) } + final F::UnderscoreStatement getCondition() { ruby_unless_def(this, result) } /** Gets the node corresponding to the field `consequence`. */ - final Then getConsequence() { ruby_unless_consequence(this, result) } + final F::Then getConsequence() { ruby_unless_consequence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_unless_alternative(this, result) or ruby_unless_def(this, result) or ruby_unless_consequence(this, result) @@ -1835,147 +2001,154 @@ module Ruby { } /** A class representing `unless_guard` nodes. */ - final class UnlessGuard extends @ruby_unless_guard, AstNodeImpl { + class UnlessGuard extends @ruby_unless_guard, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnlessGuard" } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_unless_guard_def(this, result) } + final F::UnderscoreExpression getCondition() { ruby_unless_guard_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_unless_guard_def(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_unless_guard_def(this, result) } } /** A class representing `unless_modifier` nodes. */ - final class UnlessModifier extends @ruby_unless_modifier, AstNodeImpl { + class UnlessModifier extends @ruby_unless_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnlessModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_unless_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_unless_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_unless_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_unless_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_unless_modifier_def(this, result, _) or ruby_unless_modifier_def(this, _, result) } } /** A class representing `until` nodes. */ - final class Until extends @ruby_until, AstNodeImpl { + class Until extends @ruby_until, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Until" } /** Gets the node corresponding to the field `body`. */ - final Do getBody() { ruby_until_def(this, result, _) } + final F::Do getBody() { ruby_until_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_until_def(this, _, result) } + final F::UnderscoreStatement getCondition() { ruby_until_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_until_def(this, result, _) or ruby_until_def(this, _, result) } } /** A class representing `until_modifier` nodes. */ - final class UntilModifier extends @ruby_until_modifier, AstNodeImpl { + class UntilModifier extends @ruby_until_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UntilModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_until_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_until_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_until_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_until_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_until_modifier_def(this, result, _) or ruby_until_modifier_def(this, _, result) } } /** A class representing `variable_reference_pattern` nodes. */ - final class VariableReferencePattern extends @ruby_variable_reference_pattern, AstNodeImpl { + class VariableReferencePattern extends @ruby_variable_reference_pattern, + F::UnderscorePatternExprBasic + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VariableReferencePattern" } /** Gets the node corresponding to the field `name`. */ - final AstNode getName() { ruby_variable_reference_pattern_def(this, result) } + final F::AstNode getName() { ruby_variable_reference_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_variable_reference_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { + ruby_variable_reference_pattern_def(this, result) + } } /** A class representing `when` nodes. */ - final class When extends @ruby_when, AstNodeImpl { + class When extends @ruby_when, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "When" } /** Gets the node corresponding to the field `body`. */ - final Then getBody() { ruby_when_body(this, result) } + final F::Then getBody() { ruby_when_body(this, result) } + + /** Gets the node corresponding to the field `pattern`. */ + final F::Pattern getPattern(int i) { ruby_when_pattern(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern(int i) { ruby_when_pattern(this, i, result) } + final F::Pattern getAPattern() { result = this.getPattern(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_when_body(this, result) or ruby_when_pattern(this, _, result) } } /** A class representing `while` nodes. */ - final class While extends @ruby_while, AstNodeImpl { + class While extends @ruby_while, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "While" } /** Gets the node corresponding to the field `body`. */ - final Do getBody() { ruby_while_def(this, result, _) } + final F::Do getBody() { ruby_while_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreStatement getCondition() { ruby_while_def(this, _, result) } + final F::UnderscoreStatement getCondition() { ruby_while_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_while_def(this, result, _) or ruby_while_def(this, _, result) } } /** A class representing `while_modifier` nodes. */ - final class WhileModifier extends @ruby_while_modifier, AstNodeImpl { + class WhileModifier extends @ruby_while_modifier, F::UnderscoreStatement { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "WhileModifier" } /** Gets the node corresponding to the field `body`. */ - final UnderscoreStatement getBody() { ruby_while_modifier_def(this, result, _) } + final F::UnderscoreStatement getBody() { ruby_while_modifier_def(this, result, _) } /** Gets the node corresponding to the field `condition`. */ - final UnderscoreExpression getCondition() { ruby_while_modifier_def(this, _, result) } + final F::UnderscoreExpression getCondition() { ruby_while_modifier_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { ruby_while_modifier_def(this, result, _) or ruby_while_modifier_def(this, _, result) } } /** A class representing `yield` nodes. */ - final class Yield extends @ruby_yield, AstNodeImpl { + class Yield extends @ruby_yield, F::UnderscoreExpression, F::UnderscorePrimary { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Yield" } /** Gets the child of this node. */ - final ArgumentList getChild() { ruby_yield_child(this, result) } + final F::ArgumentList getChild() { ruby_yield_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { ruby_yield_child(this, result) } + final override F::AstNode getAFieldOrChild() { ruby_yield_child(this, result) } } /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(Alias).getAlias() and i = -1 and name = "getAlias" or result = node.(Alias).getName() and i = -1 and name = "getName" @@ -2307,10 +2480,322 @@ module Ruby { } } +module RubyFinal { + private module F = Ruby; + + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class UnderscoreArg = F::UnderscoreArg; + + final class UnderscoreCallOperator = F::UnderscoreCallOperator; + + final class UnderscoreExpression = F::UnderscoreExpression; + + final class UnderscoreLhs = F::UnderscoreLhs; + + final class UnderscoreMethodName = F::UnderscoreMethodName; + + final class UnderscoreNonlocalVariable = F::UnderscoreNonlocalVariable; + + final class UnderscorePatternConstant = F::UnderscorePatternConstant; + + final class UnderscorePatternExpr = F::UnderscorePatternExpr; + + final class UnderscorePatternExprBasic = F::UnderscorePatternExprBasic; + + final class UnderscorePatternPrimitive = F::UnderscorePatternPrimitive; + + final class UnderscorePatternTopExprBody = F::UnderscorePatternTopExprBody; + + final class UnderscorePrimary = F::UnderscorePrimary; + + final class UnderscoreSimpleNumeric = F::UnderscoreSimpleNumeric; + + final class UnderscoreStatement = F::UnderscoreStatement; + + final class UnderscoreVariable = F::UnderscoreVariable; + + final class Alias = F::Alias; + + final class AlternativePattern = F::AlternativePattern; + + final class ArgumentList = F::ArgumentList; + + final class Array = F::Array; + + final class ArrayPattern = F::ArrayPattern; + + final class AsPattern = F::AsPattern; + + final class Assignment = F::Assignment; + + final class BareString = F::BareString; + + final class BareSymbol = F::BareSymbol; + + final class Begin = F::Begin; + + final class BeginBlock = F::BeginBlock; + + final class Binary = F::Binary; + + final class Block = F::Block; + + final class BlockArgument = F::BlockArgument; + + final class BlockBody = F::BlockBody; + + final class BlockParameter = F::BlockParameter; + + final class BlockParameters = F::BlockParameters; + + final class BodyStatement = F::BodyStatement; + + final class Break = F::Break; + + final class Call = F::Call; + + final class Case = F::Case; + + final class CaseMatch = F::CaseMatch; + + final class ChainedString = F::ChainedString; + + final class Character = F::Character; + + final class Class = F::Class; + + final class ClassVariable = F::ClassVariable; + + final class Comment = F::Comment; + + final class Complex = F::Complex; + + final class Conditional = F::Conditional; + + final class Constant = F::Constant; + + final class DelimitedSymbol = F::DelimitedSymbol; + + final class DestructuredLeftAssignment = F::DestructuredLeftAssignment; + + final class DestructuredParameter = F::DestructuredParameter; + + final class Do = F::Do; + + final class DoBlock = F::DoBlock; + + final class ElementReference = F::ElementReference; + + final class Else = F::Else; + + final class Elsif = F::Elsif; + + final class EmptyStatement = F::EmptyStatement; + + final class Encoding = F::Encoding; + + final class EndBlock = F::EndBlock; + + final class Ensure = F::Ensure; + + final class EscapeSequence = F::EscapeSequence; + + final class ExceptionVariable = F::ExceptionVariable; + + final class Exceptions = F::Exceptions; + + final class ExpressionReferencePattern = F::ExpressionReferencePattern; + + final class False = F::False; + + final class File = F::File; + + final class FindPattern = F::FindPattern; + + final class Float = F::Float; + + final class For = F::For; + + final class ForwardArgument = F::ForwardArgument; + + final class ForwardParameter = F::ForwardParameter; + + final class GlobalVariable = F::GlobalVariable; + + final class Hash = F::Hash; + + final class HashKeySymbol = F::HashKeySymbol; + + final class HashPattern = F::HashPattern; + + final class HashSplatArgument = F::HashSplatArgument; + + final class HashSplatNil = F::HashSplatNil; + + final class HashSplatParameter = F::HashSplatParameter; + + final class HeredocBeginning = F::HeredocBeginning; + + final class HeredocBody = F::HeredocBody; + + final class HeredocContent = F::HeredocContent; + + final class HeredocEnd = F::HeredocEnd; + + final class Identifier = F::Identifier; + + final class If = F::If; + + final class IfGuard = F::IfGuard; + + final class IfModifier = F::IfModifier; + + final class In = F::In; + + final class InClause = F::InClause; + + final class InstanceVariable = F::InstanceVariable; + + final class Integer = F::Integer; + + final class Interpolation = F::Interpolation; + + final class KeywordParameter = F::KeywordParameter; + + final class KeywordPattern = F::KeywordPattern; + + final class Lambda = F::Lambda; + + final class LambdaParameters = F::LambdaParameters; + + final class LeftAssignmentList = F::LeftAssignmentList; + + final class Line = F::Line; + + final class MatchPattern = F::MatchPattern; + + final class Method = F::Method; + + final class MethodParameters = F::MethodParameters; + + final class Module = F::Module; + + final class Next = F::Next; + + final class Nil = F::Nil; + + final class Operator = F::Operator; + + final class OperatorAssignment = F::OperatorAssignment; + + final class OptionalParameter = F::OptionalParameter; + + final class Pair = F::Pair; + + final class ParenthesizedPattern = F::ParenthesizedPattern; + + final class ParenthesizedStatements = F::ParenthesizedStatements; + + final class Pattern = F::Pattern; + + final class Program = F::Program; + + final class Range = F::Range; + + final class Rational = F::Rational; + + final class Redo = F::Redo; + + final class Regex = F::Regex; + + final class Rescue = F::Rescue; + + final class RescueModifier = F::RescueModifier; + + final class RestAssignment = F::RestAssignment; + + final class Retry = F::Retry; + + final class Return = F::Return; + + final class RightAssignmentList = F::RightAssignmentList; + + final class ScopeResolution = F::ScopeResolution; + + final class Self = F::Self; + + final class Setter = F::Setter; + + final class SimpleSymbol = F::SimpleSymbol; + + final class SingletonClass = F::SingletonClass; + + final class SingletonMethod = F::SingletonMethod; + + final class SplatArgument = F::SplatArgument; + + final class SplatParameter = F::SplatParameter; + + final class String = F::String; + + final class StringArray = F::StringArray; + + final class StringContent = F::StringContent; + + final class Subshell = F::Subshell; + + final class Super = F::Super; + + final class Superclass = F::Superclass; + + final class SymbolArray = F::SymbolArray; + + final class TestPattern = F::TestPattern; + + final class Then = F::Then; + + final class True = F::True; + + final class Unary = F::Unary; + + final class Undef = F::Undef; + + final class Uninterpreted = F::Uninterpreted; + + final class Unless = F::Unless; + + final class UnlessGuard = F::UnlessGuard; + + final class UnlessModifier = F::UnlessModifier; + + final class Until = F::Until; + + final class UntilModifier = F::UntilModifier; + + final class VariableReferencePattern = F::VariableReferencePattern; + + final class When = F::When; + + final class While = F::While; + + final class WhileModifier = F::WhileModifier; + + final class Yield = F::Yield; +} + overlay[local] module Erb { + private module F = Erb; + /** The base class for all AST nodes */ - private class AstNodeImpl extends @erb_ast_node { + class AstNode extends @erb_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -2318,13 +2803,13 @@ module Erb { final L::Location getLocation() { erb_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { erb_ast_node_parent(this, result, _) } + final F::AstNode getParent() { erb_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { erb_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -2333,10 +2818,8 @@ module Erb { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @erb_token, AstNodeImpl { + class Token extends @erb_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { erb_tokeninfo(this, _, result) } @@ -2347,10 +2830,8 @@ module Erb { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A reserved word. */ - final class ReservedWord extends @erb_reserved_word, TokenImpl { + class ReservedWord extends @erb_reserved_word, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReservedWord" } } @@ -2376,87 +2857,90 @@ module Erb { } /** A class representing `code` tokens. */ - final class Code extends @erb_token_code, TokenImpl { + class Code extends @erb_token_code, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Code" } } /** A class representing `comment` tokens. */ - final class Comment extends @erb_token_comment, TokenImpl { + class Comment extends @erb_token_comment, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Comment" } } /** A class representing `comment_directive` nodes. */ - final class CommentDirective extends @erb_comment_directive, AstNodeImpl { + class CommentDirective extends @erb_comment_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CommentDirective" } /** Gets the child of this node. */ - final Comment getChild() { erb_comment_directive_child(this, result) } + final F::Comment getChild() { erb_comment_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_comment_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_comment_directive_child(this, result) } } /** A class representing `content` tokens. */ - final class Content extends @erb_token_content, TokenImpl { + class Content extends @erb_token_content, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Content" } } /** A class representing `directive` nodes. */ - final class Directive extends @erb_directive, AstNodeImpl { + class Directive extends @erb_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Directive" } /** Gets the child of this node. */ - final Code getChild() { erb_directive_child(this, result) } + final F::Code getChild() { erb_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_directive_child(this, result) } } /** A class representing `graphql_directive` nodes. */ - final class GraphqlDirective extends @erb_graphql_directive, AstNodeImpl { + class GraphqlDirective extends @erb_graphql_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GraphqlDirective" } /** Gets the child of this node. */ - final Code getChild() { erb_graphql_directive_child(this, result) } + final F::Code getChild() { erb_graphql_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_graphql_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_graphql_directive_child(this, result) } } /** A class representing `output_directive` nodes. */ - final class OutputDirective extends @erb_output_directive, AstNodeImpl { + class OutputDirective extends @erb_output_directive, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OutputDirective" } /** Gets the child of this node. */ - final Code getChild() { erb_output_directive_child(this, result) } + final F::Code getChild() { erb_output_directive_child(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_output_directive_child(this, result) } + final override F::AstNode getAFieldOrChild() { erb_output_directive_child(this, result) } } /** A class representing `template` nodes. */ - final class Template extends @erb_template, AstNodeImpl { + class Template extends @erb_template, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Template" } /** Gets the `i`th child of this node. */ - final AstNode getChild(int i) { erb_template_child(this, i, result) } + final F::AstNode getChild(int i) { erb_template_child(this, i, result) } + + /** Gets the `i`th child of this node. */ + final F::AstNode getAChild() { result = this.getChild(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { erb_template_child(this, _, result) } + final override F::AstNode getAFieldOrChild() { erb_template_child(this, _, result) } } /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(CommentDirective).getChild() and i = -1 and name = "getChild" or result = node.(Directive).getChild() and i = -1 and name = "getChild" @@ -2469,3 +2953,31 @@ module Erb { } } } + +module ErbFinal { + private module F = Erb; + + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class ReservedWord = F::ReservedWord; + + final class Code = F::Code; + + final class Comment = F::Comment; + + final class CommentDirective = F::CommentDirective; + + final class Content = F::Content; + + final class Directive = F::Directive; + + final class GraphqlDirective = F::GraphqlDirective; + + final class OutputDirective = F::OutputDirective; + + final class Template = F::Template; +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll b/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll index f0e5725eef0d..5a7c65f3d88f 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/core/Gem.qll @@ -90,6 +90,9 @@ module Gem { result = this.getAPublicModule().getStmt(_).(SingletonClass) } + /** Holds if this gem is vendored in this codebase. */ + predicate isVendored() { File.super.getParentContainer+().getBaseName() = "vendor" } + /** Gets a parameter from an exported method, which is an input to this gem. */ DataFlow::ParameterNode getAnInputParameter() { exists(MethodBase method | @@ -107,6 +110,7 @@ module Gem { DataFlow::ParameterNode getALibraryInput() { exists(GemSpec spec | exists(spec.getName()) and // we only consider `.gemspec` files that have a name + not spec.isVendored() and // if the gem is vendored its parameters are not external inputs result = spec.getAnInputParameter() ) } diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index a491cb61462a..597e6242c9dd 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 6.0.2 +version: 6.0.3 groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 781cbbe6d9f7..a8502538032b 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.6.8 + +No user-facing changes. + ## 1.6.7 No user-facing changes. diff --git a/ruby/ql/src/change-notes/released/1.6.8.md b/ruby/ql/src/change-notes/released/1.6.8.md new file mode 100644 index 000000000000..0a5d9b06c55e --- /dev/null +++ b/ruby/ql/src/change-notes/released/1.6.8.md @@ -0,0 +1,3 @@ +## 1.6.8 + +No user-facing changes. diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index 0b49adeac7da..fbc11aa62b75 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.6.7 +lastReleaseVersion: 1.6.8 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index 0f833109f18e..60d063996d4a 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 1.6.7 +version: 1.6.8 groups: - ruby - queries diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected new file mode 100644 index 000000000000..979cc77777b7 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.expected @@ -0,0 +1,10 @@ +models +edges +| implicit_return.rb:12:3:12:11 | call to source | implicit_return.rb:15:6:15:11 | call to m_body | provenance | | +nodes +| implicit_return.rb:12:3:12:11 | call to source | semmle.label | call to source | +| implicit_return.rb:15:6:15:11 | call to m_body | semmle.label | call to m_body | +subpaths +testFailures +#select +| implicit_return.rb:15:6:15:11 | call to m_body | implicit_return.rb:12:3:12:11 | call to source | implicit_return.rb:15:6:15:11 | call to m_body | $@ | implicit_return.rb:12:3:12:11 | call to source | call to source | diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql new file mode 100644 index 000000000000..fae4b68cda0e --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit-return.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import codeql.ruby.AST +import utils.test.InlineFlowTest +import DefaultFlowTest +import ValueFlow::PathGraph + +from ValueFlow::PathNode source, ValueFlow::PathNode sink +where ValueFlow::flowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb new file mode 100644 index 000000000000..2ea215902f02 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/implicit-return/implicit_return.rb @@ -0,0 +1,68 @@ +# Tests for implicit return steps in Ruby data flow. +# +# An implicit return is when no `return` statement is used; instead the +# last evaluated expression is returned. +# +# The following cases test the behaviour when the returned value is +# in the main body, a `rescue` clause, or an `else` clause, +# with and without an `ensure` clause present. + +# Simple implicit return from the method body. +def m_body + source(1) +end + +sink(m_body) # $ hasValueFlow=1 + +# Implicit return from the method body when an `ensure` clause is present. +def m_body_ensure + source(2) +ensure + source(20) +end + +sink(m_body_ensure) # $ MISSING: hasValueFlow=2 + +# Implicit return from a `rescue` clause. +def m_rescue + raise "error" +rescue + source(3) +end + +sink(m_rescue) # $ MISSING: hasValueFlow=3 + +# Implicit return from a `rescue` clause when an `ensure` clause is present. +def m_rescue_ensure + raise "error" +rescue + source(4) +ensure + source(40) +end + +sink(m_rescue_ensure) # $ MISSING: hasValueFlow=4 + +# Implicit return from an `else` clause. +def m_else + source(50) +rescue + nil +else + source(5) +end + +sink(m_else) # $ MISSING: hasValueFlow=5 + +# Implicit return from an `else` clause when an `ensure` clause is present. +def m_else_ensure + source(60) +rescue + nil +else + source(6) +ensure + nil +end + +sink(m_else_ensure) # $ MISSING: hasValueFlow=6 diff --git a/rust/ql/integration-tests/subst/file.expected b/rust/ql/integration-tests/subst/file.expected index c1ff73337f2a..407f50b5c0ea 100644 --- a/rust/ql/integration-tests/subst/file.expected +++ b/rust/ql/integration-tests/subst/file.expected @@ -1,2 +1,2 @@ -| code/test.rs:0:0:0:0 | code/test.rs | | +| code/test.rs:0:0:0:0 | code/test.rs | relative | | file://:0:0:0:0 | | | diff --git a/rust/ql/lib/CHANGELOG.md b/rust/ql/lib/CHANGELOG.md index c4da1d50e0aa..6e7ca1f1f10a 100644 --- a/rust/ql/lib/CHANGELOG.md +++ b/rust/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.19 + +No user-facing changes. + ## 0.2.18 No user-facing changes. diff --git a/rust/ql/lib/change-notes/released/0.2.19.md b/rust/ql/lib/change-notes/released/0.2.19.md new file mode 100644 index 000000000000..40c7c07e47b7 --- /dev/null +++ b/rust/ql/lib/change-notes/released/0.2.19.md @@ -0,0 +1,3 @@ +## 0.2.19 + +No user-facing changes. diff --git a/rust/ql/lib/codeql-pack.release.yml b/rust/ql/lib/codeql-pack.release.yml index 22e36b609026..b37d10786472 100644 --- a/rust/ql/lib/codeql-pack.release.yml +++ b/rust/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.2.18 +lastReleaseVersion: 0.2.19 diff --git a/rust/ql/lib/qlpack.yml b/rust/ql/lib/qlpack.yml index 70a11bff45fc..9f013c345d61 100644 --- a/rust/ql/lib/qlpack.yml +++ b/rust/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-all -version: 0.2.18 +version: 0.2.19 groups: rust extractor: rust dbscheme: rust.dbscheme diff --git a/rust/ql/src/CHANGELOG.md b/rust/ql/src/CHANGELOG.md index 1732a4853b12..e6a2f67fac00 100644 --- a/rust/ql/src/CHANGELOG.md +++ b/rust/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.40 + +No user-facing changes. + ## 0.1.39 No user-facing changes. diff --git a/rust/ql/src/change-notes/released/0.1.40.md b/rust/ql/src/change-notes/released/0.1.40.md new file mode 100644 index 000000000000..f7aacd7a077e --- /dev/null +++ b/rust/ql/src/change-notes/released/0.1.40.md @@ -0,0 +1,3 @@ +## 0.1.40 + +No user-facing changes. diff --git a/rust/ql/src/codeql-pack.release.yml b/rust/ql/src/codeql-pack.release.yml index 2ae59ee1c0ae..676d88550b91 100644 --- a/rust/ql/src/codeql-pack.release.yml +++ b/rust/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.1.39 +lastReleaseVersion: 0.1.40 diff --git a/rust/ql/src/qlpack.yml b/rust/ql/src/qlpack.yml index dee21284edae..a4a357bff44f 100644 --- a/rust/ql/src/qlpack.yml +++ b/rust/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rust-queries -version: 0.1.39 +version: 0.1.40 groups: - rust - queries diff --git a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected index 859ab8e116e8..4f8a04f22ab3 100644 --- a/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/strings/inline-taint-flow.expected @@ -8,134 +8,152 @@ models | 7 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | | 8 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | edges -| main.rs:26:9:26:9 | s | main.rs:27:19:27:19 | s | provenance | | -| main.rs:26:9:26:9 | s | main.rs:27:19:27:25 | s[...] | provenance | | -| main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | s | provenance | | -| main.rs:27:9:27:14 | sliced [&ref] | main.rs:28:16:28:21 | sliced | provenance | | -| main.rs:27:18:27:25 | &... [&ref] | main.rs:27:9:27:14 | sliced [&ref] | provenance | | -| main.rs:27:19:27:19 | s | main.rs:27:19:27:25 | s[...] | provenance | MaD:2 | -| main.rs:27:19:27:25 | s[...] | main.rs:27:18:27:25 | &... [&ref] | provenance | | -| main.rs:32:9:32:10 | s1 | main.rs:35:14:35:15 | s1 | provenance | | -| main.rs:32:14:32:23 | source(...) | main.rs:32:9:32:10 | s1 | provenance | | -| main.rs:35:9:35:10 | s4 | main.rs:38:10:38:11 | s4 | provenance | | -| main.rs:35:14:35:15 | s1 | main.rs:35:14:35:20 | ... + ... | provenance | MaD:5 | -| main.rs:35:14:35:20 | ... + ... | main.rs:35:9:35:10 | s4 | provenance | | -| main.rs:43:9:43:10 | s1 | main.rs:46:34:46:35 | s1 | provenance | | -| main.rs:43:14:43:23 | source(...) | main.rs:43:9:43:10 | s1 | provenance | | -| main.rs:46:33:46:35 | &s1 [&ref] | main.rs:46:10:46:35 | ... + ... | provenance | MaD:4 | -| main.rs:46:34:46:35 | s1 | main.rs:46:33:46:35 | &s1 [&ref] | provenance | | -| main.rs:51:9:51:10 | s1 | main.rs:52:27:52:28 | s1 | provenance | | -| main.rs:51:14:51:29 | source_slice(...) | main.rs:51:9:51:10 | s1 | provenance | | -| main.rs:52:9:52:10 | s2 | main.rs:53:10:53:11 | s2 | provenance | | -| main.rs:52:14:52:29 | ...::from(...) | main.rs:52:9:52:10 | s2 | provenance | | -| main.rs:52:27:52:28 | s1 | main.rs:52:14:52:29 | ...::from(...) | provenance | MaD:3 | -| main.rs:57:9:57:10 | s1 | main.rs:58:14:58:15 | s1 | provenance | | -| main.rs:57:14:57:29 | source_slice(...) | main.rs:57:9:57:10 | s1 | provenance | | -| main.rs:58:9:58:10 | s2 | main.rs:59:10:59:11 | s2 | provenance | | -| main.rs:58:14:58:15 | s1 | main.rs:58:14:58:27 | s1.to_string() | provenance | MaD:1 | -| main.rs:58:14:58:27 | s1.to_string() | main.rs:58:9:58:10 | s2 | provenance | | -| main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | | -| main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | | -| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:6 | -| main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | | -| main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | | -| main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | | -| main.rs:70:9:70:18 | formatted1 | main.rs:71:10:71:19 | formatted1 | provenance | | -| main.rs:70:22:70:62 | ...::format(...) | main.rs:70:9:70:18 | formatted1 | provenance | | -| main.rs:70:34:70:61 | MacroExpr | main.rs:70:22:70:62 | ...::format(...) | provenance | MaD:7 | -| main.rs:73:9:73:18 | formatted2 | main.rs:74:10:74:19 | formatted2 | provenance | | -| main.rs:73:22:73:60 | ...::format(...) | main.rs:73:9:73:18 | formatted2 | provenance | | -| main.rs:73:34:73:59 | MacroExpr | main.rs:73:22:73:60 | ...::format(...) | provenance | MaD:7 | -| main.rs:76:9:76:13 | width | main.rs:77:34:77:74 | MacroExpr | provenance | | -| main.rs:76:17:76:32 | source_usize(...) | main.rs:76:9:76:13 | width | provenance | | -| main.rs:77:9:77:18 | formatted3 | main.rs:78:10:78:19 | formatted3 | provenance | | -| main.rs:77:22:77:75 | ...::format(...) | main.rs:77:9:77:18 | formatted3 | provenance | | -| main.rs:77:34:77:74 | MacroExpr | main.rs:77:22:77:75 | ...::format(...) | provenance | MaD:7 | -| main.rs:82:9:82:10 | s1 | main.rs:86:18:86:25 | MacroExpr | provenance | | -| main.rs:82:9:82:10 | s1 | main.rs:87:18:87:32 | MacroExpr | provenance | | -| main.rs:82:14:82:23 | source(...) | main.rs:82:9:82:10 | s1 | provenance | | -| main.rs:86:18:86:25 | ...::format(...) | main.rs:86:18:86:25 | { ... } | provenance | | -| main.rs:86:18:86:25 | ...::must_use(...) | main.rs:86:10:86:26 | MacroExpr | provenance | | -| main.rs:86:18:86:25 | MacroExpr | main.rs:86:18:86:25 | ...::format(...) | provenance | MaD:7 | -| main.rs:86:18:86:25 | { ... } | main.rs:86:18:86:25 | ...::must_use(...) | provenance | MaD:8 | -| main.rs:87:18:87:32 | ...::format(...) | main.rs:87:18:87:32 | { ... } | provenance | | -| main.rs:87:18:87:32 | ...::must_use(...) | main.rs:87:10:87:33 | MacroExpr | provenance | | -| main.rs:87:18:87:32 | MacroExpr | main.rs:87:18:87:32 | ...::format(...) | provenance | MaD:7 | -| main.rs:87:18:87:32 | { ... } | main.rs:87:18:87:32 | ...::must_use(...) | provenance | MaD:8 | +| main.rs:27:9:27:9 | s | main.rs:28:19:28:19 | s | provenance | | +| main.rs:27:9:27:9 | s | main.rs:28:19:28:25 | s[...] | provenance | | +| main.rs:27:13:27:22 | source(...) | main.rs:27:9:27:9 | s | provenance | | +| main.rs:28:9:28:14 | sliced [&ref] | main.rs:29:16:29:21 | sliced | provenance | | +| main.rs:28:18:28:25 | &... [&ref] | main.rs:28:9:28:14 | sliced [&ref] | provenance | | +| main.rs:28:19:28:19 | s | main.rs:28:19:28:25 | s[...] | provenance | MaD:2 | +| main.rs:28:19:28:25 | s[...] | main.rs:28:18:28:25 | &... [&ref] | provenance | | +| main.rs:33:9:33:10 | s1 | main.rs:36:14:36:15 | s1 | provenance | | +| main.rs:33:14:33:23 | source(...) | main.rs:33:9:33:10 | s1 | provenance | | +| main.rs:36:9:36:10 | s4 | main.rs:39:10:39:11 | s4 | provenance | | +| main.rs:36:14:36:15 | s1 | main.rs:36:14:36:20 | ... + ... | provenance | MaD:5 | +| main.rs:36:14:36:20 | ... + ... | main.rs:36:9:36:10 | s4 | provenance | | +| main.rs:44:9:44:10 | s1 | main.rs:47:34:47:35 | s1 | provenance | | +| main.rs:44:14:44:23 | source(...) | main.rs:44:9:44:10 | s1 | provenance | | +| main.rs:47:33:47:35 | &s1 [&ref] | main.rs:47:10:47:35 | ... + ... | provenance | MaD:4 | +| main.rs:47:34:47:35 | s1 | main.rs:47:33:47:35 | &s1 [&ref] | provenance | | +| main.rs:52:9:52:10 | s1 | main.rs:53:27:53:28 | s1 | provenance | | +| main.rs:52:14:52:29 | source_slice(...) | main.rs:52:9:52:10 | s1 | provenance | | +| main.rs:53:9:53:10 | s2 | main.rs:54:10:54:11 | s2 | provenance | | +| main.rs:53:14:53:29 | ...::from(...) | main.rs:53:9:53:10 | s2 | provenance | | +| main.rs:53:27:53:28 | s1 | main.rs:53:14:53:29 | ...::from(...) | provenance | MaD:3 | +| main.rs:58:9:58:10 | s1 | main.rs:59:14:59:15 | s1 | provenance | | +| main.rs:58:14:58:29 | source_slice(...) | main.rs:58:9:58:10 | s1 | provenance | | +| main.rs:59:9:59:10 | s2 | main.rs:60:10:60:11 | s2 | provenance | | +| main.rs:59:14:59:15 | s1 | main.rs:59:14:59:27 | s1.to_string() | provenance | MaD:1 | +| main.rs:59:14:59:27 | s1.to_string() | main.rs:59:9:59:10 | s2 | provenance | | +| main.rs:64:9:64:9 | s | main.rs:65:16:65:16 | s | provenance | | +| main.rs:64:13:64:22 | source(...) | main.rs:64:9:64:9 | s | provenance | | +| main.rs:65:16:65:16 | s | main.rs:65:16:65:25 | s.as_str() | provenance | MaD:6 | +| main.rs:69:9:69:9 | s | main.rs:71:34:71:61 | MacroExpr | provenance | | +| main.rs:69:9:69:9 | s | main.rs:74:34:74:59 | MacroExpr | provenance | | +| main.rs:69:9:69:9 | s | main.rs:81:39:81:64 | MacroExpr | provenance | | +| main.rs:69:9:69:9 | s | main.rs:84:41:84:66 | MacroExpr | provenance | | +| main.rs:69:13:69:22 | source(...) | main.rs:69:9:69:9 | s | provenance | | +| main.rs:71:9:71:18 | formatted1 | main.rs:72:10:72:19 | formatted1 | provenance | | +| main.rs:71:22:71:62 | ...::format(...) | main.rs:71:9:71:18 | formatted1 | provenance | | +| main.rs:71:34:71:61 | MacroExpr | main.rs:71:22:71:62 | ...::format(...) | provenance | MaD:7 | +| main.rs:74:9:74:18 | formatted2 | main.rs:75:10:75:19 | formatted2 | provenance | | +| main.rs:74:22:74:60 | ...::format(...) | main.rs:74:9:74:18 | formatted2 | provenance | | +| main.rs:74:34:74:59 | MacroExpr | main.rs:74:22:74:60 | ...::format(...) | provenance | MaD:7 | +| main.rs:77:9:77:13 | width | main.rs:78:34:78:74 | MacroExpr | provenance | | +| main.rs:77:17:77:32 | source_usize(...) | main.rs:77:9:77:13 | width | provenance | | +| main.rs:78:9:78:18 | formatted3 | main.rs:79:10:79:19 | formatted3 | provenance | | +| main.rs:78:22:78:75 | ...::format(...) | main.rs:78:9:78:18 | formatted3 | provenance | | +| main.rs:78:34:78:74 | MacroExpr | main.rs:78:22:78:75 | ...::format(...) | provenance | MaD:7 | +| main.rs:81:9:81:18 | formatted4 | main.rs:82:10:82:19 | formatted4 | provenance | | +| main.rs:81:22:81:65 | ...::format(...) | main.rs:81:9:81:18 | formatted4 | provenance | | +| main.rs:81:39:81:64 | MacroExpr | main.rs:81:22:81:65 | ...::format(...) | provenance | MaD:7 | +| main.rs:84:9:84:18 | formatted5 | main.rs:85:10:85:19 | formatted5 | provenance | | +| main.rs:84:22:84:67 | ...::format(...) | main.rs:84:9:84:18 | formatted5 | provenance | | +| main.rs:84:41:84:66 | MacroExpr | main.rs:84:22:84:67 | ...::format(...) | provenance | MaD:7 | +| main.rs:89:9:89:10 | s1 | main.rs:93:18:93:25 | MacroExpr | provenance | | +| main.rs:89:9:89:10 | s1 | main.rs:94:18:94:32 | MacroExpr | provenance | | +| main.rs:89:14:89:23 | source(...) | main.rs:89:9:89:10 | s1 | provenance | | +| main.rs:93:18:93:25 | ...::format(...) | main.rs:93:18:93:25 | { ... } | provenance | | +| main.rs:93:18:93:25 | ...::must_use(...) | main.rs:93:10:93:26 | MacroExpr | provenance | | +| main.rs:93:18:93:25 | MacroExpr | main.rs:93:18:93:25 | ...::format(...) | provenance | MaD:7 | +| main.rs:93:18:93:25 | { ... } | main.rs:93:18:93:25 | ...::must_use(...) | provenance | MaD:8 | +| main.rs:94:18:94:32 | ...::format(...) | main.rs:94:18:94:32 | { ... } | provenance | | +| main.rs:94:18:94:32 | ...::must_use(...) | main.rs:94:10:94:33 | MacroExpr | provenance | | +| main.rs:94:18:94:32 | MacroExpr | main.rs:94:18:94:32 | ...::format(...) | provenance | MaD:7 | +| main.rs:94:18:94:32 | { ... } | main.rs:94:18:94:32 | ...::must_use(...) | provenance | MaD:8 | nodes -| main.rs:26:9:26:9 | s | semmle.label | s | -| main.rs:26:13:26:22 | source(...) | semmle.label | source(...) | -| main.rs:27:9:27:14 | sliced [&ref] | semmle.label | sliced [&ref] | -| main.rs:27:18:27:25 | &... [&ref] | semmle.label | &... [&ref] | -| main.rs:27:19:27:19 | s | semmle.label | s | -| main.rs:27:19:27:25 | s[...] | semmle.label | s[...] | -| main.rs:28:16:28:21 | sliced | semmle.label | sliced | -| main.rs:32:9:32:10 | s1 | semmle.label | s1 | -| main.rs:32:14:32:23 | source(...) | semmle.label | source(...) | -| main.rs:35:9:35:10 | s4 | semmle.label | s4 | -| main.rs:35:14:35:15 | s1 | semmle.label | s1 | -| main.rs:35:14:35:20 | ... + ... | semmle.label | ... + ... | -| main.rs:38:10:38:11 | s4 | semmle.label | s4 | -| main.rs:43:9:43:10 | s1 | semmle.label | s1 | -| main.rs:43:14:43:23 | source(...) | semmle.label | source(...) | -| main.rs:46:10:46:35 | ... + ... | semmle.label | ... + ... | -| main.rs:46:33:46:35 | &s1 [&ref] | semmle.label | &s1 [&ref] | -| main.rs:46:34:46:35 | s1 | semmle.label | s1 | -| main.rs:51:9:51:10 | s1 | semmle.label | s1 | -| main.rs:51:14:51:29 | source_slice(...) | semmle.label | source_slice(...) | -| main.rs:52:9:52:10 | s2 | semmle.label | s2 | -| main.rs:52:14:52:29 | ...::from(...) | semmle.label | ...::from(...) | -| main.rs:52:27:52:28 | s1 | semmle.label | s1 | -| main.rs:53:10:53:11 | s2 | semmle.label | s2 | -| main.rs:57:9:57:10 | s1 | semmle.label | s1 | -| main.rs:57:14:57:29 | source_slice(...) | semmle.label | source_slice(...) | -| main.rs:58:9:58:10 | s2 | semmle.label | s2 | -| main.rs:58:14:58:15 | s1 | semmle.label | s1 | -| main.rs:58:14:58:27 | s1.to_string() | semmle.label | s1.to_string() | -| main.rs:59:10:59:11 | s2 | semmle.label | s2 | -| main.rs:63:9:63:9 | s | semmle.label | s | -| main.rs:63:13:63:22 | source(...) | semmle.label | source(...) | -| main.rs:64:16:64:16 | s | semmle.label | s | -| main.rs:64:16:64:25 | s.as_str() | semmle.label | s.as_str() | -| main.rs:68:9:68:9 | s | semmle.label | s | -| main.rs:68:13:68:22 | source(...) | semmle.label | source(...) | -| main.rs:70:9:70:18 | formatted1 | semmle.label | formatted1 | -| main.rs:70:22:70:62 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:70:34:70:61 | MacroExpr | semmle.label | MacroExpr | -| main.rs:71:10:71:19 | formatted1 | semmle.label | formatted1 | -| main.rs:73:9:73:18 | formatted2 | semmle.label | formatted2 | -| main.rs:73:22:73:60 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:73:34:73:59 | MacroExpr | semmle.label | MacroExpr | -| main.rs:74:10:74:19 | formatted2 | semmle.label | formatted2 | -| main.rs:76:9:76:13 | width | semmle.label | width | -| main.rs:76:17:76:32 | source_usize(...) | semmle.label | source_usize(...) | -| main.rs:77:9:77:18 | formatted3 | semmle.label | formatted3 | -| main.rs:77:22:77:75 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:77:34:77:74 | MacroExpr | semmle.label | MacroExpr | -| main.rs:78:10:78:19 | formatted3 | semmle.label | formatted3 | -| main.rs:82:9:82:10 | s1 | semmle.label | s1 | -| main.rs:82:14:82:23 | source(...) | semmle.label | source(...) | -| main.rs:86:10:86:26 | MacroExpr | semmle.label | MacroExpr | -| main.rs:86:18:86:25 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:86:18:86:25 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:86:18:86:25 | MacroExpr | semmle.label | MacroExpr | -| main.rs:86:18:86:25 | { ... } | semmle.label | { ... } | -| main.rs:87:10:87:33 | MacroExpr | semmle.label | MacroExpr | -| main.rs:87:18:87:32 | ...::format(...) | semmle.label | ...::format(...) | -| main.rs:87:18:87:32 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| main.rs:87:18:87:32 | MacroExpr | semmle.label | MacroExpr | -| main.rs:87:18:87:32 | { ... } | semmle.label | { ... } | +| main.rs:27:9:27:9 | s | semmle.label | s | +| main.rs:27:13:27:22 | source(...) | semmle.label | source(...) | +| main.rs:28:9:28:14 | sliced [&ref] | semmle.label | sliced [&ref] | +| main.rs:28:18:28:25 | &... [&ref] | semmle.label | &... [&ref] | +| main.rs:28:19:28:19 | s | semmle.label | s | +| main.rs:28:19:28:25 | s[...] | semmle.label | s[...] | +| main.rs:29:16:29:21 | sliced | semmle.label | sliced | +| main.rs:33:9:33:10 | s1 | semmle.label | s1 | +| main.rs:33:14:33:23 | source(...) | semmle.label | source(...) | +| main.rs:36:9:36:10 | s4 | semmle.label | s4 | +| main.rs:36:14:36:15 | s1 | semmle.label | s1 | +| main.rs:36:14:36:20 | ... + ... | semmle.label | ... + ... | +| main.rs:39:10:39:11 | s4 | semmle.label | s4 | +| main.rs:44:9:44:10 | s1 | semmle.label | s1 | +| main.rs:44:14:44:23 | source(...) | semmle.label | source(...) | +| main.rs:47:10:47:35 | ... + ... | semmle.label | ... + ... | +| main.rs:47:33:47:35 | &s1 [&ref] | semmle.label | &s1 [&ref] | +| main.rs:47:34:47:35 | s1 | semmle.label | s1 | +| main.rs:52:9:52:10 | s1 | semmle.label | s1 | +| main.rs:52:14:52:29 | source_slice(...) | semmle.label | source_slice(...) | +| main.rs:53:9:53:10 | s2 | semmle.label | s2 | +| main.rs:53:14:53:29 | ...::from(...) | semmle.label | ...::from(...) | +| main.rs:53:27:53:28 | s1 | semmle.label | s1 | +| main.rs:54:10:54:11 | s2 | semmle.label | s2 | +| main.rs:58:9:58:10 | s1 | semmle.label | s1 | +| main.rs:58:14:58:29 | source_slice(...) | semmle.label | source_slice(...) | +| main.rs:59:9:59:10 | s2 | semmle.label | s2 | +| main.rs:59:14:59:15 | s1 | semmle.label | s1 | +| main.rs:59:14:59:27 | s1.to_string() | semmle.label | s1.to_string() | +| main.rs:60:10:60:11 | s2 | semmle.label | s2 | +| main.rs:64:9:64:9 | s | semmle.label | s | +| main.rs:64:13:64:22 | source(...) | semmle.label | source(...) | +| main.rs:65:16:65:16 | s | semmle.label | s | +| main.rs:65:16:65:25 | s.as_str() | semmle.label | s.as_str() | +| main.rs:69:9:69:9 | s | semmle.label | s | +| main.rs:69:13:69:22 | source(...) | semmle.label | source(...) | +| main.rs:71:9:71:18 | formatted1 | semmle.label | formatted1 | +| main.rs:71:22:71:62 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:71:34:71:61 | MacroExpr | semmle.label | MacroExpr | +| main.rs:72:10:72:19 | formatted1 | semmle.label | formatted1 | +| main.rs:74:9:74:18 | formatted2 | semmle.label | formatted2 | +| main.rs:74:22:74:60 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:74:34:74:59 | MacroExpr | semmle.label | MacroExpr | +| main.rs:75:10:75:19 | formatted2 | semmle.label | formatted2 | +| main.rs:77:9:77:13 | width | semmle.label | width | +| main.rs:77:17:77:32 | source_usize(...) | semmle.label | source_usize(...) | +| main.rs:78:9:78:18 | formatted3 | semmle.label | formatted3 | +| main.rs:78:22:78:75 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:78:34:78:74 | MacroExpr | semmle.label | MacroExpr | +| main.rs:79:10:79:19 | formatted3 | semmle.label | formatted3 | +| main.rs:81:9:81:18 | formatted4 | semmle.label | formatted4 | +| main.rs:81:22:81:65 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:81:39:81:64 | MacroExpr | semmle.label | MacroExpr | +| main.rs:82:10:82:19 | formatted4 | semmle.label | formatted4 | +| main.rs:84:9:84:18 | formatted5 | semmle.label | formatted5 | +| main.rs:84:22:84:67 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:84:41:84:66 | MacroExpr | semmle.label | MacroExpr | +| main.rs:85:10:85:19 | formatted5 | semmle.label | formatted5 | +| main.rs:89:9:89:10 | s1 | semmle.label | s1 | +| main.rs:89:14:89:23 | source(...) | semmle.label | source(...) | +| main.rs:93:10:93:26 | MacroExpr | semmle.label | MacroExpr | +| main.rs:93:18:93:25 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:93:18:93:25 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:93:18:93:25 | MacroExpr | semmle.label | MacroExpr | +| main.rs:93:18:93:25 | { ... } | semmle.label | { ... } | +| main.rs:94:10:94:33 | MacroExpr | semmle.label | MacroExpr | +| main.rs:94:18:94:32 | ...::format(...) | semmle.label | ...::format(...) | +| main.rs:94:18:94:32 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| main.rs:94:18:94:32 | MacroExpr | semmle.label | MacroExpr | +| main.rs:94:18:94:32 | { ... } | semmle.label | { ... } | subpaths testFailures #select -| main.rs:28:16:28:21 | sliced | main.rs:26:13:26:22 | source(...) | main.rs:28:16:28:21 | sliced | $@ | main.rs:26:13:26:22 | source(...) | source(...) | -| main.rs:38:10:38:11 | s4 | main.rs:32:14:32:23 | source(...) | main.rs:38:10:38:11 | s4 | $@ | main.rs:32:14:32:23 | source(...) | source(...) | -| main.rs:46:10:46:35 | ... + ... | main.rs:43:14:43:23 | source(...) | main.rs:46:10:46:35 | ... + ... | $@ | main.rs:43:14:43:23 | source(...) | source(...) | -| main.rs:53:10:53:11 | s2 | main.rs:51:14:51:29 | source_slice(...) | main.rs:53:10:53:11 | s2 | $@ | main.rs:51:14:51:29 | source_slice(...) | source_slice(...) | -| main.rs:59:10:59:11 | s2 | main.rs:57:14:57:29 | source_slice(...) | main.rs:59:10:59:11 | s2 | $@ | main.rs:57:14:57:29 | source_slice(...) | source_slice(...) | -| main.rs:64:16:64:25 | s.as_str() | main.rs:63:13:63:22 | source(...) | main.rs:64:16:64:25 | s.as_str() | $@ | main.rs:63:13:63:22 | source(...) | source(...) | -| main.rs:71:10:71:19 | formatted1 | main.rs:68:13:68:22 | source(...) | main.rs:71:10:71:19 | formatted1 | $@ | main.rs:68:13:68:22 | source(...) | source(...) | -| main.rs:74:10:74:19 | formatted2 | main.rs:68:13:68:22 | source(...) | main.rs:74:10:74:19 | formatted2 | $@ | main.rs:68:13:68:22 | source(...) | source(...) | -| main.rs:78:10:78:19 | formatted3 | main.rs:76:17:76:32 | source_usize(...) | main.rs:78:10:78:19 | formatted3 | $@ | main.rs:76:17:76:32 | source_usize(...) | source_usize(...) | -| main.rs:86:10:86:26 | MacroExpr | main.rs:82:14:82:23 | source(...) | main.rs:86:10:86:26 | MacroExpr | $@ | main.rs:82:14:82:23 | source(...) | source(...) | -| main.rs:87:10:87:33 | MacroExpr | main.rs:82:14:82:23 | source(...) | main.rs:87:10:87:33 | MacroExpr | $@ | main.rs:82:14:82:23 | source(...) | source(...) | +| main.rs:29:16:29:21 | sliced | main.rs:27:13:27:22 | source(...) | main.rs:29:16:29:21 | sliced | $@ | main.rs:27:13:27:22 | source(...) | source(...) | +| main.rs:39:10:39:11 | s4 | main.rs:33:14:33:23 | source(...) | main.rs:39:10:39:11 | s4 | $@ | main.rs:33:14:33:23 | source(...) | source(...) | +| main.rs:47:10:47:35 | ... + ... | main.rs:44:14:44:23 | source(...) | main.rs:47:10:47:35 | ... + ... | $@ | main.rs:44:14:44:23 | source(...) | source(...) | +| main.rs:54:10:54:11 | s2 | main.rs:52:14:52:29 | source_slice(...) | main.rs:54:10:54:11 | s2 | $@ | main.rs:52:14:52:29 | source_slice(...) | source_slice(...) | +| main.rs:60:10:60:11 | s2 | main.rs:58:14:58:29 | source_slice(...) | main.rs:60:10:60:11 | s2 | $@ | main.rs:58:14:58:29 | source_slice(...) | source_slice(...) | +| main.rs:65:16:65:25 | s.as_str() | main.rs:64:13:64:22 | source(...) | main.rs:65:16:65:25 | s.as_str() | $@ | main.rs:64:13:64:22 | source(...) | source(...) | +| main.rs:72:10:72:19 | formatted1 | main.rs:69:13:69:22 | source(...) | main.rs:72:10:72:19 | formatted1 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:75:10:75:19 | formatted2 | main.rs:69:13:69:22 | source(...) | main.rs:75:10:75:19 | formatted2 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:79:10:79:19 | formatted3 | main.rs:77:17:77:32 | source_usize(...) | main.rs:79:10:79:19 | formatted3 | $@ | main.rs:77:17:77:32 | source_usize(...) | source_usize(...) | +| main.rs:82:10:82:19 | formatted4 | main.rs:69:13:69:22 | source(...) | main.rs:82:10:82:19 | formatted4 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:85:10:85:19 | formatted5 | main.rs:69:13:69:22 | source(...) | main.rs:85:10:85:19 | formatted5 | $@ | main.rs:69:13:69:22 | source(...) | source(...) | +| main.rs:93:10:93:26 | MacroExpr | main.rs:89:14:89:23 | source(...) | main.rs:93:10:93:26 | MacroExpr | $@ | main.rs:89:14:89:23 | source(...) | source(...) | +| main.rs:94:10:94:33 | MacroExpr | main.rs:89:14:89:23 | source(...) | main.rs:94:10:94:33 | MacroExpr | $@ | main.rs:89:14:89:23 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/strings/main.rs b/rust/ql/test/library-tests/dataflow/strings/main.rs index 0afcc290e568..12ee31663b82 100644 --- a/rust/ql/test/library-tests/dataflow/strings/main.rs +++ b/rust/ql/test/library-tests/dataflow/strings/main.rs @@ -1,4 +1,5 @@ use std::fmt; +extern crate alloc; // Taint tests for strings @@ -76,6 +77,12 @@ fn format_args_built_in() { let width = source_usize(10); let formatted3 = fmt::format(format_args!("Hello {:width$}!", "World")); sink(formatted3); // $ hasTaintFlow=10 + + let formatted4 = std::fmt::format(format_args!("Hello {s}!")); + sink(formatted4); // $ hasTaintFlow=88 + + let formatted5 = alloc::fmt::format(format_args!("Hello {s}!")); + sink(formatted5); // $ hasTaintFlow=88 } fn format_macro() { diff --git a/shared/concepts/CHANGELOG.md b/shared/concepts/CHANGELOG.md index 772a7934b5c2..9acabbed4e46 100644 --- a/shared/concepts/CHANGELOG.md +++ b/shared/concepts/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.29 + +No user-facing changes. + ## 0.0.28 No user-facing changes. diff --git a/shared/concepts/change-notes/released/0.0.29.md b/shared/concepts/change-notes/released/0.0.29.md new file mode 100644 index 000000000000..4428927c79d5 --- /dev/null +++ b/shared/concepts/change-notes/released/0.0.29.md @@ -0,0 +1,3 @@ +## 0.0.29 + +No user-facing changes. diff --git a/shared/concepts/codeql-pack.release.yml b/shared/concepts/codeql-pack.release.yml index 3462db7d348f..c81f18131208 100644 --- a/shared/concepts/codeql-pack.release.yml +++ b/shared/concepts/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.28 +lastReleaseVersion: 0.0.29 diff --git a/shared/concepts/qlpack.yml b/shared/concepts/qlpack.yml index 682474b6be37..b00bbb9f887b 100644 --- a/shared/concepts/qlpack.yml +++ b/shared/concepts/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/concepts -version: 0.0.28 +version: 0.0.29 groups: shared library: true dependencies: diff --git a/shared/controlflow/CHANGELOG.md b/shared/controlflow/CHANGELOG.md index 1cd70884e88b..9abcc742814f 100644 --- a/shared/controlflow/CHANGELOG.md +++ b/shared/controlflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.39 + +No user-facing changes. + ## 2.0.38 No user-facing changes. diff --git a/shared/controlflow/change-notes/released/2.0.39.md b/shared/controlflow/change-notes/released/2.0.39.md new file mode 100644 index 000000000000..887d030df420 --- /dev/null +++ b/shared/controlflow/change-notes/released/2.0.39.md @@ -0,0 +1,3 @@ +## 2.0.39 + +No user-facing changes. diff --git a/shared/controlflow/codeql-pack.release.yml b/shared/controlflow/codeql-pack.release.yml index 4ec9eb0980cf..063a268e5f9f 100644 --- a/shared/controlflow/codeql-pack.release.yml +++ b/shared/controlflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.38 +lastReleaseVersion: 2.0.39 diff --git a/shared/controlflow/qlpack.yml b/shared/controlflow/qlpack.yml index 9d89f4e45026..d3cc00f776ed 100644 --- a/shared/controlflow/qlpack.yml +++ b/shared/controlflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/controlflow -version: 2.0.38 +version: 2.0.39 groups: shared library: true dependencies: diff --git a/shared/dataflow/CHANGELOG.md b/shared/dataflow/CHANGELOG.md index 957500952a2d..8b981f92142e 100644 --- a/shared/dataflow/CHANGELOG.md +++ b/shared/dataflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.11 + +No user-facing changes. + ## 2.1.10 No user-facing changes. diff --git a/shared/dataflow/change-notes/released/2.1.11.md b/shared/dataflow/change-notes/released/2.1.11.md new file mode 100644 index 000000000000..16b106c2f6c9 --- /dev/null +++ b/shared/dataflow/change-notes/released/2.1.11.md @@ -0,0 +1,3 @@ +## 2.1.11 + +No user-facing changes. diff --git a/shared/dataflow/codeql-pack.release.yml b/shared/dataflow/codeql-pack.release.yml index 66c655c4b892..768e745f3b43 100644 --- a/shared/dataflow/codeql-pack.release.yml +++ b/shared/dataflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.1.10 +lastReleaseVersion: 2.1.11 diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index ce4f56dd87f1..3c53868dc3ce 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/dataflow -version: 2.1.10 +version: 2.1.11 groups: shared library: true dependencies: diff --git a/shared/mad/CHANGELOG.md b/shared/mad/CHANGELOG.md index b1e3e366b72c..3a981e317c75 100644 --- a/shared/mad/CHANGELOG.md +++ b/shared/mad/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/mad/change-notes/released/1.0.55.md b/shared/mad/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/mad/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/mad/codeql-pack.release.yml b/shared/mad/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/mad/codeql-pack.release.yml +++ b/shared/mad/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/mad/codeql/mad/ModelValidation.qll b/shared/mad/codeql/mad/ModelValidation.qll index 58e13dc96008..47a3c24adce1 100644 --- a/shared/mad/codeql/mad/ModelValidation.qll +++ b/shared/mad/codeql/mad/ModelValidation.qll @@ -132,7 +132,9 @@ module KindValidation { // C# "file-write", "windows-registry", // JavaScript - "database-access-result", "response", "request" + "database-access-result", "response", "request", "browser", "browser-url-query", + "browser-url-fragment", "browser-url-path", "browser-url", "browser-window-name", + "browser-message-event" ] or this.matches([ diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index 02fff19b4d6e..72caf44fdad2 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/mad -version: 1.0.54 +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/namebinding/CHANGELOG.md b/shared/namebinding/CHANGELOG.md index d7831747b120..4ffbff1e0c4e 100644 --- a/shared/namebinding/CHANGELOG.md +++ b/shared/namebinding/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4 + +No user-facing changes. + ## 0.0.3 No user-facing changes. diff --git a/shared/namebinding/change-notes/released/0.0.4.md b/shared/namebinding/change-notes/released/0.0.4.md new file mode 100644 index 000000000000..eefe286a4d88 --- /dev/null +++ b/shared/namebinding/change-notes/released/0.0.4.md @@ -0,0 +1,3 @@ +## 0.0.4 + +No user-facing changes. diff --git a/shared/namebinding/codeql-pack.release.yml b/shared/namebinding/codeql-pack.release.yml index a24b693d1e7a..ec411a674bcd 100644 --- a/shared/namebinding/codeql-pack.release.yml +++ b/shared/namebinding/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.3 +lastReleaseVersion: 0.0.4 diff --git a/shared/namebinding/qlpack.yml b/shared/namebinding/qlpack.yml index 5f70711b4497..587b6de4f125 100644 --- a/shared/namebinding/qlpack.yml +++ b/shared/namebinding/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/namebinding -version: 0.0.3 +version: 0.0.4 groups: shared library: true dependencies: diff --git a/shared/quantum/CHANGELOG.md b/shared/quantum/CHANGELOG.md index 24dc81f3aa2c..66b8fa3444bb 100644 --- a/shared/quantum/CHANGELOG.md +++ b/shared/quantum/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.33 + +No user-facing changes. + ## 0.0.32 No user-facing changes. diff --git a/shared/quantum/change-notes/released/0.0.33.md b/shared/quantum/change-notes/released/0.0.33.md new file mode 100644 index 000000000000..0b46f1130fac --- /dev/null +++ b/shared/quantum/change-notes/released/0.0.33.md @@ -0,0 +1,3 @@ +## 0.0.33 + +No user-facing changes. diff --git a/shared/quantum/codeql-pack.release.yml b/shared/quantum/codeql-pack.release.yml index 714fcfc18281..dff9e7f6ea97 100644 --- a/shared/quantum/codeql-pack.release.yml +++ b/shared/quantum/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.32 +lastReleaseVersion: 0.0.33 diff --git a/shared/quantum/qlpack.yml b/shared/quantum/qlpack.yml index f0041559dc38..c26d83a0a25f 100644 --- a/shared/quantum/qlpack.yml +++ b/shared/quantum/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/quantum -version: 0.0.32 +version: 0.0.33 groups: shared library: true dependencies: diff --git a/shared/rangeanalysis/CHANGELOG.md b/shared/rangeanalysis/CHANGELOG.md index d3f599dc28ff..3a874c765ab7 100644 --- a/shared/rangeanalysis/CHANGELOG.md +++ b/shared/rangeanalysis/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/rangeanalysis/change-notes/released/1.0.55.md b/shared/rangeanalysis/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/rangeanalysis/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/rangeanalysis/codeql-pack.release.yml b/shared/rangeanalysis/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/rangeanalysis/codeql-pack.release.yml +++ b/shared/rangeanalysis/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/rangeanalysis/qlpack.yml b/shared/rangeanalysis/qlpack.yml index 2897d92e18ca..d8b0292bfdae 100644 --- a/shared/rangeanalysis/qlpack.yml +++ b/shared/rangeanalysis/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/rangeanalysis -version: 1.0.54 +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md index 4b02993bb99f..bbfe25191a71 100644 --- a/shared/regex/CHANGELOG.md +++ b/shared/regex/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/regex/change-notes/released/1.0.55.md b/shared/regex/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/regex/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/regex/codeql-pack.release.yml +++ b/shared/regex/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 9bd5da070ba2..187bb5f5af95 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 1.0.54 +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md index 2bc90a791ab0..b742fb0a2601 100644 --- a/shared/ssa/CHANGELOG.md +++ b/shared/ssa/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.31 + +No user-facing changes. + ## 2.0.30 No user-facing changes. diff --git a/shared/ssa/change-notes/released/2.0.31.md b/shared/ssa/change-notes/released/2.0.31.md new file mode 100644 index 000000000000..b3cd05e3de4d --- /dev/null +++ b/shared/ssa/change-notes/released/2.0.31.md @@ -0,0 +1,3 @@ +## 2.0.31 + +No user-facing changes. diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml index 19c804295854..783d47207cda 100644 --- a/shared/ssa/codeql-pack.release.yml +++ b/shared/ssa/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.30 +lastReleaseVersion: 2.0.31 diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 54c3f98c10b8..a66e5225abd0 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ssa -version: 2.0.30 +version: 2.0.31 groups: shared library: true dependencies: diff --git a/shared/threat-models/CHANGELOG.md b/shared/threat-models/CHANGELOG.md index d75ab9a9e2d7..3a3948e7bf27 100644 --- a/shared/threat-models/CHANGELOG.md +++ b/shared/threat-models/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/threat-models/change-notes/released/1.0.55.md b/shared/threat-models/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/threat-models/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/threat-models/codeql-pack.release.yml b/shared/threat-models/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/threat-models/codeql-pack.release.yml +++ b/shared/threat-models/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/threat-models/qlpack.yml b/shared/threat-models/qlpack.yml index 3a70d4a69374..93ab66cfc33f 100644 --- a/shared/threat-models/qlpack.yml +++ b/shared/threat-models/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/threat-models -version: 1.0.54 +version: 1.0.55 library: true groups: shared dataExtensions: diff --git a/shared/tree-sitter-extractor/src/extractor/desugaring.rs b/shared/tree-sitter-extractor/src/extractor/desugaring.rs new file mode 100644 index 000000000000..c52659750c77 --- /dev/null +++ b/shared/tree-sitter-extractor/src/extractor/desugaring.rs @@ -0,0 +1,104 @@ +//! Extraction for languages that rewrite their syntax tree before extraction. +//! +//! Unlike [`crate::extractor::simple`] (direct tree-sitter extraction), a +//! desugaring language parses source into a [`ParsedTree`] — a `yeast::Ast` +//! plus side-channel `extra` tokens (comments and similar) — and rewrites the +//! AST through a [`yeast::Desugarer`] before emitting TRAP. The parser is a +//! closure, so both tree-sitter grammars (via +//! [`crate::extractor::tree_sitter_parser`]) and fully custom parsers plug in +//! the same way. + +use crate::trap; +use std::path::PathBuf; + +use crate::diagnostics; +use crate::extractor::ParsedTree; +use crate::extractor::driver::{self, LanguageExtractor}; +use crate::node_types::{self, NodeTypeMap}; + +/// A parser turns source bytes into a [`ParsedTree`]. Tree-sitter grammars plug +/// in via [`crate::extractor::tree_sitter_parser`]; custom (non-tree-sitter) +/// parsers supply their own closure. +pub type Parser = Box Result + Send + Sync>; + +pub struct LanguageSpec { + pub prefix: &'static str, + /// The parser: source -> `yeast::Ast` + `extra` tokens (see [`Parser`]). + pub parser: Parser, + /// Fallback TRAP schema, used only when `desugarer` does not supply its own + /// output schema (via [`yeast::Desugarer::output_node_types_yaml`]). May be + /// empty for a custom parser whose desugarer always provides the schema. + pub node_types: &'static str, + /// The desugarer applied to the parsed AST before extraction. Its + /// `output_node_types_yaml()` (when set) provides the TRAP schema. + /// + /// `Box` so the shared extractor is agnostic to the + /// user-defined context type the desugarer uses internally. + pub desugarer: Box, + pub file_globs: Vec, +} + +impl LanguageExtractor for LanguageSpec { + fn file_globs(&self) -> &[String] { + &self.file_globs + } + + fn build_schema(&self) -> std::io::Result { + let effective_node_types: String = match self.desugarer.output_node_types_yaml() { + Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| { + std::io::Error::other(format!( + "Failed to convert YAML node-types to JSON for {}: {e}", + self.prefix + )) + })?, + None => self.node_types.to_string(), + }; + node_types::read_node_types_str(self.prefix, &effective_node_types) + } + + fn extract_file( + &self, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + path: &std::path::Path, + source: &[u8], + ) { + crate::extractor::extract_parsed( + self.parser.as_ref(), + self.prefix, + schema, + diagnostics_writer, + trap_writer, + None, + path, + source, + self.desugarer.as_ref(), + ); + } +} + +pub struct Extractor { + pub prefix: String, + pub languages: Vec, + pub trap_dir: PathBuf, + pub source_archive_dir: PathBuf, + pub file_lists: Vec, + // Typically constructed via `trap::Compression::from_env`. + // This allow us to report the error using our diagnostics system + // without exposing it to consumers. + pub trap_compression: Result, +} + +impl Extractor { + pub fn run(&self) -> std::io::Result<()> { + driver::run_extractor( + &self.prefix, + &self.languages, + &self.trap_dir, + &self.source_archive_dir, + &self.file_lists, + &self.trap_compression, + ) + } +} diff --git a/shared/tree-sitter-extractor/src/extractor/driver.rs b/shared/tree-sitter-extractor/src/extractor/driver.rs new file mode 100644 index 000000000000..d97d8f4c75c2 --- /dev/null +++ b/shared/tree-sitter-extractor/src/extractor/driver.rs @@ -0,0 +1,210 @@ +//! Shared multi-file extraction driver. +//! +//! The `simple` (direct tree-sitter) and `desugaring` (parse + desugar) +//! extractors differ only in how a language's schema is built and how a single +//! file is extracted. Everything else — threading, matching files to languages +//! by glob, writing TRAP, and copying into the source archive — is identical +//! and lives here, parameterised over the [`LanguageExtractor`] trait. + +use globset::{GlobBuilder, GlobSetBuilder}; +use rayon::prelude::*; +use std::fs::File; +use std::io::BufRead; +use std::path::{Path, PathBuf}; + +use crate::diagnostics; +use crate::file_paths; +use crate::node_types::NodeTypeMap; +use crate::trap; + +/// A language that [`run_extractor`] can process: it knows its file globs, its +/// TRAP schema, and how to extract a single file. Implemented by +/// [`super::simple::LanguageSpec`] (direct tree-sitter extraction) and +/// [`super::desugaring::LanguageSpec`] (parse into an AST and desugar it). +pub(crate) trait LanguageExtractor: Sync { + /// The file-name globs that select files for this language. + fn file_globs(&self) -> &[String]; + /// Build the TRAP node-type schema used to validate emitted tuples. + fn build_schema(&self) -> std::io::Result; + /// Extract a single file's `source` into `trap_writer`. + fn extract_file( + &self, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + path: &Path, + source: &[u8], + ); +} + +/// Drive extraction over `languages` for every file listed in `file_lists`. +/// +/// Sets up the thread pool, builds a combined glob set, and for each input file +/// dispatches to the matching language's [`LanguageExtractor::extract_file`], +/// writing the resulting TRAP and a source-archive copy. +pub(crate) fn run_extractor( + prefix: &str, + languages: &[L], + trap_dir: &Path, + source_archive_dir: &Path, + file_lists: &[PathBuf], + trap_compression: &Result, +) -> std::io::Result<()> { + tracing::info!("Extraction started"); + let diagnostics = diagnostics::DiagnosticLoggers::new(prefix); + let mut main_thread_logger = diagnostics.logger(); + let num_threads = match crate::options::num_threads() { + Ok(num) => num, + Err(e) => { + main_thread_logger.write( + main_thread_logger + .new_entry("configuration-error", "Configuration error") + .message( + "{}; defaulting to 1 thread.", + &[diagnostics::MessageArg::Code(&e)], + ) + .severity(diagnostics::Severity::Warning), + ); + 1 + } + }; + tracing::info!( + "Using {} {}", + num_threads, + if num_threads == 1 { + "thread" + } else { + "threads" + } + ); + let trap_compression = match trap_compression { + Ok(x) => *x, + Err(e) => { + main_thread_logger.write( + main_thread_logger + .new_entry("configuration-error", "Configuration error") + .message("{}; using gzip.", &[diagnostics::MessageArg::Code(e)]) + .severity(diagnostics::Severity::Warning), + ); + trap::Compression::Gzip + } + }; + drop(main_thread_logger); + + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .unwrap(); + + let file_lists: Vec = file_lists + .iter() + .map(|file_list| { + File::open(file_list) + .unwrap_or_else(|_| panic!("Unable to open file list at {file_list:?}")) + }) + .collect(); + + let mut schemas = vec![]; + for lang in languages { + schemas.push(lang.build_schema()?); + } + + // Construct a single globset containing all language globs, + // and a mapping from glob index to language index. + let (globset, glob_language_mapping) = { + let mut builder = GlobSetBuilder::new(); + let mut glob_lang_mapping = vec![]; + for (i, lang) in languages.iter().enumerate() { + for glob_str in lang.file_globs() { + let glob = GlobBuilder::new(glob_str) + .literal_separator(true) + .build() + .expect("invalid glob"); + builder.add(glob); + glob_lang_mapping.push(i); + } + } + ( + builder.build().expect("failed to build globset"), + glob_lang_mapping, + ) + }; + + let path_transformer = file_paths::load_path_transformer()?; + + let lines: std::io::Result> = file_lists + .iter() + .flat_map(|file_list| std::io::BufReader::new(file_list).lines()) + .collect(); + let lines = lines?; + + lines + .par_iter() + .try_for_each(|line| { + let mut diagnostics_writer = diagnostics.logger(); + let path = PathBuf::from(line).canonicalize()?; + let src_archive_file = crate::file_paths::path_for( + source_archive_dir, + &path, + "", + path_transformer.as_ref(), + ); + let source = std::fs::read(&path)?; + let mut trap_writer = trap::Writer::new(); + + match path.file_name() { + None => { + tracing::error!(?path, "No file name found, skipping file."); + } + Some(filename) => { + let matches = globset.matches(filename); + if matches.is_empty() { + tracing::error!(?path, "No matching language found, skipping file."); + } else { + let mut languages_processed = vec![false; languages.len()]; + + for m in matches { + let i = glob_language_mapping[m]; + if languages_processed[i] { + continue; + } + languages_processed[i] = true; + let lang = &languages[i]; + + lang.extract_file( + &schemas[i], + &mut diagnostics_writer, + &mut trap_writer, + &path, + &source, + ); + std::fs::create_dir_all(src_archive_file.parent().unwrap())?; + std::fs::copy(&path, &src_archive_file)?; + write_trap(trap_dir, &path, &trap_writer, trap_compression)?; + } + } + } + } + Ok(()) as std::io::Result<()> + }) + .expect("failed to extract files"); + + let path = PathBuf::from("extras"); + let mut trap_writer = trap::Writer::new(); + crate::extractor::populate_empty_location(&mut trap_writer); + + let res = write_trap(trap_dir, &path, &trap_writer, trap_compression); + tracing::info!("Extraction complete"); + res +} + +fn write_trap( + trap_dir: &Path, + path: &Path, + trap_writer: &trap::Writer, + trap_compression: trap::Compression, +) -> std::io::Result<()> { + let trap_file = crate::file_paths::path_for(trap_dir, path, trap_compression.extension(), None); + std::fs::create_dir_all(trap_file.parent().unwrap())?; + trap_writer.write_to_file(&trap_file, trap_compression) +} diff --git a/shared/tree-sitter-extractor/src/extractor/mod.rs b/shared/tree-sitter-extractor/src/extractor/mod.rs index 474dc096a2a6..1a8b9e820164 100644 --- a/shared/tree-sitter-extractor/src/extractor/mod.rs +++ b/shared/tree-sitter-extractor/src/extractor/mod.rs @@ -16,6 +16,8 @@ use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tree_sitter::{Language, Node, Parser, Range, Tree}; +pub mod desugaring; +mod driver; pub mod simple; /// Trait abstracting over tree-sitter and yeast node types for extraction. @@ -294,6 +296,10 @@ pub fn location_label(writer: &mut trap::Writer, location: trap::Location) -> tr /// caller's responsibility, allowing it to be done once and shared across /// files. #[allow(clippy::too_many_arguments)] +/// Extract a file with a tree-sitter grammar, walking the parse tree directly. +/// Comments and other `extra` nodes are emitted inline as tokens. This is the +/// path for languages that don't desugar their syntax tree (and hence have no +/// `extra` side channel); desugaring languages use [`extract_parsed`] instead. pub fn extract( language: &Language, language_prefix: &str, @@ -304,7 +310,6 @@ pub fn extract( path: &Path, source: &[u8], ranges: &[Range], - desugarer: Option<&dyn yeast::Desugarer>, ) { let path_str = file_paths::normalize_and_transform_path(path, transformer); let source_root = std::env::current_dir() @@ -337,21 +342,173 @@ pub fn extract( schema, ); - if let Some(desugarer) = desugarer { - let ast = desugarer - .run_from_tree(&tree, source) - .unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}")); - traverse_yeast(&ast, &mut visitor); - // Comments and other `extra` nodes are not represented in the desugared - // AST, so recover them directly from the original parse tree. - traverse_extras(&tree, &mut visitor); - } else { - traverse(&tree, &mut visitor); - } + traverse(&tree, &mut visitor); parser.reset(); } +/// A source tree produced by a parser: the raw `yeast::Ast` (pre-desugaring) +/// plus side-channel `extra` tokens (comments and similar) that are not +/// attached to the AST proper. +pub struct ParsedTree { + pub ast: yeast::Ast, + pub extras: Vec, +} + +/// A piece of side-channel `extra` content (a comment or unexpected text) +/// recovered by a parser. `kind` is a language-defined id written verbatim into +/// the `_trivia_tokeninfo` table (the tree-sitter parser uses the +/// grammar's node kind id here; a custom parser supplies its own stable +/// enumeration). +pub struct ExtraToken { + pub kind: usize, + pub range: yeast::Range, + pub text: String, +} + +/// Build a parser closure that parses `source` with a tree-sitter `language`, +/// producing a [`ParsedTree`]: a `yeast::Ast` (via [`yeast::Ast::from_tree`]) +/// plus the `extra` nodes (comments and similar) recovered as side-channel +/// tokens. This lets a tree-sitter language plug into the same +/// `ParsedTree`-producing interface as a custom parser. +pub fn tree_sitter_parser( + language: tree_sitter::Language, +) -> impl Fn(&[u8]) -> Result + Send + Sync { + move |source: &[u8]| { + let mut parser = Parser::new(); + parser + .set_language(&language) + .map_err(|e| format!("failed to set tree-sitter language: {e}"))?; + let tree = parser + .parse(source, None) + .ok_or_else(|| "tree-sitter failed to parse".to_string())?; + let ast = yeast::Ast::from_tree_with_schema_and_source( + yeast::schema::from_language(&language), + &tree, + &language, + source.to_vec(), + ); + let mut extras = Vec::new(); + collect_extras(tree.root_node(), source, &mut extras); + Ok(ParsedTree { ast, extras }) + } +} + +/// Collect `extra` nodes (comments and similar) under `node` into `out` as +/// [`ExtraToken`]s, keyed by the grammar's node kind id, for a desugaring +/// language whose rewritten AST won't retain them. +fn collect_extras(node: Node<'_>, source: &[u8], out: &mut Vec) { + let mut cursor = node.walk(); + for child in node.children(&mut cursor) { + if child.is_extra() { + let text = String::from_utf8_lossy(&source[child.byte_range()]).into_owned(); + out.push(ExtraToken { + kind: child.kind_id() as usize, + range: child.range().into(), + text, + }); + } else { + collect_extras(child, source, out); + } + } +} + +/// Extract a file from a [`ParsedTree`]-producing parser that desugars. The +/// parser yields a `yeast::Ast` plus side-channel `extra` tokens; the AST is +/// rewritten through `desugarer` ([`yeast::Desugarer::run_from_ast`]) before +/// TRAP extraction, and the `extra` tokens (comments and similar, which the +/// desugared AST does not carry) are emitted from the side channel. Both +/// tree-sitter grammars (via [`tree_sitter_parser`]) and custom parsers plug in +/// here; languages that don't desugar use [`extract`] instead. +#[allow(clippy::too_many_arguments)] +pub fn extract_parsed( + parse: &(dyn Fn(&[u8]) -> Result + Send + Sync), + language_prefix: &str, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + transformer: Option<&file_paths::PathTransformer>, + path: &Path, + source: &[u8], + desugarer: &dyn yeast::Desugarer, +) { + let path_str = file_paths::normalize_and_transform_path(path, transformer); + let source_root = std::env::current_dir() + .ok() + .and_then(|d| d.canonicalize().ok()); + let diagnostics_path = file_paths::relativize_for_diagnostic(path, source_root.as_deref()); + let span = tracing::span!(tracing::Level::TRACE, "extract", file = %path_str); + let _enter = span.enter(); + tracing::debug!("extracting: {}", path_str); + + trap_writer.comment(format!("Auto-generated TRAP file for {path_str}")); + let file_label = populate_file(trap_writer, path, transformer); + let mut visitor = Visitor::new( + source, + diagnostics_writer, + trap_writer, + &diagnostics_path, + file_label, + language_prefix, + schema, + ); + + let parsed = parse(source).unwrap_or_else(|e| panic!("Parsing failed for {path_str}: {e}")); + let ast = desugarer + .run_from_ast(parsed.ast) + .unwrap_or_else(|e| panic!("Desugaring failed for {path_str}: {e}")); + traverse_yeast(&ast, &mut visitor); + // Comments and other `extra` tokens are not part of the desugared AST; emit + // them directly from the parser's side channel. + for extra in &parsed.extras { + visitor.emit_extra(extra); + } +} + +/// A lightweight [`AstNode`] over a piece of side-channel `extra` content +/// recovered by a custom parser, so it can reuse the tree-sitter location +/// machinery. +struct ExtraNode { + range: yeast::Range, + text: String, +} + +impl AstNode for ExtraNode { + fn kind(&self) -> &str { + "extra" + } + fn is_named(&self) -> bool { + false + } + fn is_missing(&self) -> bool { + false + } + fn is_error(&self) -> bool { + false + } + fn is_extra(&self) -> bool { + true + } + fn start_position(&self) -> tree_sitter::Point { + tree_sitter::Point { + row: self.range.start_point.row, + column: self.range.start_point.column, + } + } + fn end_position(&self) -> tree_sitter::Point { + tree_sitter::Point { + row: self.range.end_point.row, + column: self.range.end_point.column, + } + } + fn byte_range(&self) -> std::ops::Range { + self.range.start_byte..self.range.end_byte + } + fn opt_string_content(&self) -> Option { + Some(self.text.clone()) + } +} + struct ChildNode { field_name: Option<&'static str>, label: trap::Label, @@ -415,10 +572,11 @@ impl<'a> Visitor<'a> { } } - /// Emits a `TriviaToken` for the given `extra` node (e.g. a comment) from - /// the original parse tree. Trivia tokens carry a location and their source - /// text, but are not attached to a parent in the (possibly desugared) AST. - fn emit_trivia_token(&mut self, node: &Node) { + /// Emit an `extra` token (a location row plus a `trivia_tokeninfo` row) for + /// any [`AstNode`], with an explicit `kind` id. Shared by the tree-sitter + /// path (kind = the grammar's node kind id) and the custom-parser path + /// (kind = a language-defined `extra` kind id). + fn emit_extra_from(&mut self, node: &N, kind: usize) { let id = self.trap_writer.fresh_id(); let loc = location_for(self, self.file_label, node); let loc_label = location_label(self.trap_writer, loc); @@ -430,12 +588,21 @@ impl<'a> Visitor<'a> { &self.trivia_tokeninfo_table_name, vec![ trap::Arg::Label(id), - trap::Arg::Int(node.kind_id() as usize), + trap::Arg::Int(kind), sliced_source_arg(self.source, node), ], ); } + /// Emit an `extra` token recovered from a parser's side channel. + fn emit_extra(&mut self, extra: &ExtraToken) { + let node = ExtraNode { + range: extra.range, + text: extra.text.clone(), + }; + self.emit_extra_from(&node, extra.kind); + } + fn record_parse_error(&mut self, loc: trap::Label, mesg: &diagnostics::DiagnosticMessage) { self.diagnostics_writer.write(mesg); let id = self.trap_writer.fresh_id(); @@ -871,24 +1038,6 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) { } } -/// Walks the original tree-sitter tree and emits a `TriviaToken` for every -/// `extra` node (e.g. a comment). Used to preserve comments that would -/// otherwise be lost after a desugaring pass rewrites the tree. -fn traverse_extras(tree: &Tree, visitor: &mut Visitor) { - emit_extras_in(visitor, tree.root_node()); -} - -fn emit_extras_in(visitor: &mut Visitor, node: Node<'_>) { - let mut cursor = node.walk(); - for child in node.children(&mut cursor) { - if child.is_extra() { - visitor.emit_trivia_token(&child); - } else { - emit_extras_in(visitor, child); - } - } -} - fn traverse_yeast(tree: &yeast::Ast, visitor: &mut Visitor) { let mut cursor = tree.walk(); visitor.enter_node(cursor.node()); diff --git a/shared/tree-sitter-extractor/src/extractor/simple.rs b/shared/tree-sitter-extractor/src/extractor/simple.rs index 9ba6f21778cf..1c6691fa8cf3 100644 --- a/shared/tree-sitter-extractor/src/extractor/simple.rs +++ b/shared/tree-sitter-extractor/src/extractor/simple.rs @@ -1,29 +1,52 @@ -use crate::{file_paths, trap}; -use globset::{GlobBuilder, GlobSetBuilder}; -use rayon::prelude::*; -use std::fs::File; -use std::io::BufRead; -use std::path::{Path, PathBuf}; +use crate::trap; +use std::path::PathBuf; use crate::diagnostics; -use crate::node_types; -use yeast; +use crate::extractor::driver::{self, LanguageExtractor}; +use crate::node_types::{self, NodeTypeMap}; +/// A tree-sitter language extracted directly from its parse tree, with no +/// desugaring. Comments and other `extra` nodes are emitted inline as tokens. +/// Languages that rewrite their syntax tree use +/// [`crate::extractor::desugaring`] instead. pub struct LanguageSpec { pub prefix: &'static str, pub ts_language: tree_sitter::Language, pub node_types: &'static str, - /// Optional desugarer. When set, the parsed tree is rewritten through - /// the desugarer before TRAP extraction. The desugarer's - /// `output_node_types_yaml()` (if set) provides the schema used both - /// at runtime (for the rewriter) and for TRAP validation. - /// - /// `Box` so the shared extractor is agnostic to - /// the user-defined context type the desugarer uses internally. - pub desugar: Option>, pub file_globs: Vec, } +impl LanguageExtractor for LanguageSpec { + fn file_globs(&self) -> &[String] { + &self.file_globs + } + + fn build_schema(&self) -> std::io::Result { + node_types::read_node_types_str(self.prefix, self.node_types) + } + + fn extract_file( + &self, + schema: &NodeTypeMap, + diagnostics_writer: &mut diagnostics::LogWriter, + trap_writer: &mut trap::Writer, + path: &std::path::Path, + source: &[u8], + ) { + crate::extractor::extract( + &self.ts_language, + self.prefix, + schema, + diagnostics_writer, + trap_writer, + None, + path, + source, + &[], + ); + } +} + pub struct Extractor { pub prefix: String, pub languages: Vec, @@ -38,182 +61,13 @@ pub struct Extractor { impl Extractor { pub fn run(&self) -> std::io::Result<()> { - tracing::info!("Extraction started"); - let diagnostics = diagnostics::DiagnosticLoggers::new(&self.prefix); - let mut main_thread_logger = diagnostics.logger(); - let num_threads = match crate::options::num_threads() { - Ok(num) => num, - Err(e) => { - main_thread_logger.write( - main_thread_logger - .new_entry("configuration-error", "Configuration error") - .message( - "{}; defaulting to 1 thread.", - &[diagnostics::MessageArg::Code(&e)], - ) - .severity(diagnostics::Severity::Warning), - ); - 1 - } - }; - tracing::info!( - "Using {} {}", - num_threads, - if num_threads == 1 { - "thread" - } else { - "threads" - } - ); - let trap_compression = match &self.trap_compression { - Ok(x) => *x, - Err(e) => { - main_thread_logger.write( - main_thread_logger - .new_entry("configuration-error", "Configuration error") - .message("{}; using gzip.", &[diagnostics::MessageArg::Code(e)]) - .severity(diagnostics::Severity::Warning), - ); - trap::Compression::Gzip - } - }; - drop(main_thread_logger); - - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build_global() - .unwrap(); - - let file_lists: Vec = self - .file_lists - .iter() - .map(|file_list| { - File::open(file_list) - .unwrap_or_else(|_| panic!("Unable to open file list at {file_list:?}")) - }) - .collect(); - - let mut schemas = vec![]; - for lang in &self.languages { - let effective_node_types: String = match lang - .desugar - .as_ref() - .and_then(|d| d.output_node_types_yaml()) - { - Some(yaml) => yeast::node_types_yaml::convert(yaml).map_err(|e| { - std::io::Error::other(format!( - "Failed to convert YAML node-types to JSON for {}: {e}", - lang.prefix - )) - })?, - None => lang.node_types.to_string(), - }; - let schema = node_types::read_node_types_str(lang.prefix, &effective_node_types)?; - schemas.push(schema); - } - - // Construct a single globset containing all language globs, - // and a mapping from glob index to language index. - let (globset, glob_language_mapping) = { - let mut builder = GlobSetBuilder::new(); - let mut glob_lang_mapping = vec![]; - for (i, lang) in self.languages.iter().enumerate() { - for glob_str in &lang.file_globs { - let glob = GlobBuilder::new(glob_str) - .literal_separator(true) - .build() - .expect("invalid glob"); - builder.add(glob); - glob_lang_mapping.push(i); - } - } - ( - builder.build().expect("failed to build globset"), - glob_lang_mapping, - ) - }; - - let path_transformer = file_paths::load_path_transformer()?; - - let lines: std::io::Result> = file_lists - .iter() - .flat_map(|file_list| std::io::BufReader::new(file_list).lines()) - .collect(); - let lines = lines?; - - lines - .par_iter() - .try_for_each(|line| { - let mut diagnostics_writer = diagnostics.logger(); - let path = PathBuf::from(line).canonicalize()?; - let src_archive_file = crate::file_paths::path_for( - &self.source_archive_dir, - &path, - "", - path_transformer.as_ref(), - ); - let source = std::fs::read(&path)?; - let mut trap_writer = trap::Writer::new(); - - match path.file_name() { - None => { - tracing::error!(?path, "No file name found, skipping file."); - } - Some(filename) => { - let matches = globset.matches(filename); - if matches.is_empty() { - tracing::error!(?path, "No matching language found, skipping file."); - } else { - let mut languages_processed = vec![false; self.languages.len()]; - - for m in matches { - let i = glob_language_mapping[m]; - if languages_processed[i] { - continue; - } - languages_processed[i] = true; - let lang = &self.languages[i]; - - crate::extractor::extract( - &lang.ts_language, - lang.prefix, - &schemas[i], - &mut diagnostics_writer, - &mut trap_writer, - None, - &path, - &source, - &[], - lang.desugar.as_deref(), - ); - std::fs::create_dir_all(src_archive_file.parent().unwrap())?; - std::fs::copy(&path, &src_archive_file)?; - write_trap(&self.trap_dir, &path, &trap_writer, trap_compression)?; - } - } - } - } - Ok(()) as std::io::Result<()> - }) - .expect("failed to extract files"); - - let path = PathBuf::from("extras"); - let mut trap_writer = trap::Writer::new(); - crate::extractor::populate_empty_location(&mut trap_writer); - - let res = write_trap(&self.trap_dir, &path, &trap_writer, trap_compression); - tracing::info!("Extraction complete"); - res + driver::run_extractor( + &self.prefix, + &self.languages, + &self.trap_dir, + &self.source_archive_dir, + &self.file_lists, + &self.trap_compression, + ) } } - -fn write_trap( - trap_dir: &Path, - path: &Path, - trap_writer: &trap::Writer, - trap_compression: trap::Compression, -) -> std::io::Result<()> { - let trap_file = crate::file_paths::path_for(trap_dir, path, trap_compression.extension(), None); - std::fs::create_dir_all(trap_file.parent().unwrap())?; - trap_writer.write_to_file(&trap_file, trap_compression) -} diff --git a/shared/tree-sitter-extractor/src/generator/mod.rs b/shared/tree-sitter-extractor/src/generator/mod.rs index dbecf62569af..cf445aaaac7f 100644 --- a/shared/tree-sitter-extractor/src/generator/mod.rs +++ b/shared/tree-sitter-extractor/src/generator/mod.rs @@ -18,6 +18,7 @@ pub fn generate( languages: Vec, dbscheme_path: PathBuf, ql_library_path: PathBuf, + use_facade_ast: bool, regenerate_instructions: &str, ) -> std::io::Result<()> { let dbscheme_file = File::create(dbscheme_path).map_err(|e| { @@ -47,6 +48,7 @@ pub fn generate( ql::write( &mut ql_writer, &[ql::TopLevel::Import(ql::Import { + is_private: false, module: "codeql.Locations", alias: Some("L"), })], @@ -122,17 +124,35 @@ pub fn generate( let mut body = vec![]; - for c in ql_gen::create_ast_node_class( + let facade_import_name = if use_facade_ast { + format!("FacadeAst::{}", &language.name) + } else { + language.name.clone() // If not using a facade AST, treat the module itself as the facade module. + }; + if use_facade_ast { + body.push(ql::TopLevel::Import(ql::Import { + is_private: true, + module: &facade_import_name, + alias: Some("F"), + })); + } else { + body.push(ql::TopLevel::ModuleAlias(ql::ModuleAlias { + is_private: true, + name: "F", + target: &language.name, + })); + } + + body.push(ql::TopLevel::Class(ql_gen::create_ast_node_class( &ast_node_name, &node_location_table_name, &node_parent_table_name, - ) { - body.push(ql::TopLevel::Class(c)); - } + ))); - for c in ql_gen::create_token_class(&token_name, &tokeninfo_name) { - body.push(ql::TopLevel::Class(c)); - } + body.push(ql::TopLevel::Class(ql_gen::create_token_class( + &token_name, + &tokeninfo_name, + ))); if has_trivia_tokens { body.push(ql::TopLevel::Class(ql_gen::create_trivia_token_class( @@ -166,14 +186,68 @@ pub fn generate( body.append(&mut ql_gen::convert_nodes(&nodes)); body.push(ql_gen::create_print_ast_module(&nodes)); + let mut final_body = if use_facade_ast { + vec![ + ql::TopLevel::Import(ql::Import { + is_private: true, + module: &facade_import_name, + alias: Some("F"), + }), + ql::TopLevel::Import(ql::Import { + is_private: false, + module: "F", + alias: None, + }), + ] + } else { + vec![ + ql::TopLevel::ModuleAlias(ql::ModuleAlias { + is_private: true, + name: "F", + target: &language.name, + }), + ql::TopLevel::Import(ql::Import { + is_private: false, + module: "F", + alias: None, + }), + ] + }; + let final_aliases = body + .iter() + .filter_map(|decl| match decl { + ql::TopLevel::Class(c) => Some(ql::TopLevel::Class(ql::Class { + qldoc: None, + name: c.name, + is_abstract: false, + is_final: true, + is_private: false, + supertypes: Set::new(), + characteristic_predicate: None, + predicates: vec![], + alias: Some(format!("F::{}", c.name)), + })), + _ => None, + }) + .collect::>(); + final_body.extend(final_aliases); + let final_module_name = format!("{}Final", language.name); ql::write( &mut ql_writer, - &[ql::TopLevel::Module(ql::Module { - qldoc: None, - name: &language.name, - body, - overlay: Some(ql::OverlayAnnotation::Local), - })], + &[ + ql::TopLevel::Module(ql::Module { + qldoc: None, + name: &language.name, + body, + overlay: Some(ql::OverlayAnnotation::Local), + }), + ql::TopLevel::Module(ql::Module { + qldoc: None, + name: &final_module_name, + body: final_body, + overlay: None, + }), + ], )?; } Ok(()) diff --git a/shared/tree-sitter-extractor/src/generator/ql.rs b/shared/tree-sitter-extractor/src/generator/ql.rs index 6a78a4f95f09..f114e251af21 100644 --- a/shared/tree-sitter-extractor/src/generator/ql.rs +++ b/shared/tree-sitter-extractor/src/generator/ql.rs @@ -5,6 +5,7 @@ use std::fmt; pub enum TopLevel<'a> { Class(Class<'a>), Import(Import<'a>), + ModuleAlias(ModuleAlias<'a>), Module(Module<'a>), Predicate(Predicate<'a>), } @@ -14,20 +15,41 @@ impl fmt::Display for TopLevel<'_> { match self { TopLevel::Import(imp) => write!(f, "{imp}"), TopLevel::Class(cls) => write!(f, "{cls}"), + TopLevel::ModuleAlias(alias) => write!(f, "{alias}"), TopLevel::Module(m) => write!(f, "{m}"), TopLevel::Predicate(pred) => write!(f, "{pred}"), } } } +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct ModuleAlias<'a> { + pub is_private: bool, + pub name: &'a str, + pub target: &'a str, +} + +impl fmt::Display for ModuleAlias<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_private { + write!(f, "private ")?; + } + write!(f, "module {} = {};", self.name, self.target) + } +} + #[derive(Clone, Eq, PartialEq, Hash)] pub struct Import<'a> { + pub is_private: bool, pub module: &'a str, pub alias: Option<&'a str>, } impl fmt::Display for Import<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_private { + write!(f, "private ")?; + } write!(f, "import {}", &self.module)?; if let Some(name) = &self.alias { write!(f, " as {name}")?; @@ -146,6 +168,9 @@ pub enum Type<'a> { /// A user-defined type. Normal(&'a str), + + /// A normal type with an `F::` prefix. + Facade(&'a str), } impl fmt::Display for Type<'_> { @@ -155,6 +180,7 @@ impl fmt::Display for Type<'_> { Type::String => write!(f, "string"), Type::Normal(name) => write!(f, "{name}"), Type::At(name) => write!(f, "@{name}"), + Type::Facade(name) => write!(f, "F::{name}"), } } } diff --git a/shared/tree-sitter-extractor/src/generator/ql_gen.rs b/shared/tree-sitter-extractor/src/generator/ql_gen.rs index 8f37bf5dff45..fe6f9a2a828b 100644 --- a/shared/tree-sitter-extractor/src/generator/ql_gen.rs +++ b/shared/tree-sitter-extractor/src/generator/ql_gen.rs @@ -8,7 +8,7 @@ pub fn create_ast_node_class<'a>( ast_node: &'a str, node_location_table: &'a str, node_parent_table: &'a str, -) -> [ql::Class<'a>; 2] { +) -> ql::Class<'a> { // Default implementation of `toString` calls `this.getAPrimaryQlClass()` let to_string = ql::Predicate { qldoc: Some(String::from( @@ -48,7 +48,7 @@ pub fn create_ast_node_class<'a>( Some(String::from("Gets a field or child node of this node.")), "getAFieldOrChild", false, - Some(ql::Type::Normal("AstNode")), + Some(ql::Type::Facade("AstNode")), ); let get_parent = ql::Predicate { qldoc: Some(String::from("Gets the parent of this element.")), @@ -56,7 +56,7 @@ pub fn create_ast_node_class<'a>( overridden: false, is_private: false, is_final: true, - return_type: Some(ql::Type::Normal("AstNode")), + return_type: Some(ql::Type::Facade("AstNode")), formal_parameters: vec![], body: ql::Expression::Pred( node_parent_table, @@ -132,41 +132,28 @@ pub fn create_ast_node_class<'a>( ), overlay: None, }; - [ - ql::Class { - qldoc: Some(String::from("The base class for all AST nodes")), - name: "AstNodeImpl", - is_abstract: false, - is_final: false, - is_private: true, - alias: None, - supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(), - characteristic_predicate: None, - predicates: vec![ - to_string, - get_location, - get_parent, - get_parent_index, - get_a_field_or_child, - get_a_primary_ql_class, - get_primary_ql_classes, - ], - }, - ql::Class { - qldoc: None, - name: "AstNode", - is_abstract: false, - is_final: true, - is_private: false, - alias: Some("AstNodeImpl".to_string()), - supertypes: vec![].into_iter().collect(), - characteristic_predicate: None, - predicates: vec![], - }, - ] + ql::Class { + qldoc: Some(String::from("The base class for all AST nodes")), + name: "AstNode", + is_abstract: false, + is_final: false, + is_private: false, + alias: None, + supertypes: vec![ql::Type::At(ast_node)].into_iter().collect(), + characteristic_predicate: None, + predicates: vec![ + to_string, + get_location, + get_parent, + get_parent_index, + get_a_field_or_child, + get_a_primary_ql_class, + get_primary_ql_classes, + ], + } } -pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> [ql::Class<'a>; 2] { +pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> ql::Class<'a> { let tokeninfo_arity = 3; // id, kind, value let get_value = ql::Predicate { qldoc: Some(String::from("Gets the value of this token.")), @@ -199,36 +186,23 @@ pub fn create_token_class<'a>(token_type: &'a str, tokeninfo: &'a str) -> [ql::C ), overlay: None, }; - [ - ql::Class { - qldoc: Some(String::from("A token.")), - name: "TokenImpl", - is_abstract: false, - is_final: false, - is_private: true, - alias: None, - supertypes: vec![ql::Type::At(token_type), ql::Type::Normal("AstNodeImpl")] - .into_iter() - .collect(), - characteristic_predicate: None, - predicates: vec![ - get_value, - to_string, - create_get_a_primary_ql_class("Token", false), - ], - }, - ql::Class { - qldoc: None, - name: "Token", - is_abstract: false, - is_final: true, - is_private: false, - alias: Some("TokenImpl".to_string()), - supertypes: vec![].into_iter().collect(), - characteristic_predicate: None, - predicates: vec![], - }, - ] + ql::Class { + qldoc: Some(String::from("A token.")), + name: "Token", + is_abstract: false, + is_final: false, + is_private: false, + alias: None, + supertypes: vec![ql::Type::At(token_type), ql::Type::Facade("AstNode")] + .into_iter() + .collect(), + characteristic_predicate: None, + predicates: vec![ + get_value, + to_string, + create_get_a_primary_ql_class("Token", false), + ], + } } /// Creates the `TriviaToken` class. Trivia tokens (e.g. comments) are @@ -283,15 +257,12 @@ pub fn create_trivia_token_class<'a>( )), name: "TriviaToken", is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, - supertypes: vec![ - ql::Type::At(trivia_token_type), - ql::Type::Normal("AstNodeImpl"), - ] - .into_iter() - .collect(), + supertypes: vec![ql::Type::At(trivia_token_type), ql::Type::Facade("AstNode")] + .into_iter() + .collect(), characteristic_predicate: None, predicates: vec![ get_value, @@ -309,10 +280,10 @@ pub fn create_reserved_word_class(db_name: &str) -> ql::Class<'_> { qldoc: Some(String::from("A reserved word.")), name: class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, - supertypes: vec![ql::Type::At(db_name), ql::Type::Normal("TokenImpl")] + supertypes: vec![ql::Type::At(db_name), ql::Type::Facade("Token")] .into_iter() .collect(), characteristic_predicate: None, @@ -635,10 +606,11 @@ fn create_get_field_expr_for_table_storage<'a>( ) } -/// Creates a pair consisting of a predicate to get the given field, and an -/// optional expression that will get the same field. When the field can occur -/// multiple times, the predicate will take an index argument, while the -/// expression will use the "don't care" expression to hold for all occurrences. +/// Creates a list of predicates to get the given field, and an optional +/// expression that will get the same field. When the field can occur multiple +/// times, this includes an indexed getter and a convenience getter that returns +/// any member; the expression uses the "don't care" expression to hold for all +/// occurrences. /// /// # Arguments /// @@ -656,16 +628,16 @@ fn create_field_getters<'a>( main_table_column_index: &mut usize, field: &'a node_types::Field, nodes: &'a node_types::NodeTypeMap, -) -> (ql::Predicate<'a>, Option>) { +) -> (Vec>, Option>) { let return_type = match &field.type_info { node_types::FieldTypeInfo::Single(t) => { - Some(ql::Type::Normal(&nodes.get(t).unwrap().ql_class_name)) + Some(ql::Type::Facade(&nodes.get(t).unwrap().ql_class_name)) } node_types::FieldTypeInfo::Multiple { types: _, dbscheme_union: _, ql_class, - } => Some(ql::Type::Normal(ql_class)), + } => Some(ql::Type::Facade(ql_class)), node_types::FieldTypeInfo::ReservedWordInt(_) => Some(ql::Type::String), }; let formal_parameters = match &field.storage { @@ -780,26 +752,87 @@ fn create_field_getters<'a>( } } }; - ( - ql::Predicate { - qldoc: Some(qldoc), - name: &field.getter_name, + let mut predicates = vec![ql::Predicate { + qldoc: Some(qldoc.clone()), + name: &field.getter_name, + overridden: false, + is_private: false, + is_final: true, + return_type: return_type.clone(), + formal_parameters, + body, + overlay: None, + }]; + + if let Some(any_getter_name) = &field.any_getter_name { + predicates.push(ql::Predicate { + qldoc: Some(qldoc.clone()), + name: any_getter_name, overridden: false, is_private: false, is_final: true, return_type, - formal_parameters, - body, + formal_parameters: vec![], + body: ql::Expression::Equals( + Box::new(ql::Expression::Var("result")), + Box::new(ql::Expression::Dot( + Box::new(ql::Expression::Var("this")), + &field.getter_name, + vec![ql::Expression::Var("_")], + )), + ), overlay: None, - }, - optional_expr, - ) + }); + } + + (predicates, optional_expr) +} + +fn compute_direct_supertypes( + nodes: &node_types::NodeTypeMap, +) -> std::collections::BTreeMap> { + let mut supertypes = std::collections::BTreeMap::new(); + for node in nodes.values() { + if let node_types::EntryKind::Union { members } = &node.kind { + for member in members { + supertypes + .entry(member.clone()) + .or_insert_with(BTreeSet::new) + .insert(node.ql_class_name.as_str()); + } + } + } + supertypes +} + +fn ast_base_types<'a>( + type_name: &node_types::TypeName, + direct_supertypes: &std::collections::BTreeMap>, +) -> BTreeSet> { + match direct_supertypes.get(type_name) { + Some(supertypes) if !supertypes.is_empty() => supertypes + .iter() + .map(|name| ql::Type::Facade(name)) + .collect(), + _ => vec![ql::Type::Facade("AstNode")].into_iter().collect(), + } +} + +fn class_supertypes<'a>( + type_name: &node_types::TypeName, + dbscheme_name: &'a str, + direct_supertypes: &std::collections::BTreeMap>, +) -> BTreeSet> { + let mut supertypes = ast_base_types(type_name, direct_supertypes); + supertypes.insert(ql::Type::At(dbscheme_name)); + supertypes } /// Converts the given node types into CodeQL classes wrapping the dbscheme. pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { let mut classes = Vec::new(); let mut token_kinds = BTreeSet::new(); + let direct_supertypes = compute_direct_supertypes(nodes); for (type_name, node) in nodes { if let node_types::EntryKind::Token { .. } = &node.kind { if type_name.named { @@ -814,14 +847,14 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { if type_name.named { let get_a_primary_ql_class = create_get_a_primary_ql_class(&node.ql_class_name, true); - let mut supertypes: BTreeSet = BTreeSet::new(); - supertypes.insert(ql::Type::At(&node.dbscheme_name)); - supertypes.insert(ql::Type::Normal("TokenImpl")); + let mut supertypes = + class_supertypes(type_name, &node.dbscheme_name, &direct_supertypes); + supertypes.insert(ql::Type::Facade("Token")); classes.push(ql::TopLevel::Class(ql::Class { qldoc: Some(format!("A class representing `{}` tokens.", type_name.kind)), name: &node.ql_class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, supertypes, @@ -837,15 +870,14 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { qldoc: None, name: &node.ql_class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, - supertypes: vec![ - ql::Type::At(&node.dbscheme_name), - ql::Type::Normal("AstNodeImpl"), - ] - .into_iter() - .collect(), + supertypes: class_supertypes( + type_name, + &node.dbscheme_name, + &direct_supertypes, + ), characteristic_predicate: None, predicates: vec![], })); @@ -871,15 +903,14 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { qldoc: Some(format!("A class representing `{}` nodes.", type_name.kind)), name: main_class_name, is_abstract: false, - is_final: true, + is_final: false, is_private: false, alias: None, - supertypes: vec![ - ql::Type::At(&node.dbscheme_name), - ql::Type::Normal("AstNodeImpl"), - ] - .into_iter() - .collect(), + supertypes: class_supertypes( + type_name, + &node.dbscheme_name, + &direct_supertypes, + ), characteristic_predicate: None, predicates: vec![create_get_a_primary_ql_class(main_class_name, true)], }; @@ -892,14 +923,14 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { // - predicates to access the fields, // - the QL expressions to access the fields that will be part of getAFieldOrChild. for field in fields { - let (get_pred, get_child_expr) = create_field_getters( + let (get_preds, get_child_expr) = create_field_getters( main_table_name, main_table_arity, &mut main_table_column_index, field, nodes, ); - main_class.predicates.push(get_pred); + main_class.predicates.extend(get_preds); if let Some(get_child_expr) = get_child_expr { get_child_exprs.push(get_child_expr) } @@ -911,7 +942,7 @@ pub fn convert_nodes(nodes: &node_types::NodeTypeMap) -> Vec> { overridden: true, is_private: false, is_final: true, - return_type: Some(ql::Type::Normal("AstNode")), + return_type: Some(ql::Type::Facade("AstNode")), formal_parameters: vec![], body: ql::Expression::Or(get_child_exprs), overlay: None, @@ -992,11 +1023,11 @@ pub fn create_print_ast_module(nodes: &node_types::NodeTypeMap) -> ql::TopLevel< overridden: false, is_private: false, is_final: false, - return_type: Some(ql::Type::Normal("AstNode")), + return_type: Some(ql::Type::Facade("AstNode")), formal_parameters: vec![ ql::FormalParameter { name: "node", - param_type: ql::Type::Normal("AstNode"), + param_type: ql::Type::Facade("AstNode"), }, ql::FormalParameter { name: "name", diff --git a/shared/tree-sitter-extractor/src/node_types.rs b/shared/tree-sitter-extractor/src/node_types.rs index 7a457fa73f0d..4c67c2e4f20e 100644 --- a/shared/tree-sitter-extractor/src/node_types.rs +++ b/shared/tree-sitter-extractor/src/node_types.rs @@ -22,7 +22,7 @@ pub enum EntryKind { Token { kind_id: usize }, } -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct TypeName { pub kind: String, pub named: bool, @@ -56,6 +56,9 @@ pub struct Field { pub name: Option, /// The name of the predicate to get this field. pub getter_name: String, + /// For plural fields, the name of a convenience getter that returns + /// any member (for example `getAnArgument` for `getArgument(i)`). + pub any_getter_name: Option, pub storage: Storage, } @@ -281,6 +284,16 @@ fn add_field( "get{}", dbscheme_name_to_class_name(&escape_name(&name_for_field_or_child(&field_name))) ); + let getter_suffix = getter_name.strip_prefix("get").unwrap_or(&getter_name); + let article = match getter_suffix.chars().next().map(|c| c.to_ascii_lowercase()) { + Some('a' | 'e' | 'i' | 'o' | 'u') => "An", + _ => "A", + }; + let any_getter_name = if field_info.multiple { + Some(format!("get{article}{getter_suffix}")) + } else { + None + }; fields.push(Field { parent: TypeName { kind: parent_type_name.kind.to_string(), @@ -289,6 +302,7 @@ fn add_field( type_info, name: field_name, getter_name, + any_getter_name, storage, }); } diff --git a/shared/tree-sitter-extractor/tests/integration_test.rs b/shared/tree-sitter-extractor/tests/integration_test.rs index 694eb526f394..2b243ff7945b 100644 --- a/shared/tree-sitter-extractor/tests/integration_test.rs +++ b/shared/tree-sitter-extractor/tests/integration_test.rs @@ -13,7 +13,6 @@ fn simple_extractor() { prefix: "ql", ts_language: tree_sitter_ql::LANGUAGE.into(), node_types: tree_sitter_ql::NODE_TYPES, - desugar: None, file_globs: vec!["*.qll".into()], }; diff --git a/shared/tree-sitter-extractor/tests/multiple_languages.rs b/shared/tree-sitter-extractor/tests/multiple_languages.rs index e345eec58280..2e45e56754a3 100644 --- a/shared/tree-sitter-extractor/tests/multiple_languages.rs +++ b/shared/tree-sitter-extractor/tests/multiple_languages.rs @@ -13,14 +13,12 @@ fn multiple_language_extractor() { prefix: "ql", ts_language: tree_sitter_ql::LANGUAGE.into(), node_types: tree_sitter_ql::NODE_TYPES, - desugar: None, file_globs: vec!["*.qll".into()], }; let lang_json = simple::LanguageSpec { prefix: "json", ts_language: tree_sitter_json::LANGUAGE.into(), node_types: tree_sitter_json::NODE_TYPES, - desugar: None, file_globs: vec!["*.json".into(), "*Jsonfile".into()], }; diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md index 34f695126455..267dbfeb562f 100644 --- a/shared/tutorial/CHANGELOG.md +++ b/shared/tutorial/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/tutorial/change-notes/released/1.0.55.md b/shared/tutorial/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/tutorial/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/tutorial/codeql-pack.release.yml +++ b/shared/tutorial/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index ccbde048c98d..0a6f77df0754 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 1.0.54 +version: 1.0.55 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/typeflow/CHANGELOG.md b/shared/typeflow/CHANGELOG.md index 906d6b96ebea..90dc2603d772 100644 --- a/shared/typeflow/CHANGELOG.md +++ b/shared/typeflow/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/typeflow/change-notes/released/1.0.55.md b/shared/typeflow/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/typeflow/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/typeflow/codeql-pack.release.yml b/shared/typeflow/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/typeflow/codeql-pack.release.yml +++ b/shared/typeflow/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/typeflow/qlpack.yml b/shared/typeflow/qlpack.yml index 5a0bb1315c2c..deb074f38410 100644 --- a/shared/typeflow/qlpack.yml +++ b/shared/typeflow/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeflow -version: 1.0.54 +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/typeinference/CHANGELOG.md b/shared/typeinference/CHANGELOG.md index 4916c26d385a..cd72576290a7 100644 --- a/shared/typeinference/CHANGELOG.md +++ b/shared/typeinference/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.36 + +No user-facing changes. + ## 0.0.35 No user-facing changes. diff --git a/shared/typeinference/change-notes/released/0.0.36.md b/shared/typeinference/change-notes/released/0.0.36.md new file mode 100644 index 000000000000..14c56d238da9 --- /dev/null +++ b/shared/typeinference/change-notes/released/0.0.36.md @@ -0,0 +1,3 @@ +## 0.0.36 + +No user-facing changes. diff --git a/shared/typeinference/codeql-pack.release.yml b/shared/typeinference/codeql-pack.release.yml index 143c97892032..b6df3a024ee6 100644 --- a/shared/typeinference/codeql-pack.release.yml +++ b/shared/typeinference/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.35 +lastReleaseVersion: 0.0.36 diff --git a/shared/typeinference/qlpack.yml b/shared/typeinference/qlpack.yml index add1c0c7d055..b2bef17c8c5a 100644 --- a/shared/typeinference/qlpack.yml +++ b/shared/typeinference/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typeinference -version: 0.0.35 +version: 0.0.36 groups: shared library: true dependencies: diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md index a0ddc0dabdb0..8226f0232aff 100644 --- a/shared/typetracking/CHANGELOG.md +++ b/shared/typetracking/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.39 + +No user-facing changes. + ## 2.0.38 No user-facing changes. diff --git a/shared/typetracking/change-notes/released/2.0.39.md b/shared/typetracking/change-notes/released/2.0.39.md new file mode 100644 index 000000000000..887d030df420 --- /dev/null +++ b/shared/typetracking/change-notes/released/2.0.39.md @@ -0,0 +1,3 @@ +## 2.0.39 + +No user-facing changes. diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml index 4ec9eb0980cf..063a268e5f9f 100644 --- a/shared/typetracking/codeql-pack.release.yml +++ b/shared/typetracking/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.38 +lastReleaseVersion: 2.0.39 diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 744a79cb9b43..b4c98d2ed55b 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 2.0.38 +version: 2.0.39 groups: shared library: true dependencies: diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md index 1f1760051700..2cad9992afb8 100644 --- a/shared/typos/CHANGELOG.md +++ b/shared/typos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/typos/change-notes/released/1.0.55.md b/shared/typos/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/typos/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/typos/codeql-pack.release.yml +++ b/shared/typos/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index f91961fd5796..7f17b05eb5dc 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typos -version: 1.0.54 +version: 1.0.55 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md index 587c0a00aa15..55fa9e7730b5 100644 --- a/shared/util/CHANGELOG.md +++ b/shared/util/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.42 + +No user-facing changes. + ## 2.0.41 No user-facing changes. diff --git a/shared/util/change-notes/released/2.0.42.md b/shared/util/change-notes/released/2.0.42.md new file mode 100644 index 000000000000..85ba02702b9f --- /dev/null +++ b/shared/util/change-notes/released/2.0.42.md @@ -0,0 +1,3 @@ +## 2.0.42 + +No user-facing changes. diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml index dcd61b02de59..000a2d0de2d1 100644 --- a/shared/util/codeql-pack.release.yml +++ b/shared/util/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 2.0.41 +lastReleaseVersion: 2.0.42 diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 022b0557fc51..85d435b88027 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 2.0.41 +version: 2.0.42 groups: shared library: true dependencies: null diff --git a/shared/xml/CHANGELOG.md b/shared/xml/CHANGELOG.md index 15640e5c1cbd..0901e77ebb22 100644 --- a/shared/xml/CHANGELOG.md +++ b/shared/xml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/xml/change-notes/released/1.0.55.md b/shared/xml/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/xml/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/xml/codeql-pack.release.yml b/shared/xml/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/xml/codeql-pack.release.yml +++ b/shared/xml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/xml/qlpack.yml b/shared/xml/qlpack.yml index 81159c215cb9..2e4d61f11abe 100644 --- a/shared/xml/qlpack.yml +++ b/shared/xml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/xml -version: 1.0.54 +version: 1.0.55 groups: shared library: true dependencies: diff --git a/shared/yaml/CHANGELOG.md b/shared/yaml/CHANGELOG.md index e45ca7c51319..9ff01d7f1b17 100644 --- a/shared/yaml/CHANGELOG.md +++ b/shared/yaml/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.55 + +No user-facing changes. + ## 1.0.54 No user-facing changes. diff --git a/shared/yaml/change-notes/released/1.0.55.md b/shared/yaml/change-notes/released/1.0.55.md new file mode 100644 index 000000000000..fd53dce64a9f --- /dev/null +++ b/shared/yaml/change-notes/released/1.0.55.md @@ -0,0 +1,3 @@ +## 1.0.55 + +No user-facing changes. diff --git a/shared/yaml/codeql-pack.release.yml b/shared/yaml/codeql-pack.release.yml index c3c3b0f4418a..3c942a6b4ea3 100644 --- a/shared/yaml/codeql-pack.release.yml +++ b/shared/yaml/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.0.54 +lastReleaseVersion: 1.0.55 diff --git a/shared/yaml/qlpack.yml b/shared/yaml/qlpack.yml index 0216ed463ad4..5c5a36fa69f3 100644 --- a/shared/yaml/qlpack.yml +++ b/shared/yaml/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/yaml -version: 1.0.54 +version: 1.0.55 groups: shared library: true warnOnImplicitThis: true diff --git a/shared/yeast-macros/src/lib.rs b/shared/yeast-macros/src/lib.rs index 0df96c91d26b..82b0e3e7b408 100644 --- a/shared/yeast-macros/src/lib.rs +++ b/shared/yeast-macros/src/lib.rs @@ -47,8 +47,35 @@ pub fn query(input: TokenStream) -> TokenStream { /// `Option`, iterator chains) splice /// their elements /// field: {expr} - extend a named field with `{expr}`'s ids +/// field: (kind ...)? - set the field only if every `#{expr}` +/// beneath it has a value (see below) /// ``` /// +/// # Optional fields +/// +/// A `?` on a field's value makes that field fallible: if a `#{expr}` +/// anywhere beneath it interpolates an absent value — an `Option` that is +/// `None` — the subtree is abandoned and the field is left unset. This +/// replaces the surrounding `Option::map` that would otherwise be needed: +/// +/// ```text +/// (break_expr label: {lbl.map(|l| tree!((identifier #{l})))}) // before +/// (break_expr label: (identifier #{lbl})?) // after +/// ``` +/// +/// The value may be nested arbitrarily deeply, and a nested `?` catches +/// first, so an inner absent value need not discard the outer node: +/// +/// ```text +/// (parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty}) +/// ``` +/// +/// Only `#{expr}` propagates absence. A `{expr}` splice is unaffected, since +/// yielding no ids already leaves a field unset, and `?` is rejected on one. +/// Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile +/// error, so the choice between "unset the field" and "unwrap it" stays +/// explicit. +/// /// Can be called with an explicit context or using the implicit context /// from an enclosing `rule!`: /// diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs index 55ada3588491..34e859c912e9 100644 --- a/shared/yeast-macros/src/parse.rs +++ b/shared/yeast-macros/src/parse.rs @@ -1,10 +1,44 @@ use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree}; use quote::quote; use std::iter::Peekable; +use std::sync::atomic::{AtomicUsize, Ordering}; +use syn::Lifetime; type Tokens = Peekable; type Result = std::result::Result; +/// Mints the block label a fallible field breaks out of. Labels must be unique +/// along a nesting chain, since a `?` nested inside another `?` has to break out +/// of the inner field only. +fn fresh_fallible_label() -> Lifetime { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + let n = COUNTER.fetch_add(1, Ordering::Relaxed); + Lifetime::new(&format!("'__yeast_field_{n}"), Span::call_site()) +} + +/// Rejects a `?` in a position where there is no field for it to leave unset. +/// +/// The advice depends on what precedes it: on a `{...}` splice a `?` is +/// redundant, and anywhere else it belongs on a field's value. Other +/// quantifiers need no handling — `*` and `+` have never been valid in a +/// template, and the existing check for stray tokens already rejects them. +fn reject_stray_optional(tokens: &mut Tokens, after_splice: bool) -> Result<()> { + let Some(TokenTree::Punct(p)) = tokens.peek() else { + return Ok(()); + }; + if p.as_char() != '?' { + return Ok(()); + } + let msg = if after_splice { + "`?` is not valid on a `{...}` splice; a splice that yields no value \ + already leaves its field unset" + } else { + "`?` is only valid on the value of a named field, as in \ + `label: (identifier #{lbl})?`" + }; + Err(syn::Error::new_spanned(p.clone(), msg)) +} + // --------------------------------------------------------------------------- // Query parsing // --------------------------------------------------------------------------- @@ -123,11 +157,14 @@ fn parse_query_fields(tokens: &mut Tokens) -> Result> { map: &mut std::collections::HashMap>, name: String, elem: TokenStream| { - if !map.contains_key(&name) { - order.push(name.clone()); - map.insert(name, vec![elem]); - } else { - map.get_mut(&name).unwrap().push(elem); + match map.entry(name) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + entry.get_mut().push(elem); + } + std::collections::hash_map::Entry::Vacant(entry) => { + order.push(entry.key().clone()); + entry.insert(vec![elem]); + } } }; while tokens.peek().is_some() { @@ -318,8 +355,9 @@ pub fn parse_tree_top(input: TokenStream) -> Result { let mut tokens = input.into_iter().peekable(); let ctx = parse_ctx_or_implicit(&mut tokens); - let first = parse_direct_node(&mut tokens, &ctx)?; + let first = parse_direct_node(&mut tokens, &ctx, None)?; + reject_stray_optional(&mut tokens, false)?; if let Some(tok) = tokens.next() { return Err(syn::Error::new_spanned( tok, @@ -352,7 +390,15 @@ pub fn parse_trees_top(input: TokenStream) -> Result { /// Parse a single node template and generate code that returns an `Id`. /// Handles: `(kind fields... children...)` and `{expr}`. -fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { +/// +/// `scope` is the enclosing fallible field's label, if any: inside one, a +/// `#{expr}` that interpolates an absent value breaks out to it, leaving that +/// field unset. See [`parse_direct_node_inner`]. +fn parse_direct_node( + tokens: &mut Tokens, + ctx: &Ident, + scope: Option<&Lifetime>, +) -> Result { match tokens.peek() { Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => { let group = expect_group(tokens, Delimiter::Brace)?; @@ -362,7 +408,7 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => { let group = expect_group(tokens, Delimiter::Parenthesis)?; let mut inner = group.stream().into_iter().peekable(); - parse_direct_node_inner(&mut inner, ctx) + parse_direct_node_inner(&mut inner, ctx, scope) } Some(tok) => Err(syn::Error::new_spanned( tok.clone(), @@ -377,7 +423,11 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result { /// Parse the inside of a parenthesized node: `kind fields... children...` /// or `kind "literal"` or `kind $fresh`. -fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result { +fn parse_direct_node_inner( + tokens: &mut Tokens, + ctx: &Ident, + scope: Option<&Lifetime>, +) -> Result { let kind = expect_ident(tokens, "expected node kind")?; let kind_str = kind.to_string(); @@ -392,6 +442,28 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result Result = Vec::new(); @@ -446,7 +519,47 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result = #label: { + ::std::option::Option::Some(#value) + }; + }); + field_args.push(quote! { + if let ::std::option::Option::Some(__id) = #temp { + __fields.push((#field_str, vec![__id])); + } + }); + } else { + // No `?` of its own, so failures beneath it belong to whichever + // fallible field encloses this one, if any. + let value = parse_direct_node_inner(&mut inner, ctx, scope)?; + stmts.push(quote! { let #temp: yeast::Id = #value; }); + field_args.push(quote! { __fields.push((#field_str, vec![#temp])); }); + } + continue; + } + + // Neither form matched; delegate for a consistent error message. + let value = parse_direct_node(tokens, ctx, scope)?; stmts.push(quote! { let #temp: yeast::Id = #value; }); field_args.push(quote! { __fields.push((#field_str, vec![#temp])); }); } @@ -486,7 +599,8 @@ fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result Result bool { matches!(tokens.peek(), Some(TokenTree::Group(g)) if g.delimiter() == delim) } +fn peek_is_punct(tokens: &mut Tokens, ch: char) -> bool { + matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == ch) +} + fn peek_is_repetition(tokens: &mut Tokens) -> bool { matches!(tokens.peek(), Some(TokenTree::Punct(p)) if matches!(p.as_char(), '*' | '+' | '?')) } diff --git a/shared/yeast-schema/src/node_types_yaml.rs b/shared/yeast-schema/src/node_types_yaml.rs index 5f6a3906f7cb..97052f9a835b 100644 --- a/shared/yeast-schema/src/node_types_yaml.rs +++ b/shared/yeast-schema/src/node_types_yaml.rs @@ -252,6 +252,41 @@ pub fn extend_schema_from_yaml( let yaml: YamlNodeTypes = serde_yaml::from_str(yaml_input).map_err(|e| format!("Failed to parse YAML: {e}"))?; apply_yaml_to_schema(&yaml, schema); + // The typed `YamlNodeTypes` stores each node's fields in a `BTreeMap` + // (alphabetical), losing the authored order. Re-parse as an ordered value to + // record the declared field order for presentation (see the AST dump). + record_field_order(schema, yaml_input)?; + Ok(()) +} + +/// Record each node kind's declared (named) field order from the source YAML, +/// which `serde`'s `BTreeMap`-based deserialization does not preserve. +/// `serde_yaml::Value` mappings keep insertion (source) order. +fn record_field_order(schema: &mut crate::schema::Schema, yaml_input: &str) -> Result<(), String> { + let value: serde_yaml::Value = serde_yaml::from_str(yaml_input) + .map_err(|e| format!("Failed to parse YAML for field order: {e}"))?; + let Some(named) = value.get("named").and_then(|v| v.as_mapping()) else { + return Ok(()); + }; + for (node_name, fields) in named { + let Some(node_name) = node_name.as_str() else { + continue; + }; + let Some(fields) = fields.as_mapping() else { + continue; // node with no fields (null) + }; + let mut order = Vec::new(); + for (raw_field_name, _) in fields { + let Some(raw) = raw_field_name.as_str() else { + continue; + }; + // Skip the unnamed/`child` slot; the dump handles it separately. + if let Some(name) = parse_field_name(raw).name { + order.push(schema.register_field(&name)); + } + } + schema.set_field_order(node_name, order); + } Ok(()) } diff --git a/shared/yeast-schema/src/schema.rs b/shared/yeast-schema/src/schema.rs index 9c438d7c22e8..0675d8913422 100644 --- a/shared/yeast-schema/src/schema.rs +++ b/shared/yeast-schema/src/schema.rs @@ -44,6 +44,11 @@ pub struct Schema { field_types: BTreeMap<(String, FieldId), Vec>, field_cardinalities: BTreeMap<(String, FieldId), FieldCardinality>, supertypes: BTreeMap>, + /// Per-node-kind declared field order (named fields only), as written in + /// the source node-types YAML. Field ids are not a stable ordering key + /// across front-ends, so this preserves the authored order for + /// presentation (see the AST dump). + field_order: BTreeMap>, } impl Default for Schema { @@ -65,6 +70,7 @@ impl Schema { field_types: BTreeMap::new(), field_cardinalities: BTreeMap::new(), supertypes: BTreeMap::new(), + field_order: BTreeMap::new(), } } @@ -269,6 +275,17 @@ impl Schema { .get(&(parent_kind.to_string(), field_id)) } + /// Record the declared (named) field order for a node kind, as authored in + /// the source node-types YAML. + pub fn set_field_order(&mut self, kind: &str, field_ids: Vec) { + self.field_order.insert(kind.to_string(), field_ids); + } + + /// The declared (named) field order for a node kind, if known. + pub fn field_order(&self, kind: &str) -> Option<&Vec> { + self.field_order.get(kind) + } + pub fn set_field_cardinality( &mut self, parent_kind: &str, diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md index 90edb510c1a1..be3bc913c700 100644 --- a/shared/yeast/doc/yeast.md +++ b/shared/yeast/doc/yeast.md @@ -235,6 +235,48 @@ yeast::trees!(ctx, (identifier #{name}) // an identifier from a Rust variable ``` +### Optional fields (`?`) + +A `?` on a field's value makes that field fallible. If a `#{expr}` anywhere +beneath it interpolates an absent value — an `Option` that is `None` — the +subtree is abandoned and the field is left unset: + +```rust +rule!((breakStmt label: _? @@lbl) => (break_expr label: (identifier #{lbl})?)) +``` + +Here an optional capture is being wrapped in a leaf, which without `?` needs +an `Option::map` to build the leaf only in the `Some` case: + +```rust +// Equivalent, but the intent is buried in the closure: +(break_expr label: {lbl.map(|l| tree!((identifier #{l})))}) +``` + +The marker mirrors the query language, where a quantifier likewise follows the +value it applies to (`label: _? @@lbl`). Note that the schema puts it on the +other side of the colon — `external_name?: identifier` — because it is +*declaring* a field's cardinality rather than supplying a value for it. + +Absence propagates outwards through as many levels as necessary, and a nested +`?` catches first, so an inner absent value need not discard the outer node: + +```rust +// If `name` is absent, `pattern` is left unset — but `type` is still set. +(parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty}) +``` + +Only `#{expr}` propagates absence, because it supplies a node's *content*: with +no value there is no leaf to build. A `{expr}` splice supplies *children*, where +yielding nothing already leaves the field unset (see below), so `?` is rejected +on one. Repetition has no marker at all, in templates or elsewhere: how many +children a `{expr}` contributes is a property of the expression rather than of +the syntax. + +Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile error. +That is deliberate: it keeps the choice between "leave the field unset" and +"unwrap it" explicit at every interpolation. + ### Fresh identifiers `(kind $name)` creates a leaf node with an auto-generated unique name. All @@ -279,6 +321,11 @@ yeast::trees!(ctx, ) ``` +Because an `Option` splices as zero or one id, `field: {opt}` already +leaves the field unset when `opt` is `None`. Use [`?`](#optional-fields-) +instead when the optional value has to be *wrapped* in a node first, so that +there is nothing to wrap when it is absent. + The contents of `{…}` are treated as a Rust block, so multi-statement expressions (with `let` bindings) work too: diff --git a/shared/yeast/src/build.rs b/shared/yeast/src/build.rs index 508a1e731346..f4f5ae5d18f3 100644 --- a/shared/yeast/src/build.rs +++ b/shared/yeast/src/build.rs @@ -108,6 +108,17 @@ impl<'a, C> BuildCtx<'a, C> { self.captures.get_all(name) } + /// Read the source text of a captured (or any other) node. + /// + /// Convenience for the common `ctx.ast.source_text(id)` reach-through used + /// by Rust-block rules that branch on, or embed, a raw capture's spelling + /// (e.g. an operator or keyword token). Resolves against the stored source + /// bytes, so it works for both parsed nodes and synthesized ones (via their + /// inherited source range). + pub fn source_text(&self, id: Id) -> String { + self.ast.source_text(id) + } + /// Create a named AST node with the given kind and fields. pub fn node(&mut self, kind: &str, fields: Vec<(&str, Vec)>) -> Id { let kind_id = self diff --git a/shared/yeast/src/dump.rs b/shared/yeast/src/dump.rs index 34b614323600..0e2e57e6f82a 100644 --- a/shared/yeast/src/dump.rs +++ b/shared/yeast/src/dump.rs @@ -2,6 +2,13 @@ use std::fmt::Write; use crate::{schema::Schema, Ast, Id, Node, NodeContent, CHILD_FIELD}; +#[derive(Clone, Copy)] +struct TypeCheckContext<'a> { + schema: &'a Schema, + expected: Option<&'a [crate::schema::NodeType]>, + parent_field: Option<(&'a str, &'a str)>, +} + /// Options for controlling AST dump output. pub struct DumpOptions { /// Whether to include source locations in the output. @@ -70,7 +77,11 @@ pub fn dump_ast_with_type_errors_and_options( source, options, 0, - Some((schema, None, None)), + Some(TypeCheckContext { + schema, + expected: None, + parent_field: None, + }), &mut out, ); out @@ -162,8 +173,12 @@ fn type_error_for_node( fn expected_for_field<'a>( schema: &'a Schema, parent_kind: &str, - field_id: u16, + field_name: &str, ) -> Option<&'a [crate::schema::NodeType]> { + // Resolve the field NAME in the validation schema's own id space, so the + // AST being dumped and the validation schema stay completely independent: + // they need not share field ids, only field names. + let field_id = schema.field_id_for_name(field_name)?; schema .field_types(parent_kind, field_id) .map(|v| v.as_slice()) @@ -175,11 +190,7 @@ fn dump_node( source: &str, options: &DumpOptions, indent: usize, - type_check: Option<( - &Schema, - Option<&[crate::schema::NodeType]>, - Option<(&str, &str)>, - )>, + type_check: Option>, out: &mut String, ) { let node = match ast.get_node(id) { @@ -215,25 +226,66 @@ fn dump_node( } } - if let Some((schema, expected, parent_field)) = type_check { - if let Some(err) = type_error_for_node(schema, node, expected, parent_field) { + if let Some(context) = type_check { + if let Some(err) = + type_error_for_node(context.schema, node, context.expected, context.parent_field) + { write!(out, " <-- ERROR: {err}").unwrap(); } } writeln!(out).unwrap(); - // Named fields first - for (&field_id, children) in &node.fields { - if field_id == CHILD_FIELD { - continue; // Handle unnamed children last + // Named fields first, in the schema's declared order when available + // (front-end-independent), else in field-id order. Any present fields not + // covered by the declared order are appended in field-id order. + // + // The declared order lives in the validation schema, keyed by *its* field + // ids; the AST being dumped may key the same field names under different + // ids. So map the declared order through field NAMES into this AST's own id + // space, keeping the two schemas independent (they share names, not ids). + let named_field_ids: Vec = { + let present: Vec = node + .fields + .keys() + .copied() + .filter(|&f| f != CHILD_FIELD) + .collect(); + match type_check.and_then(|context| { + context + .schema + .field_order(node.kind_name()) + .map(|order| (context.schema, order)) + }) { + Some((schema, order)) => { + let mut result: Vec = order + .iter() + .filter_map(|&f| schema.field_name_for_id(f)) + .filter_map(|name| ast.field_id_for_name(name)) + .filter(|&f| f != CHILD_FIELD && node.fields.contains_key(&f)) + .collect(); + for &f in &present { + if !result.contains(&f) { + result.push(f); + } + } + result + } + None => present, } + }; + for field_id in named_field_ids { + let children = &node.fields[&field_id]; let field_name = ast.field_name_for_id(field_id).unwrap_or("?"); - let child_type_check = type_check.map(|(schema, _, _)| { - let expected = - expected_for_field(schema, node.kind_name(), field_id).or(Some(EMPTY_NODE_TYPES)); + let child_type_check = type_check.map(|context| { + let expected = expected_for_field(context.schema, node.kind_name(), field_name) + .or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), field_name)); - (schema, expected, parent_field) + TypeCheckContext { + schema: context.schema, + expected, + parent_field, + } }); if children.len() == 1 { @@ -272,9 +324,15 @@ fn dump_node( } // Check for required fields that are absent - if let Some((schema, _, _)) = type_check { - for (field_id, field_name) in schema.required_fields_for_kind(node.kind_name()) { - if !node.fields.contains_key(&field_id) { + if let Some(context) = type_check { + for (_field_id, field_name) in context.schema.required_fields_for_kind(node.kind_name()) { + let present = match field_name { + Some(n) => ast + .field_id_for_name(n) + .is_some_and(|fid| node.fields.contains_key(&fid)), + None => node.fields.contains_key(&CHILD_FIELD), + }; + if !present { let name = field_name.unwrap_or("child"); writeln!(out, "{prefix} <-- ERROR: missing required field '{name}'").unwrap(); } @@ -283,11 +341,18 @@ fn dump_node( // Unnamed children — skip unnamed tokens (keywords, punctuation) if let Some(children) = node.fields.get(&CHILD_FIELD) { - let child_type_check = type_check.map(|(schema, _, _)| { - let expected = expected_for_field(schema, node.kind_name(), CHILD_FIELD) + let child_type_check = type_check.map(|context| { + let expected = context + .schema + .field_types(node.kind_name(), CHILD_FIELD) + .map(|v| v.as_slice()) .or(Some(EMPTY_NODE_TYPES)); let parent_field = Some((node.kind_name(), "children")); - (schema, expected, parent_field) + TypeCheckContext { + schema: context.schema, + expected, + parent_field, + } }); for &child_id in children { if let Some(child) = ast.get_node(child_id) { @@ -313,11 +378,7 @@ fn dump_node_inline( id: Id, source: &str, options: &DumpOptions, - type_check: Option<( - &Schema, - Option<&[crate::schema::NodeType]>, - Option<(&str, &str)>, - )>, + type_check: Option>, out: &mut String, ) { let node = match ast.get_node(id) { @@ -348,8 +409,10 @@ fn dump_node_inline( } } - if let Some((schema, expected, parent_field)) = type_check { - if let Some(err) = type_error_for_node(schema, node, expected, parent_field) { + if let Some(context) = type_check { + if let Some(err) = + type_error_for_node(context.schema, node, context.expected, context.parent_field) + { write!(out, " <-- ERROR: {err}").unwrap(); } } diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 6719a5498e2b..cf06d2d2c17b 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -117,6 +117,11 @@ where /// All standard primitive and string types implement [`YeastDisplay`] via /// the [`impl_yeast_display_via_display`] macro below. Coherence prevents a /// blanket `impl`, so additional types must be added explicitly. +#[diagnostic::on_unimplemented( + message = "`{Self}` cannot be interpolated with `#{{...}}`", + note = "if the value is optional, mark the enclosing field's value with `?` to leave \ + that field unset when it is absent, as in `label: (identifier #{{lbl}})?`" +)] pub trait YeastDisplay { fn yeast_to_string(&self, ast: &Ast) -> String; } @@ -183,6 +188,81 @@ impl YeastSourceRange for &T { } } +/// Normalizes a `#{expr}` interpolation to an optional value, so that a +/// fallible field — `field: (kind #{expr})?` — can tell "there is a value to +/// interpolate" apart from "there is none, so leave the field unset". +/// +/// Implemented for every [`YeastDisplay`] type, which always yields a value, +/// and for `Option` of the same, which yields one only when it is `Some`. +/// +/// The implementations are enumerated rather than blanket: a blanket +/// `impl` would overlap with the `Option` impl, since +/// coherence cannot rule out a future `impl YeastDisplay for Option`. +/// [`YeastDisplay`] itself is enumerated for the same reason. +/// +/// Note that this is used *only* inside a fallible field. Elsewhere `#{expr}` +/// still goes directly through [`YeastDisplay`], so interpolating an `Option` +/// without a `?` remains a compile error rather than silently dropping a node. +pub trait MaybeYeastValue { + /// The interpolated value's type, which knows how to render itself. + type Value: YeastDisplay + YeastSourceRange + ?Sized; + + /// Returns the value to interpolate, or `None` to leave the field unset. + fn maybe_yeast_value(&self) -> Option<&Self::Value>; +} + +macro_rules! impl_maybe_yeast_value { + ($($t:ty),* $(,)?) => { + $( + impl MaybeYeastValue for $t { + type Value = $t; + fn maybe_yeast_value(&self) -> Option<&$t> { + Some(self) + } + } + + impl MaybeYeastValue for Option<$t> { + type Value = $t; + fn maybe_yeast_value(&self) -> Option<&$t> { + self.as_ref() + } + } + )* + }; +} + +impl_maybe_yeast_value! { + Id, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize, + f32, f64, + bool, char, + String, +} + +// `str` is unsized, so it has no `Option` counterpart; `Option<&str>` is +// covered by the reference impls below. +impl MaybeYeastValue for str { + type Value = str; + fn maybe_yeast_value(&self) -> Option<&str> { + Some(self) + } +} + +impl MaybeYeastValue for &T { + type Value = T::Value; + fn maybe_yeast_value(&self) -> Option<&T::Value> { + (**self).maybe_yeast_value() + } +} + +impl MaybeYeastValue for Option<&T> { + type Value = T::Value; + fn maybe_yeast_value(&self) -> Option<&T::Value> { + (*self).and_then(MaybeYeastValue::maybe_yeast_value) + } +} + #[derive(Debug)] pub struct AstCursor<'a> { ast: &'a Ast, @@ -1329,10 +1409,27 @@ impl DesugaringConfig { None => Ok(schema::from_language(language)), } } + + /// Build the yeast `Schema` from the output YAML alone, with no input + /// tree-sitter grammar. Requires `output_node_types_yaml` to be set (there + /// is no grammar to fall back to). Used by custom (non-tree-sitter) + /// front-ends whose input schema is supplied by their own parser/adapter. + pub fn build_schema_no_language(&self) -> Result { + match self.output_node_types_yaml { + Some(yaml) => node_types_yaml::schema_from_yaml(yaml), + None => Err( + "a language-free desugarer requires output_node_types_yaml to be set".to_string(), + ), + } + } } pub struct Runner<'a, C = ()> { - language: tree_sitter::Language, + /// The input tree-sitter language, used only when parsing (`run_from_tree` + /// / `run`). `None` for pipelines that only ever run over an + /// externally-built AST (`run_from_ast`), so no tree-sitter grammar is + /// required. + language: Option, schema: schema::Schema, phases: &'a [Phase], } @@ -1342,7 +1439,7 @@ impl<'a, C> Runner<'a, C> { pub fn new(language: tree_sitter::Language, phases: &'a [Phase]) -> Self { let schema = schema::from_language(&language); Self { - language, + language: Some(language), schema, phases, } @@ -1355,7 +1452,18 @@ impl<'a, C> Runner<'a, C> { phases: &'a [Phase], ) -> Self { Self { - language, + language: Some(language), + schema: schema.clone(), + phases, + } + } + + /// Create a runner with no input tree-sitter language, for pipelines that + /// only run over an externally-built AST (`run_from_ast`). The parsing + /// entry points (`run_from_tree` / `run`) will error if called. + pub fn with_schema_no_language(schema: &schema::Schema, phases: &'a [Phase]) -> Self { + Self { + language: None, schema: schema.clone(), phases, } @@ -1368,7 +1476,7 @@ impl<'a, C> Runner<'a, C> { ) -> Result { let schema = config.build_schema(&language)?; Ok(Self { - language, + language: Some(language), schema, phases: &config.phases, }) @@ -1388,7 +1496,9 @@ impl<'a, C: Clone> Runner<'a, C> { let mut ast = Ast::from_tree_with_schema_and_source( self.schema.clone(), tree, - &self.language, + self.language + .as_ref() + .ok_or("run_from_tree requires a tree-sitter language")?, source.to_vec(), ); self.run_phases(&mut ast, user_ctx)?; @@ -1398,9 +1508,13 @@ impl<'a, C: Clone> Runner<'a, C> { /// Parse `input` and run all phases, threading `user_ctx` through /// every rule transform. The caller owns the initial context state. pub fn run_with_ctx(&self, input: &str, user_ctx: &mut C) -> Result { + let language = self + .language + .as_ref() + .ok_or("run requires a tree-sitter language")?; let mut parser = tree_sitter::Parser::new(); parser - .set_language(&self.language) + .set_language(language) .map_err(|e| format!("Failed to set language: {e}"))?; let tree = parser .parse(input, None) @@ -1408,7 +1522,7 @@ impl<'a, C: Clone> Runner<'a, C> { let mut ast = Ast::from_tree_with_schema_and_source( self.schema.clone(), &tree, - &self.language, + language, input.as_bytes().to_vec(), ); self.run_phases(&mut ast, user_ctx)?; @@ -1506,7 +1620,10 @@ pub trait Desugarer: Send + Sync { /// schema so that per-call cost is bounded to constructing a transient /// [`Runner`] and cloning the schema (no YAML re-parsing). pub struct ConcreteDesugarer { - language: tree_sitter::Language, + /// The input tree-sitter language, or `None` for a custom (non-tree-sitter) + /// front-end that only ever desugars an externally-built AST + /// (`run_from_ast`). + language: Option, schema: schema::Schema, config: DesugaringConfig, } @@ -1520,7 +1637,20 @@ impl ConcreteDesugarer { ) -> Result { let schema = config.build_schema(&language)?; Ok(Self { - language, + language: Some(language), + schema, + config, + }) + } + + /// Build a desugarer with no input tree-sitter language, for a custom + /// front-end whose parser supplies the input AST directly. Only + /// [`run_from_ast`](Desugarer::run_from_ast) is supported; the schema comes + /// from the config's `output_node_types_yaml` (which must be set). + pub fn without_language(config: DesugaringConfig) -> Result { + let schema = config.build_schema_no_language()?; + Ok(Self { + language: None, schema, config, }) @@ -1533,7 +1663,11 @@ impl Desugarer for ConcreteDesugarer } fn run_from_tree(&self, tree: &tree_sitter::Tree, source: &[u8]) -> Result { - let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases); + let language = self + .language + .clone() + .ok_or("run_from_tree requires a tree-sitter language")?; + let runner = Runner::with_schema(language, &self.schema, &self.config.phases); runner.run_from_tree(tree, source) } @@ -1541,7 +1675,8 @@ impl Desugarer for ConcreteDesugarer // The AST was built against its own (external) schema; make sure the // output kind/field names the rules build are resolvable in it. ast.register_names_from_schema(&self.schema); - let runner = Runner::with_schema(self.language.clone(), &self.schema, &self.config.phases); + // `run_from_ast` never parses, so no tree-sitter language is needed. + let runner = Runner::with_schema_no_language(&self.schema, &self.config.phases); runner.run_from_ast(ast) } } diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs index 756e219bd890..bdc17c7593dc 100644 --- a/shared/yeast/tests/test.rs +++ b/shared/yeast/tests/test.rs @@ -674,6 +674,117 @@ fn test_tree_builder() { ); } +/// Builds `(assignment left: … right: (integer #{value})?)`, where a `None` +/// `value` leaves `right` unset rather than producing an `integer` with no +/// content. +fn build_optional_right(ast: &mut Ast, value: Option) -> (yeast::Id, yeast::Id) { + let captures = yeast::captures::Captures::new(); + let fresh = yeast::tree_builder::FreshScope::new(); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(ast, &captures, &fresh, &mut user_ctx); + let left = yeast::tree!(ctx, (identifier "x")); + let root = yeast::tree!(ctx, + (assignment + left: {left} + right: (integer #{value})? + ) + ); + (root, left) +} + +#[test] +fn test_optional_field_is_set_when_the_value_is_present() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + // Any node will do as the interpolated value; `#{…}` renders its source text. + let mut cursor = AstCursor::new(&ast); + cursor.goto_first_child(); + let some = cursor.node_id(); + + let (root, _) = build_optional_right(&mut ast, Some(some)); + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + left: identifier "x" + right: integer "x = 1" + "#, + ); +} + +#[test] +fn test_optional_field_is_unset_when_the_value_is_absent() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + let (root, _) = build_optional_right(&mut ast, None); + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + left: identifier "x" + "#, + ); +} + +#[test] +fn test_optional_field_propagates_through_nested_nodes() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + let captures = yeast::captures::Captures::new(); + let fresh = yeast::tree_builder::FreshScope::new(); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx); + + // The absent value sits two levels below the `?`, so the whole + // `left_assignment_list` subtree is abandoned along with it. + let absent: Option = None; + let right = yeast::tree!(ctx, (integer "1")); + let root = yeast::tree!(ctx, + (assignment + left: (left_assignment_list child: (identifier #{absent}))? + right: {right} + ) + ); + + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + right: integer "1" + "#, + ); +} + +#[test] +fn test_innermost_optional_field_catches_first() { + let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]); + let mut ast = runner.run("x = 1").unwrap(); + + let captures = yeast::captures::Captures::new(); + let fresh = yeast::tree_builder::FreshScope::new(); + let mut user_ctx = (); + let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx); + + // The inner `?` catches, so only `child` is dropped; `left` survives. + let absent: Option = None; + let root = yeast::tree!(ctx, + (assignment + left: (left_assignment_list child: (identifier #{absent})?)? + ) + ); + + assert_dump_eq( + &dump_ast(&ast, root, "x = 1"), + r#" + assignment + left: left_assignment_list + "#, + ); +} + // ---- Rule tests ---- // These rules use field names from node-types.yml, which extends the diff --git a/swift/extractor/mangler/SwiftMangler.cpp b/swift/extractor/mangler/SwiftMangler.cpp index e7dbda6ba914..986cce695103 100644 --- a/swift/extractor/mangler/SwiftMangler.cpp +++ b/swift/extractor/mangler/SwiftMangler.cpp @@ -1,6 +1,5 @@ #include "swift/extractor/mangler/SwiftMangler.h" #include "swift/extractor/infra/SwiftDispatcher.h" -#include "swift/extractor/trap/generated/decl/TrapClasses.h" #include "swift/logging/SwiftLogging.h" #include @@ -170,15 +169,12 @@ void SwiftMangler::indexExtensionsAndFilePrivateValues(llvm::ArrayRefsubmodules()) { + index = indexClangSubmoduleExtensionsAndFilePrivateValues(submodule, moduleLoader, index); if (auto* swiftSubmodule = moduleLoader->getWrapperForModule(submodule)) { llvm::SmallVector children; swiftSubmodule->getTopLevelDecls(children); @@ -191,6 +187,17 @@ void SwiftMangler::indexClangExtensionsAndFilePrivateValues( } } } + return index; +} + +void SwiftMangler::indexClangExtensionsAndFilePrivateValues( + const clang::Module* clangModule, + swift::ClangModuleLoader* moduleLoader) { + if (!moduleLoader) { + return; + } + + indexClangSubmoduleExtensionsAndFilePrivateValues(clangModule, moduleLoader, 0u); } SwiftMangledName SwiftMangler::visitGenericTypeParamDecl(const swift::GenericTypeParamDecl* decl) { diff --git a/swift/extractor/mangler/SwiftMangler.h b/swift/extractor/mangler/SwiftMangler.h index 92175b5887b3..6b835348f14b 100644 --- a/swift/extractor/mangler/SwiftMangler.h +++ b/swift/extractor/mangler/SwiftMangler.h @@ -126,6 +126,9 @@ class SwiftMangler : private swift::TypeVisitor, bool isExtensionOrFilePrivateValue(const swift::Decl* decl); void indexExtensionsAndFilePrivateValues(llvm::ArrayRef siblings); + uint32_t indexClangSubmoduleExtensionsAndFilePrivateValues(const clang::Module* clangModule, + swift::ClangModuleLoader* moduleLoader, + uint32_t index); void indexClangExtensionsAndFilePrivateValues(const clang::Module* clangModule, swift::ClangModuleLoader* moduleLoader); ExtensionOrFilePrivateValueIndex getExtensionOrFilePrivateValueIndex(const swift::Decl* decl, diff --git a/swift/ql/lib/CHANGELOG.md b/swift/ql/lib/CHANGELOG.md index 168e31e76c18..ffad5ee2398a 100644 --- a/swift/ql/lib/CHANGELOG.md +++ b/swift/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.8.1 + +No user-facing changes. + ## 6.8.0 ### Major Analysis Improvements diff --git a/swift/ql/lib/change-notes/released/6.8.1.md b/swift/ql/lib/change-notes/released/6.8.1.md new file mode 100644 index 000000000000..eb2ce653fc0f --- /dev/null +++ b/swift/ql/lib/change-notes/released/6.8.1.md @@ -0,0 +1,3 @@ +## 6.8.1 + +No user-facing changes. diff --git a/swift/ql/lib/codeql-pack.release.yml b/swift/ql/lib/codeql-pack.release.yml index 78131e1dceb7..49874c2924ed 100644 --- a/swift/ql/lib/codeql-pack.release.yml +++ b/swift/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 6.8.0 +lastReleaseVersion: 6.8.1 diff --git a/swift/ql/lib/qlpack.yml b/swift/ql/lib/qlpack.yml index 811270faed34..856752875cd8 100644 --- a/swift/ql/lib/qlpack.yml +++ b/swift/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-all -version: 6.8.0 +version: 6.8.1 groups: swift extractor: swift dbscheme: swift.dbscheme diff --git a/swift/ql/src/CHANGELOG.md b/swift/ql/src/CHANGELOG.md index 0063b69f12b3..826ee7e9d4e9 100644 --- a/swift/ql/src/CHANGELOG.md +++ b/swift/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.8 + +No user-facing changes. + ## 1.3.7 No user-facing changes. diff --git a/swift/ql/src/change-notes/released/1.3.8.md b/swift/ql/src/change-notes/released/1.3.8.md new file mode 100644 index 000000000000..c7f5b27e47ec --- /dev/null +++ b/swift/ql/src/change-notes/released/1.3.8.md @@ -0,0 +1,3 @@ +## 1.3.8 + +No user-facing changes. diff --git a/swift/ql/src/codeql-pack.release.yml b/swift/ql/src/codeql-pack.release.yml index 2f4b67be43f7..898725a6deb4 100644 --- a/swift/ql/src/codeql-pack.release.yml +++ b/swift/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.3.7 +lastReleaseVersion: 1.3.8 diff --git a/swift/ql/src/qlpack.yml b/swift/ql/src/qlpack.yml index ef34bce7e957..91be0e594012 100644 --- a/swift/ql/src/qlpack.yml +++ b/swift/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/swift-queries -version: 1.3.7 +version: 1.3.8 groups: - swift - queries diff --git a/unified/AGENTS.md b/unified/AGENTS.md index a50a49868a24..9c9bbbb534cb 100644 --- a/unified/AGENTS.md +++ b/unified/AGENTS.md @@ -1,23 +1,32 @@ # Agent instructions -This is a CodeQL extractor based on tree-sitter. +This is a CodeQL extractor that maps a language's parse tree onto a shared AST +using the `yeast` desugaring engine. Swift, the only language so far, is parsed +by Apple's swift-syntax rather than by tree-sitter. ## Building - To build the extractor, run `scripts/create-extractor-pack.sh` ## Swift Parser -- The Swift parser is defined by `extractor/tree-sitter-swift/grammar.js` and can be edited if needed. +- Swift source is parsed by `swift-syntax-parse`, a small Swift/Rust binary in + `swift-syntax-rs` that wraps Apple's swift-syntax and emits the parse tree as + JSON. There is no grammar in this repository to edit. -- After editing the grammar, always run `scripts/regenerate-grammar.sh`. +- `extractor/src/languages/swift/adapter.rs` converts that JSON into a yeast AST. -- The raw parse tree is described by `extractor/tree-sitter-swift/node-types.yml` and should be reviewed after grammar changes. +- The raw parse tree's shape is described by `extractor/swift_node_types.yml`, + which is maintained by hand. ## AST Mapping - The target AST shape is described by `extractor/ast_types.yml`. - The mapping from the parse tree to the target AST is found in `extractor/src/languages/swift/swift.rs` -- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory. +- To run tests for the parser and mapping, run `cargo test` in the `extractor` + directory. The tests need the `swift-syntax-parse` binary: point + `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` at it, or put it on `PATH`. + Corpus tests skip themselves when it cannot be found, so check for skips + before concluding a change is clean. - Extractor test cases are located at `extractor/tests/corpus/swift/*/*.swift`. diff --git a/unified/BUILD.bazel b/unified/BUILD.bazel index e702fd251594..405500d7d407 100644 --- a/unified/BUILD.bazel +++ b/unified/BUILD.bazel @@ -1,5 +1,6 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup") load("//misc/bazel:pkg.bzl", "codeql_pack", "codeql_pkg_files") +load("//misc/bazel:utils.bzl", "select_os") package(default_visibility = ["//visibility:public"]) @@ -46,12 +47,26 @@ codeql_pkg_files( prefix = "tools/{CODEQL_PLATFORM}", ) +# The Swift front-end parser (wrapper + real binary + bundled Swift runtime), +# shipped next to the extractor. Only on platforms where swift-syntax builds +# (Linux/macOS); elsewhere the group is empty so the pack still builds (Swift +# extraction is simply unavailable there). +pkg_filegroup( + name = "swift-syntax-parse-arch", + srcs = select_os( + otherwise = [], + posix = ["//unified/swift-syntax-rs:swift-syntax-parse-pkg"], + ), + prefix = "tools/{CODEQL_PLATFORM}", +) + codeql_pack( name = "unified", srcs = [ ":codeql-extractor-yml", ":dbscheme-group", ":extractor-arch", + ":swift-syntax-parse-arch", "//unified/tools", ], ) diff --git a/unified/extractor/BUILD.bazel b/unified/extractor/BUILD.bazel index 0ef7f1b68b0e..58b32d9fc5c3 100644 --- a/unified/extractor/BUILD.bazel +++ b/unified/extractor/BUILD.bazel @@ -7,7 +7,10 @@ codeql_rust_binary( name = "extractor", srcs = glob(["src/**/*.rs"]), aliases = aliases(), - compile_data = ["ast_types.yml"], + compile_data = [ + "ast_types.yml", + "swift_node_types.yml", + ], proc_macro_deps = all_crate_deps( proc_macro = True, ), @@ -17,6 +20,5 @@ codeql_rust_binary( ) + [ "//shared/tree-sitter-extractor", "//shared/yeast", - "//unified/extractor/tree-sitter-swift", ], ) diff --git a/unified/extractor/Cargo.toml b/unified/extractor/Cargo.toml index 39c20598b1ff..be333298f1ad 100644 --- a/unified/extractor/Cargo.toml +++ b/unified/extractor/Cargo.toml @@ -7,9 +7,6 @@ edition = "2024" # When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh` [dependencies] -tree-sitter = ">= 0.23.0" -tree-sitter-embedded-template = "0.25.0" -tree-sitter-swift = { path = "tree-sitter-swift" } clap = { version = "4.5", features = ["derive"] } tracing = "0.1" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index 418772aa2680..ca5f6d45edc6 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -31,6 +31,7 @@ supertypes: - throw_expr - try_expr - switch_expr + - unresolved_operator_sequence - unsupported_node expr_or_pattern: - expr @@ -38,11 +39,17 @@ supertypes: expr_or_type: - expr - type_expr + # An element of an `unresolved_operator_sequence`: either an operand (`expr`) + # or one of the infix operators separating the operands. + expr_or_operator: + - expr + - infix_operator pattern: - name_pattern - tuple_pattern - constructor_pattern - or_pattern + - conditional_pattern - ignore_pattern - expr_equality_pattern - bulk_importing_pattern @@ -50,9 +57,6 @@ supertypes: # A statement is anything that can appear in a block. # This type contains all of 'expr' and has partial overlap with 'member'. # For example, type_alias_declaration can appear either as a stmt or member. - # constructor_declaration and destructor_declaration appear here because - # tree-sitter-swift's error recovery for #if/#endif in class bodies can place - # init/deinit declarations at the wrong (statement) level. stmt: - expr - variable_declaration @@ -137,6 +141,19 @@ named: operand: expr operator: operator + # A flat, unresolved operator sequence such as `a <+> b <+> c`. + # + # Swift's grammar doesn't encode operator precedence, so an operator chain is + # first parsed as a flat list of operands and operators. The parser front-end + # resolves this into structured `binary_expr` trees when it knows the + # operators' precedence (standard-library operators, and operators declared in + # the same file). When it encounters an operator whose precedence it can't + # determine (e.g. one imported from another module), it leaves that chain + # unresolved and emits it here rather than guessing a (possibly wrong) + # structure. The `element`s alternate operands (`expr`) and infix operators. + unresolved_operator_sequence: + element*: expr_or_operator + # Plain assignment assign_expr: target: expr_or_pattern @@ -350,7 +367,6 @@ named: catch_clause: modifier*: modifier pattern?: pattern - guard?: expr body: block # `switch value { case pattern: body case ...: default: body }` @@ -362,11 +378,9 @@ named: # A single `case ...:` (or `default:`) entry in a switch. # An entry with multiple `case p1, p2:` patterns uses an `or_pattern`. # A `default:` entry has no pattern. - # An optional `guard` corresponds to a `where`-clause on the case. switch_case: modifier*: modifier pattern?: pattern - guard?: expr body: block # Evaluate 'expr' and match its result against 'pattern', and return true if it matches. @@ -427,6 +441,14 @@ named: modifier*: modifier pattern*: pattern + # A pattern that matches against a nested pattern, and subsequently checks a condition. + # The match is rejected if the condition does not hold. + # Variables bound in the nested pattern are in scope within the condition. + conditional_pattern: + modifier*: modifier + condition: expr + pattern: pattern + # A pattern with an optional associated name. pattern_element: modifier*: modifier diff --git a/unified/extractor/src/extractor.rs b/unified/extractor/src/extractor.rs index 301c6cf533f4..82bfe81219b5 100644 --- a/unified/extractor/src/extractor.rs +++ b/unified/extractor/src/extractor.rs @@ -2,7 +2,7 @@ use clap::Args; use std::path::PathBuf; use crate::languages; -use codeql_extractor::extractor::simple; +use codeql_extractor::extractor::desugaring; use codeql_extractor::trap; #[derive(Args)] @@ -31,7 +31,7 @@ pub fn run(options: Options) -> std::io::Result<()> { lang.prefix = "unified"; } - let extractor = simple::Extractor { + let extractor = desugaring::Extractor { prefix: "unified".to_string(), languages, trap_dir: options.output_dir, diff --git a/unified/extractor/src/generator.rs b/unified/extractor/src/generator.rs index 974de5dbca97..f1f8a34ca84d 100644 --- a/unified/extractor/src/generator.rs +++ b/unified/extractor/src/generator.rs @@ -35,6 +35,7 @@ pub fn run(options: Options) -> std::io::Result<()> { languages, options.dbscheme, options.library, + true, // use facade AST "run unified/scripts/create-extractor-pack.sh", ) } diff --git a/unified/extractor/src/languages/mod.rs b/unified/extractor/src/languages/mod.rs index 52a1bd40ffc7..c79806dc9d43 100644 --- a/unified/extractor/src/languages/mod.rs +++ b/unified/extractor/src/languages/mod.rs @@ -1,20 +1,21 @@ -use codeql_extractor::extractor::simple; +use codeql_extractor::extractor::desugaring; #[path = "swift/swift.rs"] mod swift; /// swift-syntax JSON -> `yeast::Ast` adapter for the Swift front-end. -/// -/// Currently exercised by tests and the forthcoming runtime extraction path; -/// `allow(dead_code)` because this is a binary crate, so its public API isn't -/// counted as used until the binary itself calls it. #[path = "swift/adapter.rs"] -#[allow(dead_code)] pub mod swift_adapter; +/// Swift front-end parser: shells out to `swift-syntax-parse` and adapts its +/// JSON output via [`swift_adapter`]. This is the live Swift front-end used by +/// [`all_language_specs`]. +#[path = "swift/parse.rs"] +pub mod swift_parse; + /// Shared YEAST output AST schema for all languages. pub(crate) const OUTPUT_AST_SCHEMA: &str = include_str!("../../ast_types.yml"); -pub fn all_language_specs() -> Vec { +pub fn all_language_specs() -> Vec { vec![swift::language_spec(OUTPUT_AST_SCHEMA)] } diff --git a/unified/extractor/src/languages/swift/adapter.rs b/unified/extractor/src/languages/swift/adapter.rs index 37d5aac00d2d..f34e5df3d00b 100644 --- a/unified/extractor/src/languages/swift/adapter.rs +++ b/unified/extractor/src/languages/swift/adapter.rs @@ -2,9 +2,8 @@ //! in-memory format the CodeQL desugaring rules operate on. //! //! The JSON tree is produced by the `swift-syntax-rs` crate's Swift FFI shim -//! (`parse_to_json`). This module is pure Rust (only `yeast` + `serde_json`), -//! so the extractor consumes swift-syntax output without pulling in the Swift -//! toolchain (the JSON is produced out-of-process). +//! (`parse_to_json`). This module needs no Swift toolchain, so the extractor +//! consumes swift-syntax output out-of-process. //! //! The mapping mirrors tree-sitter's node model, which is what yeast (and the //! extractor's rewrite rules) expect: @@ -18,37 +17,24 @@ //! * Collection nodes are already elided to JSON arrays upstream, so a //! list-valued field maps directly to that field holding several children. //! -//! Note: this preserves swift-syntax's own kind/field names. Aligning those -//! names with the tree-sitter-swift schema (so the rewrite rules in -//! [`super::swift`] fire) is done incrementally in the rules. +//! Note: this preserves swift-syntax's own kind/field names; the rewrite rules +//! in [`super::swift`] match those names directly. use std::collections::BTreeMap; +use codeql_extractor::extractor::ExtraToken; use serde_json::Value; -use yeast::schema::Schema; use yeast::{Ast, Id, NodeContent, Point, Range}; -/// A comment (or `unexpectedText`) recovered from the syntax tree's trivia. +/// The result of adapting a swift-syntax JSON tree: the [`yeast::Ast`] plus the +/// comment/`unexpectedText` [`ExtraToken`]s harvested from it (in source order). /// -/// These are collected into a side channel rather than embedded in the -/// [`yeast::Ast`], mirroring how the extractor treats tree-sitter `extra` +/// The extra tokens are collected into a side channel rather than embedded in +/// the [`yeast::Ast`], mirroring how the extractor treats tree-sitter `extra` /// nodes: they carry a location and text but are not attached to a parent. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TriviaToken { - /// The trivia kind (e.g. `lineComment`, `blockComment`, `docLineComment`, - /// `docBlockComment`, `unexpectedText`). - pub kind: String, - /// The verbatim source text of the piece (e.g. `// comment`). - pub text: String, - /// The source range the piece occupies. - pub range: Range, -} - -/// The result of adapting a swift-syntax JSON tree: the [`yeast::Ast`] plus the -/// comment/`unexpectedText` trivia harvested from it (in source order). pub struct AdaptedTree { pub ast: Ast, - pub trivia: Vec, + pub extras: Vec, } /// swift-syntax `TokenKind` cases whose text is *not* determined by the kind @@ -170,17 +156,18 @@ fn children_of(value: &Value) -> Vec<&Value> { /// in the schema on the fly, immediately before the node is created. Children /// are built first so a parent's field lists reference existing ids. Any /// comment/`unexpectedText` trivia carried by a token is harvested into -/// `trivia` during the same pass rather than embedded in the tree. -fn build(node: &Value, ast: &mut Ast, trivia: &mut Vec) -> Result { +/// `extras` (as [`ExtraToken`]s) during the same pass rather than embedded in +/// the tree. +fn build(node: &Value, ast: &mut Ast, extras: &mut Vec) -> Result { let info = classify(node)?; - collect_trivia(node, trivia); + collect_extras(node, extras); let mut fields: BTreeMap> = BTreeMap::new(); for (field, value) in field_entries(node) { let field_id = ast.register_field(field); let mut ids = Vec::new(); for child in children_of(value) { - ids.push(build(child, ast, trivia)?); + ids.push(build(child, ast, extras)?); } fields.insert(field_id, ids); } @@ -201,9 +188,10 @@ fn build(node: &Value, ast: &mut Ast, trivia: &mut Vec) -> Result) { +/// filtered to comments/`unexpectedText` upstream) into `out` as +/// [`ExtraToken`]s. Non-token nodes have no trivia keys, so this is a no-op for +/// them. +fn collect_extras(node: &Value, out: &mut Vec) { for key in ["leadingTrivia", "trailingTrivia"] { let Some(Value::Array(pieces)) = node.get(key) else { continue; @@ -220,8 +208,8 @@ fn collect_trivia(node: &Value, out: &mut Vec) { .and_then(Value::as_str) .unwrap_or("") .to_string(); - out.push(TriviaToken { - kind: kind.to_string(), + out.push(ExtraToken { + kind: trivia_kind_id(kind), text, range, }); @@ -229,6 +217,21 @@ fn collect_trivia(node: &Value, out: &mut Vec) { } } +/// Map a swift-syntax trivia kind name to the stable integer id stored in an +/// [`ExtraToken`]'s `kind` (and written to the `unified_trivia_tokeninfo` +/// table). The value is opaque to the QL library (which reads only the text), +/// but is kept stable and meaningful. +fn trivia_kind_id(kind: &str) -> usize { + match kind { + "lineComment" => 1, + "blockComment" => 2, + "docLineComment" => 3, + "docBlockComment" => 4, + "unexpectedText" => 5, + _ => 0, + } +} + /// Parse a node's `range` into a [`yeast::Range`]. /// /// The JSON carries, for `start` and `end`, a 0-based UTF-8 file byte `offset`, @@ -258,21 +261,29 @@ fn parse_range(node: &Value) -> Option { }) } +/// The authoritative swift-syntax input node-types schema. +/// [`json_to_ast`] seeds every parse with the schema built from this, +/// pre-registering every input kind and field so rule matching never references +/// a name absent from a given file's tree. +const SWIFT_NODE_TYPES: &str = include_str!("../../../swift_node_types.yml"); + /// Convert a swift-syntax JSON tree (as produced by [`crate::parse_to_json`]) /// into a [`yeast::Ast`] plus the comment/`unexpectedText` trivia harvested -/// from it. Both are produced in a single traversal. +/// from it. Both are produced in a single traversal. The AST is seeded with the +/// authoritative swift-syntax schema ([`SWIFT_NODE_TYPES`]); the adapter only +/// ever consumes swift-syntax input, so the schema is not a parameter. pub fn json_to_ast(json: &str) -> Result { let root: Value = serde_json::from_str(json).map_err(|e| format!("invalid JSON: {e}"))?; - let mut ast = Ast::with_schema(Schema::new()); - let mut trivia = Vec::new(); - let root_id = build(&root, &mut ast, &mut trivia)?; + let mut ast = Ast::with_schema(yeast::node_types_yaml::schema_from_yaml(SWIFT_NODE_TYPES)?); + let mut extras = Vec::new(); + let root_id = build(&root, &mut ast, &mut extras)?; ast.set_root(root_id); - // Emit trivia in source order (the traversal visits nodes bottom-up). - trivia.sort_by_key(|t| t.range.start_byte); + // Emit extras in source order (the traversal visits nodes bottom-up). + extras.sort_by_key(|t| t.range.start_byte); - Ok(AdaptedTree { ast, trivia }) + Ok(AdaptedTree { ast, extras }) } #[cfg(test)] @@ -373,7 +384,7 @@ mod tests { } #[test] - fn collects_trivia_into_side_channel() { + fn collects_extras_into_side_channel() { // A token carrying a trailing line comment in its trivia. let json = r#"{ "kind": "sourceFile", @@ -395,9 +406,10 @@ mod tests { let adapted = json_to_ast(json).expect("adapter should succeed"); // The comment is in the side channel, with its text and location. - assert_eq!(adapted.trivia.len(), 1); - let comment = &adapted.trivia[0]; - assert_eq!(comment.kind, "lineComment"); + assert_eq!(adapted.extras.len(), 1); + let comment = &adapted.extras[0]; + // `lineComment` maps to extra kind id 1. + assert_eq!(comment.kind, 1); assert_eq!(comment.text, "// c"); assert_eq!(comment.range.start_byte, 2); assert_eq!(comment.range.end_byte, 6); diff --git a/unified/extractor/src/languages/swift/parse.rs b/unified/extractor/src/languages/swift/parse.rs new file mode 100644 index 000000000000..c8633f1a27a5 --- /dev/null +++ b/unified/extractor/src/languages/swift/parse.rs @@ -0,0 +1,121 @@ +//! Swift front-end parser: shells out to the separate `swift-syntax-parse` +//! binary (which links swift-syntax) to obtain a JSON syntax tree, then adapts +//! that JSON into a `yeast::Ast` via the pure-Rust [`swift_adapter`] module. +//! +//! Running the parser in a separate process keeps the Swift toolchain out of +//! the extractor's own build: the extractor never links Swift, so working on +//! other (e.g. tree-sitter based) languages needs no Swift toolchain. Each call +//! spawns the parser afresh; a longer-lived parser process could be swapped in +//! behind this same seam later without touching the extraction pipeline. + +use std::io::Write; +use std::process::{Command, Stdio}; + +use codeql_extractor::extractor::ParsedTree; + +use super::swift_adapter; + +/// Environment variable naming the `swift-syntax-parse` executable. When unset, +/// the parser is resolved next to the extractor executable, then on `PATH`. +const PARSE_BIN_ENV: &str = "CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE"; + +/// Base name of the `swift-syntax-parse` executable as shipped / looked up. +const PARSE_BIN_NAME: &str = "swift-syntax-parse"; + +/// Parse Swift `source` into a [`ParsedTree`] (a raw `yeast::Ast` plus +/// side-channel `extra` tokens), ready to be desugared via `run_from_ast`. +pub fn parse(source: &[u8]) -> Result { + let source = + std::str::from_utf8(source).map_err(|e| format!("Swift source is not valid UTF-8: {e}"))?; + let json = run_parser(source)?; + let mut adapted = swift_adapter::json_to_ast(&json)?; + adapted.ast.set_source(source.as_bytes().to_vec()); + Ok(ParsedTree { + ast: adapted.ast, + extras: adapted.extras, + }) +} + +/// The `swift-syntax-parse` executable to invoke, resolved in priority order: +/// +/// 1. the `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` override, if set; +/// 2. a copy shipped next to the extractor executable — this is how the CodeQL +/// extractor pack lays it out (`tools//{extractor, +/// swift-syntax-parse}`), so a packaged extractor is self-contained with no +/// environment setup; +/// 3. a bare `swift-syntax-parse`, looked up on `PATH`. +fn parse_bin() -> String { + if let Ok(bin) = std::env::var(PARSE_BIN_ENV) { + if !bin.is_empty() { + return bin; + } + } + if let Ok(exe) = std::env::current_exe() { + if let Some(sibling) = exe.parent().map(|dir| dir.join(PARSE_BIN_NAME)) { + if sibling.is_file() { + return sibling.to_string_lossy().into_owned(); + } + } + } + PARSE_BIN_NAME.to_string() +} + +/// Whether the `swift-syntax-parse` executable can be launched at all. +/// +/// This reports availability of the *executable*, deliberately not whether +/// parsing succeeds: a binary that launches but then crashes or emits invalid +/// JSON is still "available", so callers run and surface the failure rather +/// than silently skipping. Only a genuinely missing/unlaunchable binary (e.g. +/// no Swift toolchain is installed) reports `false`. +pub fn binary_available() -> bool { + match Command::new(parse_bin()) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + { + Ok(mut child) => { + let _ = child.wait(); + true + } + Err(e) if e.kind() == std::io::ErrorKind::NotFound => false, + // Any other spawn failure (e.g. a permissions problem) is a genuine + // issue worth surfacing, so treat the parser as available and let the + // caller fail rather than masking it as "unavailable". + Err(_) => true, + } +} + +/// Run the external parser, feeding `source` on stdin and returning its JSON +/// stdout. +fn run_parser(source: &str) -> Result { + let bin = parse_bin(); + let mut child = Command::new(&bin) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .map_err(|e| format!("failed to spawn Swift parser `{bin}`: {e}"))?; + + // The parser reads all of stdin before writing any stdout, so writing the + // whole source and then closing stdin (by dropping it) cannot deadlock. + child + .stdin + .take() + .expect("child stdin was piped") + .write_all(source.as_bytes()) + .map_err(|e| format!("failed to write source to Swift parser `{bin}`: {e}"))?; + + let output = child + .wait_with_output() + .map_err(|e| format!("failed to run Swift parser `{bin}`: {e}"))?; + if !output.status.success() { + return Err(format!( + "Swift parser `{bin}` failed ({}): {}", + output.status, + String::from_utf8_lossy(&output.stderr).trim() + )); + } + String::from_utf8(output.stdout) + .map_err(|e| format!("Swift parser produced non-UTF-8 output: {e}")) +} diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 13f1a6beadf0..000601b7215c 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -1,4 +1,4 @@ -use codeql_extractor::extractor::simple; +use codeql_extractor::extractor::desugaring; use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree}; /// User context propagated from outer rules down to the inner rules that @@ -8,50 +8,42 @@ use yeast::{ConcreteDesugarer, DesugaringConfig, PhaseKind, Rule, rule, tree}; /// post-hoc mutation. #[derive(Clone, Default)] struct SwiftContext { - /// Identifier node for the property name. Set by the outer - /// `property_binding` (computed accessors / willSet-didSet) and - /// `protocol_property_declaration` rules before translating accessor - /// children; read by the accessor inner rules - /// (`computed_getter`/`computed_setter`/`computed_modify`/ - /// `willset_clause`/`didset_clause`/`getter_specifier`/ - /// `setter_specifier`). + /// Identifier node for the property name. Set by the accessor-bearing + /// `variableDecl` rule before translating the accessor block; read by the + /// inner `accessorDecl` rules to name each `accessor_declaration`. property_name: Option, - /// Translated type node for the property type. Set by the outer - /// `property_binding` rule (computed accessors variant) and - /// `protocol_property_declaration` when present; read by the - /// accessor inner rules. + /// Translated type node for the property type. Set (for computed + /// properties) by the accessor-bearing `variableDecl` rule; read by the + /// inner `accessorDecl` rules. Left `None` for stored properties with + /// observers, so their `willSet`/`didSet` accessors carry no type. property_type: Option, - /// Default-value expression for the next translated `parameter`. Set - /// by the outer `function_parameter` rule; read by the `parameter` - /// rules. - default_value: Option, /// Translated outer modifiers to attach to each child of a flattening - /// outer rule. Set by `property_declaration`, `binding_pattern`, - /// `enum_entry`, and `protocol_property_declaration`. For `let`/`var` - /// declarations and `binding_pattern`s the list is led by the binding - /// modifier, which also serves as the "this is a binding" signal for - /// pattern translation (see `in_binding_pattern`). + /// outer rule — e.g. the `let`/`var` binding modifier on each + /// `patternBinding` of a `variableDecl`, or the binding modifier on each + /// accessor of a property. outer_modifiers: Vec, /// True when the current child of a flattening outer rule is not /// the first one — its inner rule should emit a /// `chained_declaration` modifier so the original grouping can be /// recovered downstream. is_chained: bool, + /// True while translating the parameters of a `functionType`. swift-syntax + /// models a function type's parameters with the same `tupleTypeElement` + /// kind as a tuple type's elements, so the shared `tupleTypeElement` rule + /// reads this to emit a `parameter` (function-type param) rather than a + /// `tuple_type_element` (tuple-type element). The `tupleType` / + /// `functionType` rules each set it for their direct children, so nested + /// types are translated in the correct context. + in_function_type: bool, + /// True while translating the argument list of an enum-case + /// `constructor_pattern` (e.g. `case .foo(let x, 3)`). Read by the + /// `labeledExpr` rules so a bare expression argument becomes an + /// `expr_equality_pattern` (wrapped in a `pattern_element`) rather than a + /// call `argument`. + in_pattern: bool, } impl SwiftContext { - /// Whether the pattern currently being translated is a binding - /// (the LHS of a `let`/`var` declaration or a `binding_pattern`). - /// - /// True exactly when an enclosing binding has published its modifier into - /// `outer_modifiers`. This is reliable because non-binding subtrees - /// (bodies, initializer values, ...) are translated after resetting the - /// context (see `reset`), so a bare identifier only sees a - /// non-empty `outer_modifiers` when it really is a binding. - fn in_binding_pattern(&self) -> bool { - !self.outer_modifiers.is_empty() - } - /// Clear the context fields that must not propagate into an /// expression / statement / body subtree. /// @@ -77,7 +69,7 @@ impl SwiftContext { /// rule. Returns `Option` so it splices via `{…}` to 0 or 1 ids. fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Option { if ctx.is_chained { - Some(ctx.literal("modifier", "chained_declaration")) + Some(tree!((modifier "chained_declaration"))) } else { None } @@ -85,8 +77,8 @@ fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Optio /// Combine a list of boolean sub-conditions into a single expression by /// left-folding with the infix `&&` operator. Used by control-flow -/// rules (`if`, `guard`, `while`, `repeat-while`) whose tree-sitter -/// nodes carry one or more comma-separated conditions that the target +/// rules (`if`, `guard`, `while`, `repeat-while`), which carry one or +/// more comma-separated conditions that the target /// AST represents as a single `condition:` field. Panics on an empty /// input because every caller's grammar guarantees at least one /// condition. @@ -102,6 +94,19 @@ fn and_chain( .expect("control-flow statement must have at least one condition") } +/// Return the only pattern unchanged when there is exactly one, otherwise +/// wrap the list in an `or_pattern`. +fn make_or_pattern( + ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>, + items: Vec, +) -> yeast::Id { + if items.len() == 1 { + items[0] + } else { + tree!((or_pattern pattern: {items})) + } +} + /// Translate a multi-part identifier (for example `Foo.Bar.Baz`) into a /// `member_access_expr` chain rooted at a `name_expr` over the first /// part. Panics on an empty input because the grammar's `_+` quantifier @@ -121,28 +126,19 @@ fn member_chain( ) } +/// Compound-assignment operator spellings (`+=`, `<<=`, ...). Used to tell a +/// compound assignment from an ordinary binary application, both of which +/// arrive as a `binaryOperator`-based `infixOperatorExpr`. +const COMPOUND_ASSIGN_OPS: &[&str] = &[ + "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "|=", "^=", "&+=", "&-=", "&*=", +]; + fn translation_rules() -> Vec> { vec![ // ---- Top-level ---- - // Capture all top-level statements, including unnamed tokens like `nil`. - rule!( - (source_file statement: _* @children) - => - (top_level - body: (block stmt: {children}) - ) - ), - // Declarations may be wrapped in local/global wrapper nodes. - rule!((global_declaration _ @inner) => stmt { inner }), - rule!((local_declaration _ @inner) => stmt { inner }), - // ---- swift-syntax front-end (minimal hook-up) ---- - // These rules target the swift-syntax AST (camelCase kind names), - // produced by the sibling `adapter` module. They coexist with the - // tree-sitter rules (snake_case names): rules are dispatched by exact - // kind name, and the two name spaces never collide, so these are inert - // on the tree-sitter path. Only the minimal top-level mapping lives here - // to demonstrate the pipeline end-to-end; the full translation is added - // separately. Unmatched swift-syntax nodes fall through to the + // These rules translate the swift-syntax AST (camelCase kind names), + // produced by the sibling `adapter` module from the `swift-syntax-parse` + // binary's JSON. Anything unmatched falls through to the // `unsupported_node` fallback at the end. // // `sourceFile` holds its top-level statements in an (elided) @@ -153,199 +149,242 @@ fn translation_rules() -> Vec> { => (top_level body: (block stmt: {items})) ), - rule!((codeBlockItem item: @item) => stmt { item }), + // `codeBlockItem` wraps a top-level statement. It is a simple unwrapper, + // but a single wrapped `variableDecl` can translate to *several* + // declarations (`let x = 1, y = 2`), so the wrapped node is captured with + // `_*` and the result annotated `stmt*` to splice all of them. + rule!((codeBlockItem item: _* @item) => stmt* { item }), // ---- Literals ---- - rule!((integer_literal) => (int_literal)), - rule!((hex_literal) => (int_literal)), - rule!((bin_literal) => (int_literal)), - rule!((oct_literal) => (int_literal)), - rule!((real_literal) => (float_literal)), - rule!((boolean_literal) => (boolean_literal)), - rule!("nil" => (builtin_expr)), - rule!((special_literal) => (builtin_expr)), - rule!((line_string_literal) => (string_literal)), - rule!((multi_line_string_literal) => (string_literal)), - rule!((raw_string_literal) => (string_literal)), - rule!((regex_literal) => (regex_literal)), + // swift-syntax does not distinguish the lexical integer/string forms + // (hex/binary/octal, single- vs multi-line, raw): each is a single + // `*LiteralExpr` kind, so one rule per literal type suffices. + rule!((integerLiteralExpr) => (int_literal)), + rule!((floatLiteralExpr) => (float_literal)), + rule!((booleanLiteralExpr) => (boolean_literal)), + rule!((nilLiteralExpr) => (builtin_expr)), + rule!((stringLiteralExpr) => (string_literal)), + rule!((regexLiteralExpr) => (regex_literal)), // ---- Names ---- - rule!((simple_identifier) @id => (name_expr identifier: (identifier #{id}))), - // A referenceable_operator (e.g. `+` used as a value, as in `reduce(0, +)`) - // is treated as a name reference to the operator symbol. - rule!((referenceable_operator) @op => (name_expr identifier: (identifier #{op}))), + // A function reference spelled with argument labels (`f(x:y:z:)`) is a + // `declReferenceExpr` carrying `argumentNames`. Mark it unsupported for + // now (rather than let the bare-name rule below treat it as a plain + // reference), so downstream QL isn't handed a malformed reference. In + // the future this should become a lambda expression. Matched before the + // bare-name rule. + rule!( + (declReferenceExpr argumentNames: (declNameArguments)) + => + (unsupported_node) + ), + // A bare name reference (`x`), and an operator used as a value (`+` in + // `reduce(0, +)`), are both `declReferenceExpr`; its `baseName` is the + // referenced identifier / operator symbol. + rule!((declReferenceExpr baseName: @name) => (name_expr identifier: (identifier #{name}))), + // A discard `_` used as an expression — e.g. the target of a discarding + // assignment `_ = x`. swift-syntax models it as a `discardAssignmentExpr`; + // the target AST has no expression-level discard (only `ignore_pattern`, + // which is a pattern), so it becomes a `name_expr` over the `_` token. + rule!((discardAssignmentExpr wildcard: @@w) => (name_expr identifier: (identifier #{w}))), // ---- Operators ---- - // All binary operators share the lhs/op/rhs shape. - rule!((additive_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((multiplicative_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((comparison_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((equality_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((conjunction_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((disjunction_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((infix_expression lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - // Range expression `a.. (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - // Open-ended ranges `a...` / `...b` - rule!((open_end_range_expression start: @l) => (unary_expr operator: (postfix_operator "...") operand: {l})), - rule!((open_start_range_expression end: @r) => (unary_expr operator: (prefix_operator "...") operand: {r})), - // Custom operator declaration: `[prefix|infix|postfix] operator OP [: PrecedenceGroup]`. - // The fixity keyword is an anonymous child of `operator_declaration`, so we - // dispatch on it with one rule per keyword. - rule!( - (operator_declaration "prefix" (referenceable_operator _ @op) (simple_identifier)? @prec) - => - (operator_syntax_declaration name: (identifier #{op}) fixity: (fixity "prefix") precedence: {prec}) - ), - rule!( - (operator_declaration "postfix" (referenceable_operator _ @op) (simple_identifier)? @prec) - => - (operator_syntax_declaration name: (identifier #{op}) fixity: (fixity "postfix") precedence: {prec}) - ), - rule!( - (operator_declaration "infix" (referenceable_operator _ @op) (simple_identifier)? @prec) - => - (operator_syntax_declaration - name: (identifier #{op}) - fixity: (fixity "infix") - precedence: {prec}) - ), - rule!((bitwise_operation lhs: @l op: @op rhs: @r) => (binary_expr left: {l} operator: (infix_operator #{op}) right: {r})), - rule!((nil_coalescing_expression value: @l if_nil: @r) => (binary_expr left: {l} operator: (infix_operator "??") right: {r})), - // Leading-dot member shorthand (e.g. `.some`, `.foo`) means member access - // on a contextually inferred type. - rule!((prefix_expression operation: "." target: @member) => (member_access_expr base: (inferred_type_expr) member: (identifier #{member}))), - // Prefix unary operators - rule!((prefix_expression operation: @op target: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})), - // Postfix unary operators - rule!((postfix_expression operation: @op target: @operand) => (unary_expr operator: (postfix_operator #{op}) operand: {operand})), - // TODO: Parenthesised single-value tuple is a grouping expression and should pass through. - // Multi-value tuples become tuple_expr. - rule!((tuple_expression value: _* @v) => (tuple_expr element: {v})), - // Blocks contain statement* directly. - rule!((block statement: _+ @stmts) => (block stmt: {stmts})), - rule!((block) => (block)), - // ---- Variables ---- - // property_binding rules — these produce variable_declaration and/or accessor_declaration - // nodes for individual declarators. The outer property_declaration rule splices these out - // and attaches binding/modifiers from the parent. - - // Computed property with explicit accessors (get/set/modify) → a - // sequence of `accessor_declaration` nodes. The outer rule - // publishes the property's name and type into `ctx` so that each - // inner accessor rule - // (`computed_getter`/`computed_setter`/`computed_modify`) builds - // its `accessor_declaration` with `name` and `type` set from the - // start — no schema-invalid intermediate state. + // The parser front-end folds operator chains into nested + // `infixOperatorExpr`s by precedence (see swift-syntax-rs), so + // `1 + 2 * 3` arrives here already structured. // - // Toggles `ctx.is_chained` per accessor iteration: the first - // accessor inherits the outer rule's chained state (i.e. whether - // this whole property_binding is itself a non-first declarator - // of a containing property_declaration); subsequent accessors - // always emit `chained_declaration`. - rule!( - (property_binding - name: @pattern - type: _? @ty - computed_value: (computed_property accessor: _+ @@accessors)) - => - accessor_declaration* { - ctx.property_name = Some(tree!((identifier #{pattern}))); - ctx.property_type = ty; - - let mut result = Vec::new(); - for (i, acc) in accessors.into_iter().enumerate() { - if i > 0 { - ctx.is_chained = true; - } - result.extend(ctx.translate(acc)?); + // A `binaryOperatorExpr` wraps the operator token; unwrap it to the + // operator leaf. Used by `infixOperatorExpr` (folded) and `sequenceExpr` + // (unresolved). + rule!((binaryOperatorExpr operator: @op) => (infix_operator #{op})), + // Compound assignment (`x += y`) vs. an ordinary binary application + // (`a + b`): both are `binaryOperator`-based `infixOperatorExpr`s, + // distinguishable only by the operator's spelling. The query engine + // can't match on token text, so a small Rust block reads the spelling + // and routes to `compound_assign_expr` or `binary_expr`. The operator + // is captured raw (`@@op`) to read its spelling. + rule!( + (infixOperatorExpr leftOperand: @l operator: (binaryOperatorExpr) @@op rightOperand: @r) + => + expr { + if COMPOUND_ASSIGN_OPS.contains(&ctx.source_text(op).as_str()) { + tree!((compound_assign_expr target: {l} operator: (infix_operator #{op}) value: {r})) + } else { + tree!((binary_expr left: {l} operator: (infix_operator #{op}) right: {r})) } - result } ), - // Computed property: shorthand getter (no explicit get/set, just - // statements) → a single accessor_declaration with kind "get". - // Reads outer modifiers / chained tag from `ctx` (set by the - // outer `property_declaration` rule). - rule!( - (property_binding - name: (pattern bound_identifier: @name) - type: _? @ty - computed_value: (computed_property statement: _* @@body)) + // Plain assignment (`x = y`). In a folded chain the `=` is an + // `assignmentExpr` node (distinct from other operators), matched by kind. + rule!( + (infixOperatorExpr leftOperand: @l operator: (assignmentExpr) rightOperand: @r) + => + (assign_expr target: {l} value: {r}) + ), + // In an unresolved `sequenceExpr` (below) the operator positions are not + // only `binaryOperatorExpr`s: a plain assignment (`=`), an `as`/`is` cast + // and the ternary `?:` can also appear unfolded. Map each to an + // `infix_operator` (keeping its spelling) so the sequence stays a clean + // alternation of operands and operators instead of dropping the operator + // to an opaque `unsupported_node`. These bare nodes only occur inside an + // unresolved sequence — folded forms are handled by the dedicated rules + // above (assignment) and below (`ternaryExpr`). + rule!((assignmentExpr) @op => (infix_operator #{op})), + rule!((unresolvedAsExpr) @op => (infix_operator #{op})), + rule!((unresolvedIsExpr) @op => (infix_operator #{op})), + // The ternary is a three-part operator (`? thenExpr :`) that *wraps* a + // nested expression. Splice it into `?`, the then-expression, `:` so the + // then-expression survives as a real (traversable) operand rather than + // being buried in an opaque token. + rule!( + (unresolvedTernaryExpr questionMark: @@q thenExpression: @then colon: @@c) + => + expr_or_operator* { + vec![tree!((infix_operator #{q})), then, tree!((infix_operator #{c}))] + } + ), + // Escape hatch: an operator chain the front-end could not resolve + // (because it uses an operator of unknown precedence, e.g. imported from + // another module) stays a flat `sequenceExpr`. Preserve it as an + // `unresolved_operator_sequence` whose elements alternate operands and + // infix operators, rather than guessing a structure. + rule!((sequenceExpr elements: _* @els) => (unresolved_operator_sequence element: {els})), + // Prefix unary operators (`!a`, `-x`). + rule!((prefixOperatorExpr operator: @op expression: @operand) => (unary_expr operator: (prefix_operator #{op}) operand: {operand})), + // A `tupleExpr` is a tuple literal (`(a, b)`) or a parenthesised + // expression (`(x)`). For now it is kept as an opaque `tuple_expr` leaf + // (its source text); its elements are not descended into. + // + // TODO: a parenthesised single-element `tupleExpr` is really a grouping + // expression and should be elided (unwrapped to its inner expression) + // rather than modelled as a tuple. + rule!((tupleExpr) => (tuple_expr)), + // A code block contains its statements directly. + rule!((codeBlock statements: _* @stmts) => (block stmt: {stmts})), + // ---- Properties with accessors ---- + // A computed property with an implicit getter (`var a: T { }`) + // becomes a single `accessor_declaration` of kind `get`. This form is + // self-contained (no context threading). It must precede the plain + // `variableDecl` rules, which would otherwise match and drop the accessor + // block. + rule!( + (variableDecl + bindingSpecifier: @@spec + bindings: (patternBinding + pattern: (identifierPattern identifier: @@name) + typeAnnotation: (typeAnnotation type: @ty) + accessorBlock: (accessorBlock accessors: (codeBlockItem)+ @body))) => (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} + modifier: (modifier #{spec}) name: (identifier #{name}) type: {ty} accessor_kind: (accessor_kind "get") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Stored property with willSet/didSet observers (initializer - // optional) → a `variable_declaration` followed by one - // `accessor_declaration` per observer, each born with the - // property name set. Manual rule: we publish the property name - // into `ctx` before translating the observer children so the - // inner `willset_clause` / `didset_clause` rules construct - // valid `accessor_declaration` nodes from the start. + body: (block stmt: {body})) + ), + // A property with an explicit accessor block. swift-syntax makes both + // shapes plain `accessorDecl`s, so they are told apart by the presence + // of an initializer: // - // The `variable_declaration` itself inherits the outer rule's - // chained state; observers always get `chained_declaration` - // because they're subsequent outputs of this flattening rule. - rule!( - (property_binding - name: (pattern bound_identifier: @name) - type: _? @ty - value: _? @@val - observers: (willset_didset_block willset: _? @@ws didset: _? @@ds)) + // * With an initializer (`var x: T = e { willSet {…} didSet {…} }`) it is + // a *stored* property with observers: emit the backing + // `variable_declaration` first, then one `accessor_declaration` per + // observer (observers carry no type). + // * Without an initializer (`var v: T { get set }`, incl. protocol + // requirements) it is a *computed* property: no backing variable; the + // type is published so the get/set accessors carry it. + // + // In both cases the first emitted declaration is unchained and every + // subsequent one is tagged `chained_declaration` (the `!result.is_empty()` + // test). Must precede the plain `variableDecl` rules. + rule!( + (variableDecl + bindingSpecifier: @@spec + bindings: (patternBinding + pattern: (identifierPattern identifier: @@name) + typeAnnotation: (typeAnnotation type: @ty) + initializer: (initializerClause value: @@val)? + accessorBlock: (accessorBlock accessors: (accessorDecl)+ @@accessors))) => member* { - // The initializer value must not inherit the binding - // context (it may contain patterns, e.g. a switch - // expression), so translate it inside a `ctx.scoped` - // block — the block receives a temporary `ctx` whose - // `user_ctx` is a clone; mutations to it are discarded - // when the block returns, so the outer `ctx` is intact - // for the observer loop below. The observers keep the - // outer context: each willSet/didSet accessor emits - // the binding modifier and, in turn, resets the - // context for its own body. - let val = ctx.scoped(|ctx| { - ctx.reset(); - ctx.translate(val) - })?; - - let var_decl = tree!( - (variable_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty} - value: {val}) - ); - - // Publish the property name for the observer rules. + ctx.outer_modifiers = vec![tree!((modifier #{spec}))]; ctx.property_name = Some(tree!((identifier #{name}))); - // Observers are subsequent outputs of this flattening - // rule, so they always get `chained_declaration`. - ctx.is_chained = true; - - let mut result = vec![var_decl]; - for obs in ws.into_iter().chain(ds) { - result.extend(ctx.translate(obs)?); + let mut result = Vec::new(); + if let Some(val) = val { + // Stored property with observers: the initializer is not part + // of the binding, so translate it in a reset scope. + let val = ctx.scoped(|ctx| { + ctx.reset(); + ctx.translate(val) + })?; + result.push(tree!( + (variable_declaration + modifier: {ctx.outer_modifiers.clone()} + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty} + value: {val}) + )); + } else { + // Computed property: the accessors carry the type. + ctx.property_type = Some(ty); + } + for acc in accessors.into_iter() { + ctx.is_chained = !result.is_empty(); + result.extend(ctx.translate(acc)?); } result } ), - // property_binding with any pattern name (identifier or - // destructuring). Reads outer modifiers / chained tag from `ctx`. - // - // The enclosing `property_declaration` leads `ctx.outer_modifiers` - // with the `let`/`var` binding modifier, so the auto-translated name - // pattern (the LHS) becomes a binding, while the initializer value is - // translated with a reset context (see `SwiftContext::reset`). - rule!( - (property_binding - name: @pattern - type: _? @ty - value: _? @@val) + // Each `accessorDecl` becomes an `accessor_declaration`, reading the + // property name/type and the binding/chained modifiers from `ctx`. The + // accessor kind comes straight from the specifier keyword + // (`get`/`set`/`willSet`/`didSet`). The body is optional: a body-bearing + // accessor (a computed getter/setter, or a `willSet`/`didSet` observer) + // carries the binding modifier and a translated body, whereas a bodyless + // one (a protocol requirement) carries neither. The property context is + // read out *before* translating the body, which resets `ctx` so the + // accessor's context does not leak into the body subtree. + rule!( + (accessorDecl accessorSpecifier: @@spec body: _? @@body) + => + accessor_declaration { + let binding = if body.is_some() { + ctx.outer_modifiers.clone() + } else { + Vec::new() + }; + let chained = chained_modifier(&mut ctx); + let name = ctx + .property_name + .ok_or("accessor outside property context")?; + let ty = ctx.property_type; + let body = match body { + Some(block) => { + ctx.reset(); + ctx.translate(block)?.into_iter().next() + } + None => None, + }; + tree!( + (accessor_declaration + modifier: {binding} + modifier: {chained} + name: {name} + type: {ty} + accessor_kind: (accessor_kind #{spec}) + body: {body}) + ) + } + ), + // ---- Variables ---- + // The individual bindings of a `variableDecl`. The binding modifier and + // chained tag come from `ctx` (set by the `variableDecl` rule below). The + // type annotation and initializer are both optional (one combined rule + // covers `let x`, `let x = e`, `let x: T`, and `let x: T = e`); the + // initializer value is translated in a reset scope so it is not treated + // as a binding. + rule!( + (patternBinding + pattern: @pattern + typeAnnotation: (typeAnnotation type: @ty)? + initializer: (initializerClause value: @@val)?) => (variable_declaration modifier: {ctx.outer_modifiers.clone()} @@ -354,60 +393,49 @@ fn translation_rules() -> Vec> { type: {ty} value: {ctx.reset(); ctx.translate(val)?}) ), - // property_declaration: flatten declarators (each may translate - // to multiple nodes — variable_declaration and/or - // accessor_declaration) and attach the binding modifier - // (let/var), outer modifiers, and `chained_declaration` for - // non-first declarations. Manual rule: publishes - // binding/outer modifiers into `ctx` and translates each - // declarator with `ctx.is_chained` toggled per iteration. The - // inner declaration rules (`property_binding` variants, - // accessor inner rules) read these fields and emit complete - // `modifier:` lists from the start. - rule!( - (property_declaration - binding: (value_binding_pattern mutability: @@binding_kind) - declarator: _* @@decls - (modifiers)* @mods) - => - member* { - let binding_text = ctx.ast.source_text(binding_kind); - let binding = ctx.literal("modifier", &binding_text); - // The `let`/`var` binding modifier leads the declaration's - // modifier list and doubles as the "this is a binding" signal - // for pattern translation (see `in_binding_pattern`). - ctx.outer_modifiers = std::iter::once(binding).chain(mods).collect(); - + // A `let`/`var` declaration binds one or more comma-separated patterns + // (`let x = 1, y = 2`). The `bindingSpecifier` (`let`/`var`) is published + // as the binding modifier, followed by any attributes and modifiers + // (`@objc`, `public`, `static`, …); each `patternBinding` becomes its own + // `variable_declaration`, with non-first ones tagged `chained_declaration`. + // Accessor/observer forms are handled by the earlier rules. + rule!( + (variableDecl + attributes: _* @attrs + modifiers: _* @mods + bindingSpecifier: @@spec + bindings: _* @@bindings) + => + stmt* { + let binding = tree!((modifier #{spec})); + // The binding (`let`/`var`) leads, then attributes then modifiers + // in source order (Swift writes attributes before modifiers). + ctx.outer_modifiers = std::iter::once(binding).chain(attrs).chain(mods).collect(); let mut result = Vec::new(); - for (i, decl) in decls.into_iter().enumerate() { + for (i, b) in bindings.into_iter().enumerate() { ctx.is_chained = i > 0; - result.extend(ctx.translate(decl)?); + result.extend(ctx.translate(b)?); } result } ), // ---- Enums ---- - // enum_type_parameter → parameter (with optional name as pattern). + // An enum-case payload parameter (`radius: Double`, or just `Double`). + // The label (`firstName`) is optional. rule!( - (enum_type_parameter name: @name type: @ty) + (enumCaseParameter firstName: _? @@name type: @ty) => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) + (parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty}) ), + // An enum element with associated values (`case circle(radius: Double)`) + // becomes a nested `class_like_declaration` whose constructor carries the + // payload parameters; an element with a raw value (`case a = 1`) or a + // plain element (`case north`) becomes a `variable_declaration`. All + // carry the shared case modifiers / chained tag from `ctx` (set by the + // `enumCaseDecl` rule below) and are tagged `enum_case`, after any + // `chained_declaration` tag. rule!( - (enum_type_parameter type: @ty) - => - (parameter type: {ty}) - ), - // enum_case_entry with associated values → class_like_declaration - // containing a constructor whose parameters are the data - // parameters. Reads outer modifiers / chained tag from `ctx` - // (set by the outer `enum_entry` rule). - rule!( - (enum_case_entry - name: @name - data_contents: (enum_type_parameters parameter: _* @params)) + (enumCaseElement name: @name parameterClause: (enumCaseParameterClause parameters: _* @params)) => (class_like_declaration modifier: {ctx.outer_modifiers.clone()} @@ -416,9 +444,8 @@ fn translation_rules() -> Vec> { name: (identifier #{name}) member: (constructor_declaration parameter: {params} body: (block))) ), - // enum_case_entry with explicit raw value → variable_declaration with that value. rule!( - (enum_case_entry name: @name raw_value: @val) + (enumCaseElement name: @name rawValue: (initializerClause value: @val)) => (variable_declaration modifier: {ctx.outer_modifiers.clone()} @@ -427,9 +454,8 @@ fn translation_rules() -> Vec> { pattern: (name_pattern identifier: (identifier #{name})) value: {val}) ), - // enum_case_entry without associated values → variable_declaration tagged enum_case. rule!( - (enum_case_entry name: @name) + (enumCaseElement name: @name) => (variable_declaration modifier: {ctx.outer_modifiers.clone()} @@ -437,12 +463,14 @@ fn translation_rules() -> Vec> { modifier: (modifier "enum_case") pattern: (name_pattern identifier: (identifier #{name}))) ), - // enum_entry: flatten case entries; publish outer modifiers - // into `ctx` and translate each case with `ctx.is_chained` - // toggled per iteration so the inner `enum_case_entry` rules - // emit complete `modifier:` lists from the start. + // Enum cases. A single `case` declaration may carry modifiers + // (e.g. `indirect`) and list several comma-separated elements; each + // becomes its own declaration carrying those shared modifiers, and + // non-first ones are tagged `chained_declaration`. The modifiers are + // published into `ctx` + // for the element rules above, which build the actual declaration. rule!( - (enum_entry case: _+ @@cases (modifiers)* @mods) + (enumCaseDecl modifiers: _* @mods elements: _* @@cases) => member* { ctx.outer_modifiers = mods; @@ -455,198 +483,220 @@ fn translation_rules() -> Vec> { result } ), - // Plain assignment: `x = expr` + // `identifierPattern` wraps a single identifier token. rule!( - (assignment operator: "=" target: (directly_assignable_expression expr: @target) result: @value) - => - (assign_expr target: {target} value: {value}) - ), - // Compound assignment: `x += expr` etc. - rule!( - (assignment operator: @op target: (directly_assignable_expression expr: @target) result: @value) - => - (compound_assign_expr target: {target} operator: (infix_operator #{op}) value: {value}) - ), - // Unwrap `type` wrapper node - rule!((type name: @inner) => type_expr { inner }), - // `directly_assignable_expression` is just a wrapper; unwrap it - rule!((directly_assignable_expression expr: @inner) => expr { inner }), - // Pattern with bound_identifier → name_pattern. - rule!( - (pattern bound_identifier: @name) + (identifierPattern identifier: @name) => (name_pattern identifier: (identifier #{name})) ), - // Pattern with 'let' or 'var' binding: publish the binding modifier - // into `ctx` and translate the inner pattern under it. - rule!( - (pattern kind: (binding_pattern binding: (value_binding_pattern mutability: @@binding_kind) pattern: @@pattern)) - => - pattern* { - let binding_text = ctx.ast.source_text(binding_kind); - let binding = ctx.literal("modifier", &binding_text); - ctx.outer_modifiers = vec![binding]; - ctx.translate(pattern)? + // A `let`/`var` value-binding pattern (`let x`) inside a case or `if case` + // introduces a new binding; it unwraps to its inner pattern (a + // `name_pattern`). + rule!((valueBindingPattern pattern: @p) => pattern { p }), + // An enum-case pattern with associated values (`case .foo(let x)`, + // `case Color.foo(let x)`) is an expression pattern wrapping a call of a + // member access. It becomes a `constructor_pattern`; its arguments are + // translated as pattern elements (see the `labeledExpr` rules, gated by + // `ctx.in_pattern`). Matched before the generic `expressionPattern` rule. + // The base is optional: a leading-dot form (`.foo`) has none, so the + // constructor's base is an `inferred_type_expr`. + rule!( + (expressionPattern expression: (functionCallExpr + calledExpression: (memberAccessExpr base: _? @base period: @dot declName: (declReferenceExpr baseName: @name)) + arguments: _* @@args)) + => + constructor_pattern { + ctx.in_pattern = true; + let elements = ctx.translate(args)?; + let base = base.unwrap_or_else(|| tree!((inferred_type_expr #{dot}))); + tree!((constructor_pattern + constructor: (member_access_expr + base: {base} + member: (identifier #{name})) + element: {elements})) } ), - // case T.foo(x,y) pattern - rule!( - (pattern kind: (case_pattern type: @typ name: @name arguments: (tuple_pattern item: (tuple_pattern_item)* @items)? )) - => - (constructor_pattern - constructor: (member_access_expr base: {typ} member: (identifier #{name})) - element: {items}) - ), - // case .foo(x,y) pattern - rule!( - (pattern kind: (case_pattern dot: @dot name: @name arguments: (tuple_pattern item: (tuple_pattern_item)* @items)? )) - => - (constructor_pattern - constructor: (member_access_expr base: (inferred_type_expr #{dot}) member: (identifier #{name})) - element: {items}) - ), - // Tuple pattern and its (optionally named) items - rule!((pattern kind: (tuple_pattern item: _* @elems)) => (tuple_pattern element: {elems})), - rule!((tuple_pattern_item name: @key pattern: @pat) => (pattern_element key: (identifier #{key}) pattern: {pat})), - rule!((tuple_pattern_item pattern: @pat) => (pattern_element pattern: {pat})), - // Type casting pattern (TODO) - rule!((pattern kind: (type_casting_pattern)) => (unsupported_node)), - // Wildcard pattern - rule!((pattern kind: (wildcard_pattern)) => (ignore_pattern)), - // A bare identifier used as an expression-pattern. Under a `var`/`let` - // binding it introduces a new variable and becomes a `name_pattern`; - // otherwise it matches by equality and is left as an `expr_equality_pattern` - // over the name expression. - rule!( - (pattern kind: (simple_identifier) @name) - => - pattern { - if ctx.in_binding_pattern() { - tree!((name_pattern identifier: (identifier #{name}))) - } else { - let expr = tree!((name_expr identifier: (identifier #{name}))); - tree!((expr_equality_pattern expr: {expr})) - } + // A tuple destructuring pattern (`let (a, b) = …`). A labelled element + // (`let (x: a) = …`) carries its label through as the `pattern_element` + // key; unlabelled elements have no key. + rule!((tuplePattern elements: _* @els) => (tuple_pattern element: {els})), + rule!( + (tuplePatternElement label: _? @@label pattern: @p) + => + (pattern_element key: (identifier #{label})? pattern: {p}) + ), + // A type-casting pattern (`case is T`). Not yet supported, so it is + // mapped to `unsupported_node` — an explicit reminder that this needs + // handling in the future. (Redundant with the catch-all fallback, but + // kept as a signpost.) + rule!((isTypePattern) => (unsupported_node)), + // A standalone wildcard pattern (`case _:`, `if case _`): swift-syntax + // models the bare `_` as an `expressionPattern` wrapping a + // `discardAssignmentExpr`. Matched before the generic `expressionPattern` + // rule so `_` becomes an `ignore_pattern` rather than an equality match. + // (Wildcards *inside* an enum-case argument list are handled by the + // `labeledExpr`/`discardAssignmentExpr` rules.) + rule!((expressionPattern expression: (discardAssignmentExpr)) => (ignore_pattern)), + // A wildcard *binding* pattern (`let _ = x`, `for _ in xs`). swift-syntax + // models this as a `wildcardPattern` — distinct from the `_` *match* + // pattern above, which is an `expressionPattern` over a + // `discardAssignmentExpr`. + rule!((wildcardPattern) => (ignore_pattern)), + // A tuple pattern in a match position (`case (let a, 3):`) is parsed by + // swift-syntax as an `expressionPattern` wrapping a `tupleExpr` — unlike a + // binding tuple (`let (a, b)`), which is a real `tuplePattern`. Recognise + // it as a `tuple_pattern`; its `labeledExpr` elements translate to + // `pattern_element`s under `ctx.in_pattern` (a binding element becomes a + // `name_pattern`, any other expression an `expr_equality_pattern`). + rule!( + (expressionPattern expression: (tupleExpr elements: _* @@els)) + => + tuple_pattern { + ctx.in_pattern = true; + let elements = ctx.translate(els)?; + tree!((tuple_pattern element: {elements})) } ), - // Expression pattern - // We lack a way to check if 'expr' is actually an expression, but due to rule ordering - // the 'expression' case is the only remaining possibility when this rule tries to match. - rule!((pattern kind: @expr) => (expr_equality_pattern expr: {expr})), + // A bare expression pattern (`case 1:`, `case someConstant:`) matches by + // equality. + rule!((expressionPattern expression: @e) => (expr_equality_pattern expr: {e})), // ---- Functions ---- - // Function declaration - // Function declaration (return type optional, body statements optional). + // A function declaration (parameters/return type/body optional). The + // parameters and return type nest under `signature`; the body is a + // `codeBlock`. A bodyless function (a protocol requirement) still emits + // an empty `block`. rule!( - (function_declaration + (functionDecl name: @name - parameter: _* @params - return_type: _? @ret - body: (block statement: _* @body_stmts)) + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params) + returnClause: (returnClause type: @ret)?) + body: (codeBlock statements: _* @body)) => (function_declaration name: (identifier #{name}) parameter: {params} return_type: {ret} - body: (block stmt: {body_stmts})) + body: (block stmt: {body})) ), - // Parameters are wrapped in function_parameter, which also carries - // optional default values. Publishes the default value into `ctx` - // before translating the inner `parameter` so the `parameter` - // rules can include it as a `default:` field directly. rule!( - (function_parameter parameter: @@p default_value: _? @def) + (functionDecl + name: @name + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params) + returnClause: (returnClause type: @ret)?)) => - parameter* { - ctx.default_value = def; - ctx.translate(p)? + (function_declaration + name: (identifier #{name}) + parameter: {params} + return_type: {ret} + body: (block)) + ), + // A function parameter. With two names (`firstName`+`secondName`) the + // first is the external argument label and the second the internal name; + // with one name it is just the internal name. The declared type is + // emitted; the default value is optional. + rule!( + (functionParameter + firstName: @@first + secondName: _? @@second + type: @ty + defaultValue: (initializerClause value: @val)?) + => + parameter { + let (external, name) = match second { + Some(second) => (Some(tree!((identifier #{first}))), second), + None => (None, first), + }; + tree!((parameter + external_name: {external} + pattern: (name_pattern identifier: (identifier #{name})) + type: {ty} + default: {val})) } ), - // Parameter with external name and type - rule!( - (parameter external_name: @ext name: @name) - => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name})) - default: {ctx.default_value}) - ), - rule!( - (parameter external_name: @ext name: @name type: @ty) - => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty} - default: {ctx.default_value}) - ), - // Parameter with just name and type (no external name) + // A function/method call (`foo(1, 2)`). `calledExpression` is the callee + // and `arguments` is an (elided) list of `labeledExpr`, each translated + // to an `argument` below. A trailing closure (`xs.map { … }`) becomes a + // final unlabelled argument; that variant is matched first. rule!( - (parameter name: @name) + (functionCallExpr calledExpression: @callee arguments: _* @args trailingClosure: @tc) => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - default: {ctx.default_value}) + (call_expr callee: {callee} argument: {args} argument: (argument value: {tc})) ), rule!( - (parameter name: @name type: @ty) + (functionCallExpr calledExpression: @callee arguments: _* @args) => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty} - default: {ctx.default_value}) + (call_expr callee: {callee} argument: {args}) ), - // Reference to a function, f(x:y:z:). This is parsed as a call with a single argument with multiple reference_specifier labels. - // We don't want downstream QL to try to handle this as a call_expr with a weird argument, so explicitly mark it as unsupported for now. - // In the future we probably want to translate this to a lambda expression. + // A call argument or an enum-case pattern argument. When translating an + // enum-case `constructor_pattern`'s arguments (`ctx.in_pattern`), a + // `patternExpr` argument (`let x`) becomes a bound `name_pattern`, a + // wildcard (`_`) becomes an `ignore_pattern`, and any other expression + // becomes an `expr_equality_pattern`; each is wrapped in a + // `pattern_element` carrying the optional argument label as its `key`. + // Otherwise the argument keeps its label as the `name` and its value. + // The pattern-only shapes (`patternExpr`, `discardAssignmentExpr`) are + // matched first; they never occur as ordinary call arguments. rule!( - (call_expression suffix: (call_suffix arguments: (value_arguments argument: (value_argument reference_specifier: _+) @ref_arg))) + (labeledExpr label: _? @@lbl expression: (patternExpr pattern: @p)) => - (unsupported_node) + (pattern_element key: (identifier #{lbl})? pattern: {p}) ), - // Call expression: function(args...) rule!( - (call_expression function: @func suffix: (call_suffix arguments: (value_arguments argument: (value_argument)* @args))) + (labeledExpr label: _? @@lbl expression: (discardAssignmentExpr) @@wildcard) => - (call_expr callee: {func} argument: {args}) + (pattern_element key: (identifier #{lbl})? pattern: (ignore_pattern #{wildcard})) ), - // Value argument with label (value: _ matches both named nodes and anonymous tokens like nil) rule!( - (value_argument name: (value_argument_label name: @label) value: @val) + (labeledExpr label: _? @@lbl expression: @val) => - (argument name: (identifier #{label}) value: {val}) + argument { + if ctx.in_pattern { + tree!((pattern_element + key: (identifier #{lbl})? + pattern: (expr_equality_pattern expr: {val}))) + } else { + tree!((argument name: (identifier #{lbl})? value: {val})) + } + } ), - // Value argument without label + // Member access (`list.append`). The `declName` is itself a + // `declReferenceExpr`; pull its `baseName` out as the member identifier. + // A leading-dot access (`.foo`) has no explicit base — the base is an + // `inferred_type_expr`. The base-ful form is matched first. rule!( - (value_argument value: @val) + (memberAccessExpr base: @base declName: (declReferenceExpr baseName: @member)) => - (argument value: {val}) + (member_access_expr base: {base} member: (identifier #{member})) ), - // Navigation expression → member_access_expr rule!( - (navigation_expression target: @target suffix: (navigation_suffix suffix: @member)) + (memberAccessExpr declName: (declReferenceExpr baseName: @member)) => - (member_access_expr base: {target} member: (identifier #{member})) + (member_access_expr base: (inferred_type_expr) member: (identifier #{member})) ), - // Return / break / continue, one rule per keyword. - // The anonymous "return"/"break"/"continue" keywords are matched as - // string literals. - rule!((control_transfer_statement kind: "return" result: _? @val) => (return_expr value: {val})), - rule!((control_transfer_statement kind: "break" result: @lbl) => (break_expr label: (identifier #{lbl}))), - rule!((control_transfer_statement kind: "break") => (break_expr)), - rule!((control_transfer_statement kind: "continue" result: @lbl) => (continue_expr label: (identifier #{lbl}))), - rule!((control_transfer_statement kind: "continue") => (continue_expr)), - rule!((control_transfer_statement kind: (throw_keyword) result: @val) => (throw_expr value: {val})), + // Control transfer, one rule per keyword. `return` carries an optional + // value; `break` / `continue` an optional target label; `throw` its + // thrown expression. + rule!((returnStmt expression: _? @val) => (return_expr value: {val})), + rule!((breakStmt label: _? @@lbl) => (break_expr label: (identifier #{lbl})?)), + rule!((continueStmt label: _? @@lbl) => (continue_expr label: (identifier #{lbl})?)), + rule!((throwStmt expression: @val) => (throw_expr value: {val})), // ---- Closures ---- - // Lambda literal with optional type header (parameters + optional return type). - // The return_type capture is optional, so this rule covers both cases. - rule!( - (lambda_literal - attribute: _* @attrs - captures: (capture_list item: _* @captures)? - type: (lambda_function_type - params: (lambda_function_type_parameters parameter: _* @params) - return_type: _? @ret)? - statement: _* @body) + // A closure (`{ (x: Int) -> Int in … }`) becomes a `function_expr`. The + // whole signature is optional, as are its capture list, parameter + // clause, and return clause, so one rule covers everything from a bare + // `{ … }` to `{ [weak self] (x) -> T in … }`. Shorthand `$0` closures + // have no signature and their `$0` references are ordinary name + // expressions. + rule!( + (closureExpr + signature: (closureSignature + attributes: _* @attrs + capture: (closureCaptureClause items: _* @captures)? + parameterClause: _* @params + returnClause: (returnClause type: @ret)?)? + statements: _* @body) => (function_expr modifier: {attrs} @@ -655,114 +705,103 @@ fn translation_rules() -> Vec> { return_type: {ret} body: (block stmt: {body})) ), - // capture_list_item with ownership modifier (e.g. [weak self], [unowned x]) + // A closure capture (`[weak self]`, `[x]`, `[y = expr]`). The optional + // ownership specifier (`weak`/`unowned`) becomes a modifier; the + // captured name becomes the bound `name_pattern`; an explicit capture + // initializer (`[y = expr]`) becomes the bound value. rule!( - (capture_list_item ownership: _? @ownership name: @name value: _? @val) + (closureCapture + specifier: (closureCaptureSpecifier specifier: @@spec)? + name: @@name + initializer: (initializerClause value: @val)?) => (variable_declaration - modifier: {ownership} + modifier: (modifier #{spec})? pattern: (name_pattern identifier: (identifier #{name})) value: {val}) ), - // Lambda parameter with type and optional external name - rule!( - (lambda_parameter external_name: @ext name: @name type: @ty) - => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) - ), - rule!( - (lambda_parameter name: @name type: @ty) - => - (parameter - pattern: (name_pattern identifier: (identifier #{name})) - type: {ty}) - ), + // A closure parameter clause (`(x: Int, y)`) unwraps to its parameters. + rule!((closureParameterClause parameters: _* @params) => parameter* { params }), + // A closure parameter (`x: Int`, or just `x`). Unlike a function + // parameter it has no external label; the type is optional. rule!( - (lambda_parameter external_name: @ext name: @name) + (closureParameter firstName: @name type: _? @ty) => - (parameter - external_name: (identifier #{ext}) - pattern: (name_pattern identifier: (identifier #{name}))) + (parameter pattern: (name_pattern identifier: (identifier #{name})) type: {ty}) ), + // A shorthand closure parameter (`x` in `{ x, y in … }`): a bare name + // with no parentheses and no type. rule!( - (lambda_parameter name: @name) + (closureShorthandParameter name: @name) => (parameter pattern: (name_pattern identifier: (identifier #{name}))) ), - // Call expression with trailing closure (no value_arguments) - rule!( - (call_expression function: @func suffix: (call_suffix lambda: (lambda_literal) @closure)) - => - (call_expr - callee: {func} - argument: (argument value: {closure})) - ), // ---- Control flow ---- - // If statement + // An `if`/`else` expression. Conditions are joined via `and_chain`; the + // then-body and optional else-body (another block, or an `ifExpr` for an + // else-if chain) are translated recursively. rule!( - (if_statement condition: _* @cond body: @then_body else_branch: _? @else_stmts) + (ifExpr conditions: _* @cond body: @then_body elseBody: _? @else_stmts) => (if_expr condition: {and_chain(&mut ctx, cond)} then: {then_body} else: {else_stmts}) ), - // Guard statement + // A `guard … else { }` statement. The `body` is the else block. rule!( - (guard_statement condition: _* @cond body: (block statement: _* @else_stmts)) + (guardStmt conditions: _* @cond body: @else_stmts) => (guard_if_stmt condition: {and_chain(&mut ctx, cond)} - else: (block stmt: {else_stmts})) + else: {else_stmts}) ), - // Ternary expression → if_expr + // Ternary (`c ? a : b`) desugars to an `if_expr`. rule!( - (ternary_expression condition: @cond if_true: @then_val if_false: @else_val) + (ternaryExpr condition: @cond thenExpression: @then_val elseExpression: @else_val) => (if_expr condition: {cond} then: {then_val} else: {else_val}) ), - // Switch statement + // A `switch` statement. Each `switchCase` becomes a `switch_case` with a + // pattern (or an `or_pattern` for comma-separated `case a, b:`) and a + // body; a `default:` case has a body but no pattern. The case items and + // body are auto-translated; the Rust block only picks the pattern shape + // by arity (the query engine can't branch on list length). rule!( - (switch_statement expr: @val entry: (switch_entry)* @cases) + (switchExpr subject: @val cases: _* @cases) => (switch_expr value: {val} case: {cases}) ), - // Switch entry with multiple patterns and body rule!( - (switch_entry - pattern: (switch_pattern pattern: @first) - pattern: (switch_pattern pattern: @rest)+ - statement: _* @body) + (switchCase label: (switchCaseLabel caseItems: _* @items) statements: _* @body) => - (switch_case pattern: (or_pattern pattern: {first} pattern: {rest}) body: (block stmt: {body})) - ), - // Switch entry with exactly one pattern and body - rule!( - (switch_entry pattern: (switch_pattern pattern: @pat) statement: _* @body) - => - (switch_case pattern: {pat} body: (block stmt: {body})) + (switch_case + pattern: {make_or_pattern(&mut ctx, items)} + body: (block stmt: {body})) ), - // Switch entry: default case (no patterns) rule!( - (switch_entry default: (default_keyword) statement: _* @body) + (switchCase label: (switchDefaultLabel) statements: _* @body) => (switch_case body: (block stmt: {body})) ), - // if case PATTERN = expr — preserve the pattern directly (no Optional wrapping) + // A single case item unwraps to its pattern, possibly boxed in conditional_pattern + rule!((switchCaseItem pattern: @p whereClause: (whereClause condition: @cond)) => (conditional_pattern pattern: { p } condition: {cond})), + rule!((switchCaseItem pattern: @p) => pattern { p }), + // A pattern-matching condition (`if case let x = e`, `if case .foo(let x) + // = e`) becomes a `pattern_guard_expr`: the matched pattern and the + // scrutinee value are translated recursively. rule!( - (if_let_binding "case" pattern: @pat value: @val) + (matchingPatternCondition pattern: @pat initializer: (initializerClause value: @val)) => - (pattern_guard_expr - value: {val} - pattern: {pat}) + (pattern_guard_expr pattern: {pat} value: {val}) ), + // Optional binding (`if let x = foo`, or shorthand `if let x`) desugars + // to a `pattern_guard_expr` matching `Optional.some(x)`. The initialized + // form is matched first. rule!( - (if_let_binding - pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name) - value: @val) + (optionalBindingCondition + pattern: (identifierPattern identifier: @name) + initializer: (initializerClause value: @val)) => (pattern_guard_expr value: {val} @@ -770,10 +809,8 @@ fn translation_rules() -> Vec> { constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some")) element: (pattern_element pattern: (name_pattern identifier: (identifier #{name}))))) ), - // Shorthand if let x (Swift 5.7+) — also semantically .some(x) rule!( - (if_let_binding - pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name)) + (optionalBindingCondition pattern: (identifierPattern identifier: @name)) => (pattern_guard_expr value: (name_expr identifier: (identifier #{name})) @@ -781,281 +818,347 @@ fn translation_rules() -> Vec> { constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some")) element: (pattern_element pattern: (name_pattern identifier: (identifier #{name}))))) ), - // If-condition — unwrap (pass through the inner expression/pattern) - rule!((if_condition kind: @inner) => expr_or_pattern { inner }), + // A single condition in an `if`/`while`/`guard` condition list unwraps to + // its inner expression; `and_chain` joins multiple with `&&`. + rule!((conditionElement condition: @c) => expr { c }), + // `if`/`switch`/`do` are expressions in Swift; when used as a statement + // swift-syntax wraps them in an `expressionStmt`. Unwrap to the inner + // expression (a plain expression statement, e.g. a call, is not wrapped). + rule!((expressionStmt expression: @e) => expr { e }), // ---- Loops ---- - // For-in loop with optional where-clause guard. + // A `for`-`in` loop. The optional `where` clause becomes the `guard`. rule!( - (for_statement - item: @pat - collection: @iter - where: (where_clause expr: @guard)? - body: (block statement: _* @body)) + (forStmt + pattern: @pat + sequence: @iter + whereClause: (whereClause condition: @guard)? + body: @body) => (for_each_stmt pattern: {pat} iterable: {iter} guard: {guard} - body: (block stmt: {body})) + body: {body}) ), - // While loop + // A `while` loop. rule!( - (while_statement condition: _* @cond body: (block statement: _* @body)) + (whileStmt conditions: _* @cond body: @body) => (while_stmt condition: {and_chain(&mut ctx, cond)} - body: (block stmt: {body})) + body: {body}) ), - // Repeat-while loop + // A `repeat { } while c` loop desugars to a `do_while_stmt`. rule!( - (repeat_while_statement condition: _* @cond body: (block statement: _* @body)) + (repeatStmt body: @body condition: @cond) => - (do_while_stmt - condition: {and_chain(&mut ctx, cond)} - body: (block stmt: {body})) + (do_while_stmt condition: {cond} body: {body}) + ), + // A labeled statement (`outer: for … { }`). swift-syntax stores the + // label and colon as separate tokens, so the label token is already the + // bare name (no trailing `:` to strip). + rule!( + (labeledStmt label: @@lbl statement: @stmt) + => + (labeled_stmt label: (identifier #{lbl}) stmt: {stmt}) ), - // Labeled statement (e.g. `outer: for ...`). Strip the trailing ':' from the label token. - rule!((labeled_statement label: (statement_label) @lbl statement: @stmt) => labeled_stmt { - let text = ctx.ast.source_text(lbl); - let name = &text[..text.len() - 1]; - tree!((labeled_stmt label: (identifier #{name}) stmt: {stmt})) - }), // ---- Collections ---- - // Array literal - rule!((array_literal element: _* @elems) => (array_literal element: {elems})), - // Empty array literal - rule!((array_literal) => (array_literal)), - // Dictionary literal — zip keys and values into key_value_pairs + // An array literal (`[1, 2, 3]`). Each `arrayElement` unwraps to its + // contained expression. + rule!( + (arrayExpr elements: _* @els) + => + (array_literal element: {els}) + ), + rule!((arrayElement expression: @e) => expr { e }), + // A dictionary literal (`["a": 1]`) is kept as an opaque `map_literal` + // leaf (its source span). + rule!((dictionaryExpr) => (map_literal)), + // A subscript access (`xs[0]`) is modelled as a call. swift-syntax does + // report a distinct `subscriptCallExpr`, so giving + // subscripts their own shape needs only a `subscript_expr` node in + // ast_types.yml and a remap here. rule!( - (dictionary_literal key: _* @keys value: _* @vals) + (subscriptCallExpr calledExpression: @callee arguments: _* @args) => - (map_literal element: {keys.into_iter().zip(vals).map(|(k, v)| - tree!((key_value_pair key: {k} value: {v})) - )}) + (call_expr callee: {callee} argument: {args}) ), - rule!((dictionary_literal element: _* @elems) => (map_literal element: {elems})), - rule!((dictionary_literal_item key: @k value: @v) => (key_value_pair key: {k} value: {v})), // ---- Optionals and errors ---- // Optional chaining — unwrap the marker - rule!((optional_chain_marker expr: @inner) => expr { inner }), + rule!((optionalChainingExpr expression: @inner) => expr { inner }), // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!" - rule!((try_expression (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), - rule!((try_expression operator: (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), + rule!( + (tryExpr questionOrExclamationMark: _? @@m expression: @e) + => + expr { + let op = format!("try{}", m.map(|m| ctx.source_text(m)).unwrap_or_default()); + tree!((unary_expr operator: (prefix_operator #{op}) operand: {e})) + } + ), // Do-catch → try_expr rule!( - (do_statement body: (block statement: _* @body) catch: (catch_block)* @catches) + (doStmt body: @body catchClauses: _* @catches) => (try_expr - body: (block stmt: {body}) + body: {body} catch_clause: {catches}) ), - // Catch block with bound identifier; optional where-clause guard. rule!( - (catch_block - keyword: (catch_keyword) - error: @pattern - where: (where_clause expr: @guard)? - body: (block statement: _* @body)) + (catchItem pattern: @pattern whereClause: (whereClause condition: @guard)) + => + (conditional_pattern pattern: {pattern} condition: {guard}) + ), + rule!( + (catchItem pattern: @pattern) + => + pattern {pattern} + ), + // Catch block with one or more patterns (which have been translated by the catchItem rules) + rule!( + (catchClause + catchItems: _+ @patterns + body: @body) => (catch_clause - pattern: {pattern} - guard: {guard} - body: (block stmt: {body})) + pattern: {make_or_pattern(&mut ctx, patterns)} + body: {body}) ), // Catch block without error binding + rule!((catchClause body: @body) => (catch_clause body: {body})), + // As expression (type cast) — as?, as! + rule!((asExpr expression: @val questionOrExclamationMark: _? @@mark type: @ty) => type_cast_expr { + let op = format!("as{}", mark.map(|m| ctx.source_text(m)).unwrap_or_default()); + tree!((type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})) + }), + // Check expression (`x is T`) → type_test_expr + rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})), + // Await expression → unary_expr with operator "await" + rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), + // Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated + // `forceUnwrapExpr` node. + rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})), + // ---- Imports ---- + // An import declaration. The dotted path (a list of + // `importPathComponent`s) becomes a `name_expr`/`member_access_expr` + // chain (via `member_chain`). A scoped import (`import struct Foo.Bar`) + // has an `importKindSpecifier` and binds the last path component as a + // `name_pattern`; a plain import (`import Foundation`) has none and uses + // a `bulk_importing_pattern` spanning the whole declaration. Any leading + // attributes (`@_exported`) and access modifiers (`public`) become + // `modifier`s. + rule!( + (importDecl + attributes: _* @attrs + modifiers: _* @mods + importKindSpecifier: _? @@kind + path: (importPathComponent name: @@parts)*) + => + import_declaration { + let pattern = match kind { + Some(_) => { + let last = *parts.last().ok_or("import has no path")?; + tree!((name_pattern identifier: (identifier #{last}))) + } + None => tree!((bulk_importing_pattern)), + }; + tree!((import_declaration + modifier: (modifier #{kind})? + modifier: {attrs} + modifier: {mods} + pattern: {pattern} + imported_expr: {member_chain(&mut ctx, parts)})) + } + ), + // ---- Types and declarations ---- + // A leading attribute (`@objc`) or access/function/member/mutation/ + // ownership modifier (swift-syntax models each as a single `declModifier`) + // becomes a `modifier`; its source text is the modifier spelling. + rule!((attribute) @m => (modifier #{m})), + rule!((declModifier) @m => (modifier #{m})), + // A `super` expression. (`self` needs no rule: swift-syntax models it as + // an ordinary `declReferenceExpr`, already mapped to a `name_expr`.) + rule!((superExpr) => (super_expr)), + // Type expressions. A generic type applied with explicit arguments + // (`Set`) becomes a `generic_type_expr` whose `base` is the type + // name and whose `type_argument`s are the (structured) arguments — the + // same shape the sugared `?`/`[]`/`[:]` types desugar to. Matched before + // the plain `identifierType` rule, which would otherwise drop the + // arguments. rule!( - (catch_block keyword: (catch_keyword) body: (block statement: _* @body)) + (identifierType + name: @@name + genericArgumentClause: (genericArgumentClause arguments: (genericArgument argument: @args)*)) => - (catch_clause body: (block stmt: {body})) + (generic_type_expr + base: (named_type_expr name: (identifier #{name})) + type_argument: {args}) ), - // Empty catch block: catch {} + // A named type (`Int`). `identifierType.name` is the type-name token. + rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))), + // A qualified type (`Outer.Inner`, `NSString.CompareOptions`). swift-syntax + // nests these as `memberType` nodes; we keep the whole dotted path as the + // opaque `named_type_expr` name. + rule!((memberType) @ty => (named_type_expr name: (identifier #{ty}))), + // Sugared types desugar to `generic_type_expr`: `T?` -> Optional, + // `[T]` -> Array, `[K: V]` -> Dictionary. rule!( - (catch_block (catch_keyword)) + (optionalType wrappedType: @w) => - (catch_clause body: (block)) + (generic_type_expr base: (named_type_expr name: (identifier "Optional")) type_argument: {w}) ), - // Catch block with unhandled pattern — preserve pattern; optional body. rule!( - (catch_block keyword: (catch_keyword) error: @pat body: (block statement: _* @body)) + (arrayType element: @e) => - (catch_clause - pattern: {pat} - body: (block stmt: {body})) + (generic_type_expr base: (named_type_expr name: (identifier "Array")) type_argument: {e}) ), - // As expression (type cast) — as?, as! - rule!((as_expression (as_operator) @op expr: @val type: @ty) => (type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), - // Check expression (`x is T`) → type_test_expr - rule!((check_expression op: @op target: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), - // Await expression → unary_expr with operator "await" - rule!((await_expression expr: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), - // A multi-part identifier (for example `Foo.Bar.Baz`) is translated to - // a member_access_expr chain with a name_expr base. rule!( - (identifier part: _+ @parts) + (dictionaryType key: @k value: @v) => - expr { member_chain(&mut ctx, parts) } + (generic_type_expr base: (named_type_expr name: (identifier "Dictionary")) type_argument: {k} type_argument: {v}) ), - // Scoped import declaration (for example `import struct Foo.Bar`): - // flatten the identifier parts into a member_access_expr and bind the - // final segment as a name_pattern. + // A tuple type (`(Int, String)`) or function type (`(Int) -> Bool`). + // Both hold their contents as `tupleTypeElement`s, but a tuple element + // maps to `tuple_type_element` while a function parameter maps to + // `parameter`. Each container sets `ctx.in_function_type` for its direct + // children (and translates them explicitly, so a nested type is + // translated in the right context) and the shared `tupleTypeElement` + // rule below reads it. An element's label (`firstName`) is optional. rule!( - (import_declaration scoped_import_kind: @kind name: (identifier part: _+ @parts) @name modifiers: (modifiers)? @mods) + (tupleType elements: _* @@elems) => - (import_declaration - pattern: (name_pattern identifier: (identifier #{parts.last().unwrap()})) - imported_expr: {name} - modifier: (modifier #{kind}) - modifier: {mods}) - ), - // Non-scoped import declaration (for example `import Foundation`): - // flatten the identifier parts into a member_access_expr and use a - // bulk_importing_pattern. - rule!( - (import_declaration name: @name modifiers: (modifiers)? @mods) - => - (import_declaration - pattern: (bulk_importing_pattern) - imported_expr: {name} - modifier: {mods}) - ), - // ---- Types and classes ---- - // Self expression → name_expr - rule!((self_expression) => (name_expr identifier: (identifier "self"))), - // Super expression → super_expr - rule!((super_expression) => (super_expr)), - // Modifiers — unwrap to individual modifier children - rule!((modifiers _* @mods) => modifier* { mods }), - rule!((attribute) @m => (modifier #{m})), - rule!((visibility_modifier) @m => (modifier #{m})), - rule!((function_modifier) @m => (modifier #{m})), - rule!((member_modifier) @m => (modifier #{m})), - rule!((mutation_modifier) @m => (modifier #{m})), - rule!((ownership_modifier) @m => (modifier #{m})), - rule!((property_modifier) @m => (modifier #{m})), - rule!((parameter_modifier) @m => (modifier #{m})), - rule!((inheritance_modifier) @m => (modifier #{m})), - rule!((property_behavior_modifier) @m => (modifier #{m})), - // Type annotations — unwrap - rule!((type_annotation type: @inner) => type_expr { inner }), - // user_type is split into simple_user_type parts. - // Keep a conservative textual fallback to avoid dropping type information. - rule!((user_type) @ty => (named_type_expr name: (identifier #{ty}))), - // Tuple type → tuple_type_expr - rule!((tuple_type element: _* @elems) => (tuple_type_expr element: {elems})), - rule!((tuple_type_item name: @name type: @ty) => (tuple_type_element name: (identifier #{name}) type: {ty})), - rule!((tuple_type_item type: @ty) => (tuple_type_element type: {ty})), - // Array type `[T]` → generic_type_expr with Array base - rule!((array_type element: @e) => (generic_type_expr - base: (named_type_expr name: (identifier "Array")) - type_argument: {e})), - // Dictionary type `[K: V]` → generic_type_expr with Dictionary base - rule!((dictionary_type key: @k value: @v) => (generic_type_expr - base: (named_type_expr name: (identifier "Dictionary")) - type_argument: {k} - type_argument: {v})), - // Optional type `T?` → generic_type_expr with Optional base - rule!((optional_type wrapped: @w) => (generic_type_expr - base: (named_type_expr name: (identifier "Optional")) - type_argument: {w})), - // Function type `(Params) -> Ret` → function_type_expr. - rule!((function_type parameter: _* @ps return_type: @ret) => (function_type_expr parameter: {ps} return_type: {ret})), - rule!((function_type_parameter name: @name type: @ty) => (parameter external_name: (identifier #{name}) type: {ty})), - rule!((function_type_parameter type: @ty) => (parameter type: {ty})), - // Selector expression: `#selector(inner)` -- not yet supported + tuple_type_expr { + ctx.in_function_type = false; + let mut out = Vec::new(); + for e in elems { + out.extend(ctx.translate(e)?); + } + tree!((tuple_type_expr element: {out})) + } + ), rule!( - (selector_expression _ @inner) + (functionType parameters: _* @@params returnClause: (returnClause type: @ret)) => - (unsupported_node) + function_type_expr { + ctx.in_function_type = true; + let mut out = Vec::new(); + for p in params { + out.extend(ctx.translate(p)?); + } + tree!((function_type_expr parameter: {out} return_type: {ret})) + } + ), + rule!( + (tupleTypeElement firstName: _? @@name type: @ty) + => + tuple_type_element { + if ctx.in_function_type { + tree!((parameter external_name: (identifier #{name})? type: {ty})) + } else { + tree!((tuple_type_element name: (identifier #{name})? type: {ty})) + } + } ), - // Key path expressions are currently unsupported. - rule!((key_path_expression) => (unsupported_node)), - // Inheritance specifier → base_type - rule!((inheritance_specifier inherits_from: @ty) => (base_type type: {ty})), + // Selector expression: `#selector(inner)` -- not yet supported + // (swift-syntax represents `#selector`/`#keyPath` and other macro + // expansions uniformly as a `macroExpansionExpr`). + rule!((macroExpansionExpr) => (unsupported_node)), + // A nominal type's `inheritanceClause` (`: Base, Proto`) becomes a list + // of `base_type`s, one per inherited type. Each declaration keyword + // gets its own rule; the bodies are identical but for the keyword. // Class declaration with body containing members rule!( - (class_declaration - declaration_kind: @kind + (classDecl + classKeyword: @kind + modifiers: _* @mods name: @name - body: (class_body member: _* @members) - (inheritance_specifier)* @bases - (modifiers)* @mods) + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases} + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), // Enum class declaration: same as a regular class but with an enum body. rule!( - (class_declaration - declaration_kind: @kind + (enumDecl + enumKeyword: @kind + modifiers: _* @mods name: @name - body: (enum_class_body member: _* @members) - (inheritance_specifier)* @bases - (modifiers)* @mods) + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases} + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), - // Class declaration with empty body + // A `struct` declaration. rule!( - (class_declaration - declaration_kind: @kind + (structDecl + structKeyword: @kind + modifiers: _* @mods name: @name - body: _ - (inheritance_specifier)* @bases - (modifiers)* @mods) + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases}) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} + member: {members}) ), // Protocol declaration rule!( - (protocol_declaration + (protocolDecl + protocolKeyword: @kind + modifiers: _* @mods name: @name - body: (protocol_body member: _* @members) - (inheritance_specifier)* @bases - (modifiers)* @mods) + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => (class_like_declaration - modifier: (modifier "protocol") + modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - base_type: {bases} + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} member: {members}) ), - // Protocol function — return type and body statements both optional. + // An `extension Foo { … }` is likewise a `class_like_declaration`, named + // by the extended type. The extended type is captured opaquely (as its + // source text) so that qualified names (`extension String.Interpolation`, + // a `memberType`) name the declaration just like simple ones. rule!( - (protocol_function_declaration - name: @name - (parameter)* @params - return_type: _? @ret - body: (block statement: _* @body_stmts)? - (modifiers)* @mods) + (extensionDecl + extensionKeyword: @kind + modifiers: _* @mods + extendedType: @@name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)? + memberBlock: (memberBlock members: _* @members)) => - (function_declaration + (class_like_declaration + modifier: (modifier #{kind}) modifier: {mods} name: (identifier #{name}) - parameter: {params} - return_type: {ret} - body: (block stmt: {body_stmts})) + base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))} + member: {members}) ), + // A member of a type declaration unwraps to the contained declaration. + rule!((memberBlockItem decl: _* @d) => member* { d }), // Init declaration → constructor_declaration. Body statements optional; - // body itself is also optional (protocol requirement). + // body itself is also optional (protocol requirement). The parameters + // nest under `signature` (as for `functionDecl`). rule!( - (init_declaration - (parameter)* @params - body: (block statement: _* @body_stmts)? - (modifiers)* @mods) + (initializerDecl + modifiers: _* @mods + signature: (functionSignature + parameterClause: (functionParameterClause parameters: _* @params)) + body: (codeBlock statements: _* @body_stmts)?) => (constructor_declaration modifier: {mods} @@ -1064,9 +1167,9 @@ fn translation_rules() -> Vec> { ), // Deinit declaration → destructor_declaration. Body statements optional. rule!( - (deinit_declaration - body: (block statement: _* @body_stmts) - (modifiers)* @mods) + (deinitializerDecl + modifiers: _* @mods + body: (codeBlock statements: _* @body_stmts)) => (destructor_declaration modifier: {mods} @@ -1074,165 +1177,28 @@ fn translation_rules() -> Vec> { ), // Typealias declaration rule!( - (typealias_declaration name: @name value: @val (modifiers)* @mods) + (typeAliasDecl + modifiers: _* @mods + name: @@name + initializer: (typeInitializerClause value: @val)) => (type_alias_declaration modifier: {mods} name: (identifier #{name}) r#type: {val}) ), - // Subscript declaration (not yet supported -- grammar needs to distinguish plain calls from subscript calls) - rule!( - (subscript_declaration (parameter)* @params (modifiers)* @mods) - => - (unsupported_node) - ), // Associated type declaration (with optional bound) rule!( - (associatedtype_declaration name: @name inherits_from: _? @bound (modifiers)* @mods) + (associatedTypeDecl + modifiers: _* @mods + name: @@name + inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bound))?) => (associated_type_declaration modifier: {mods} name: (identifier #{name}) bound: {bound}) ), - // Protocol property declaration: translate each accessor - // requirement to an `accessor_declaration` carrying the property - // name, type, and outer modifiers. Manual rule: we publish the - // property's name/type/modifiers into `ctx` and translate each - // accessor with `ctx.is_chained` toggled per iteration so the - // inner `getter_specifier`/`setter_specifier` rules emit - // complete nodes from the start (including the - // `chained_declaration` tag for non-first accessors). - rule!( - (protocol_property_declaration - name: (pattern bound_identifier: @name) - requirements: (protocol_property_requirements accessor: _+ @@accessors) - type: _? @ty - (modifiers)* @mods) - => - accessor_declaration* { - ctx.property_name = Some(tree!((identifier #{name}))); - ctx.property_type = ty; - ctx.outer_modifiers = mods; - - let mut result = Vec::new(); - for (i, acc) in accessors.into_iter().enumerate() { - ctx.is_chained = i > 0; - result.extend(ctx.translate(acc)?); - } - result - } - ), - // getter_specifier / setter_specifier → bodyless accessor_declaration - // getter_specifier / setter_specifier → bodyless - // accessor_declaration. Reads property name/type/modifiers from - // `ctx` set by the outer `protocol_property_declaration` rule. - rule!( - (getter_specifier) - => - (accessor_declaration - name: {ctx.property_name.ok_or("getter_specifier outside protocol_property_declaration context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "get") - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)}) - ), - rule!( - (setter_specifier) - => - (accessor_declaration - name: {ctx.property_name.ok_or("setter_specifier outside protocol_property_declaration context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "set") - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)}) - ), - // protocol_property_requirements wrapper — should be consumed by above; fallback - rule!((protocol_property_requirements accessor: _* @accs) => accessor_declaration* { accs }), - // Computed getter → accessor_declaration (body optional). - // Reads property name/type from the outer property_binding rule - // and binding/outer modifiers + chained tag from the outer - // property_declaration rule. - rule!( - (computed_getter body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_getter outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "get") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Computed setter with explicit parameter name. - rule!( - (computed_setter parameter: @param body: (block statement: _* @@body)) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "set") - parameter: (parameter pattern: (name_pattern identifier: (identifier #{param}))) - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Computed setter without explicit parameter name; body optional. - rule!( - (computed_setter body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "set") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Computed modify → accessor_declaration - rule!( - (computed_modify body: (block statement: _* @@body)) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("computed_modify outside property_binding context")?} - type: {ctx.property_type} - accessor_kind: (accessor_kind "modify") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // willset/didset block — spread to children (only reachable as a - // fallback; the outer property_binding manual rule normally - // captures the willset/didset clauses directly). - rule!((willset_didset_block _* @clauses) => accessor_declaration* { clauses }), - // willset clause → accessor_declaration (body optional). Reads - // `ctx.property_name` set by the outer property_binding rule and - // binding/outer modifiers + chained tag from the outer - // property_declaration rule. - rule!( - (willset_clause body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("willset_clause outside property_binding context")?} - accessor_kind: (accessor_kind "willSet") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // didset clause → accessor_declaration (body optional). - rule!( - (didset_clause body: (block statement: _* @@body)?) - => - (accessor_declaration - modifier: {ctx.outer_modifiers.clone()} - modifier: {chained_modifier(&mut ctx)} - name: {ctx.property_name.ok_or("didset_clause outside property_binding context")?} - accessor_kind: (accessor_kind "didSet") - body: (block stmt: {ctx.reset(); ctx.translate(body)?})) - ), - // Preprocessor conditionals — unsupported - rule!((diagnostic) => (unsupported_node)), // ---- Fallbacks ---- // Bare `_` (rather than `(_)`) so this matches both named nodes // and unnamed tokens. Any unnamed token that escapes the @@ -1249,18 +1215,17 @@ fn translation_rules() -> Vec> { ] } -pub fn language_spec(desugared_ast_schema: &'static str) -> simple::LanguageSpec { - let ts_language: tree_sitter::Language = tree_sitter_swift::LANGUAGE.into(); +pub fn language_spec(desugared_ast_schema: &'static str) -> desugaring::LanguageSpec { let config = DesugaringConfig::::new() .add_phase("translate", PhaseKind::OneShot, translation_rules()) .with_output_node_types_yaml(desugared_ast_schema); - let desugarer = ConcreteDesugarer::new(ts_language.clone(), config) - .expect("failed to build Swift desugarer"); - simple::LanguageSpec { + let desugarer = + ConcreteDesugarer::without_language(config).expect("failed to build Swift desugarer"); + desugaring::LanguageSpec { prefix: "swift", - ts_language, - node_types: tree_sitter_swift::NODE_TYPES, + parser: Box::new(super::swift_parse::parse), + node_types: "", file_globs: vec!["*.swift".into(), "*.swiftinterface".into()], - desugar: Some(Box::new(desugarer)), + desugarer: Box::new(desugarer), } } diff --git a/unified/extractor/swift_node_types.yml b/unified/extractor/swift_node_types.yml new file mode 100644 index 000000000000..c98dd1d33b23 --- /dev/null +++ b/unified/extractor/swift_node_types.yml @@ -0,0 +1,1280 @@ +supertypes: + decl: + - accessorDecl + - actorDecl + - associatedTypeDecl + - classDecl + - deinitializerDecl + - editorPlaceholderDecl + - enumCaseDecl + - enumDecl + - extensionDecl + - functionDecl + - ifConfigDecl + - importDecl + - initializerDecl + - macroDecl + - macroExpansionDecl + - missingDecl + - operatorDecl + - poundSourceLocation + - precedenceGroupDecl + - protocolDecl + - structDecl + - subscriptDecl + - typeAliasDecl + - unexpectedCodeDecl + - usingDecl + - variableDecl + expr: + - _canImportExpr + - _canImportVersionInfo + - arrayExpr + - arrowExpr + - asExpr + - assignmentExpr + - awaitExpr + - binaryOperatorExpr + - booleanLiteralExpr + - borrowExpr + - closureExpr + - consumeExpr + - copyExpr + - declReferenceExpr + - dictionaryExpr + - discardAssignmentExpr + - doExpr + - editorPlaceholderExpr + - floatLiteralExpr + - forceUnwrapExpr + - functionCallExpr + - genericSpecializationExpr + - ifExpr + - inOutExpr + - infixOperatorExpr + - integerLiteralExpr + - isExpr + - keyPathExpr + - macroExpansionExpr + - memberAccessExpr + - missingExpr + - nilLiteralExpr + - optionalChainingExpr + - packElementExpr + - packExpansionExpr + - patternExpr + - postfixIfConfigExpr + - postfixOperatorExpr + - prefixOperatorExpr + - regexLiteralExpr + - sequenceExpr + - simpleStringLiteralExpr + - stringLiteralExpr + - subscriptCallExpr + - superExpr + - switchExpr + - ternaryExpr + - tryExpr + - tupleExpr + - typeExpr + - unresolvedAsExpr + - unresolvedIsExpr + - unresolvedTernaryExpr + - unsafeExpr + pattern: + - expressionPattern + - identifierPattern + - isTypePattern + - missingPattern + - tuplePattern + - valueBindingPattern + - wildcardPattern + stmt: + - breakStmt + - continueStmt + - deferStmt + - discardStmt + - doStmt + - expressionStmt + - fallThroughStmt + - forStmt + - guardStmt + - labeledStmt + - missingStmt + - repeatStmt + - returnStmt + - thenStmt + - throwStmt + - whileStmt + - yieldStmt + syntax: + - abiAttributeArguments + - accessorBlock + - accessorBlockFile + - accessorEffectSpecifiers + - accessorParameters + - arrayElement + - attribute + - attributeClauseFile + - availabilityArgument + - availabilityCondition + - availabilityLabeledArgument + - availabilityMacroDefinitionFile + - backDeployedAttributeArguments + - catchClause + - catchItem + - closureCapture + - closureCaptureClause + - closureCaptureSpecifier + - closureParameter + - closureParameterClause + - closureShorthandParameter + - closureSignature + - codeBlock + - codeBlockFile + - codeBlockItem + - compositionTypeElement + - conditionElement + - conformanceRequirement + - declModifier + - declModifierDetail + - declNameArgument + - declNameArguments + - deinitializerEffectSpecifiers + - derivativeAttributeArguments + - designatedType + - dictionaryElement + - differentiabilityArgument + - differentiabilityArguments + - differentiabilityWithRespectToArgument + - differentiableAttributeArguments + - documentationAttributeArgument + - dynamicReplacementAttributeArguments + - enumCaseElement + - enumCaseParameter + - enumCaseParameterClause + - expressionSegment + - functionEffectSpecifiers + - functionParameter + - functionParameterClause + - functionSignature + - genericArgument + - genericArgumentClause + - genericParameter + - genericParameterClause + - genericRequirement + - genericWhereClause + - ifConfigClause + - implementsAttributeArguments + - importPathComponent + - inheritanceClause + - inheritedType + - initializerClause + - keyPathComponent + - keyPathMethodComponent + - keyPathOptionalComponent + - keyPathPropertyComponent + - keyPathSubscriptComponent + - labeledExpr + - labeledSpecializeArgument + - layoutRequirement + - lifetimeSpecifierArgument + - lifetimeTypeSpecifier + - matchingPatternCondition + - memberBlock + - memberBlockItem + - memberBlockItemListFile + - missing + - moduleSelector + - multipleTrailingClosureElement + - nonisolatedSpecifierArgument + - nonisolatedTypeSpecifier + - objCSelectorPiece + - operatorPrecedenceAndTypes + - optionalBindingCondition + - originallyDefinedInAttributeArguments + - patternBinding + - platformVersion + - platformVersionItem + - poundSourceLocationArguments + - precedenceGroupAssignment + - precedenceGroupAssociativity + - precedenceGroupName + - precedenceGroupRelation + - primaryAssociatedType + - primaryAssociatedTypeClause + - returnClause + - sameTypeRequirement + - simpleTypeSpecifier + - sourceFile + - specializeAvailabilityArgument + - specializeTargetFunctionArgument + - specializedAttributeArgument + - stringSegment + - switchCase + - switchCaseItem + - switchCaseLabel + - switchDefaultLabel + - throwsClause + - tuplePatternElement + - tupleTypeElement + - typeAnnotation + - typeEffectSpecifiers + - typeInitializerClause + - versionComponent + - versionTuple + - whereClause + - yieldedExpression + - yieldedExpressionsClause + type: + - arrayType + - attributedType + - classRestrictionType + - compositionType + - dictionaryType + - functionType + - identifierType + - implicitlyUnwrappedOptionalType + - inlineArrayType + - memberType + - metatypeType + - missingType + - namedOpaqueReturnType + - optionalType + - packElementType + - packExpansionType + - someOrAnyType + - suppressedType + - tupleType +named: + _canImportExpr: + canImportKeyword: _token + leftParen: _token + importPath: _token + versionInfo?: _canImportVersionInfo + rightParen: _token + _canImportVersionInfo: + comma: _token + label: _token + colon: _token + version: versionTuple + abiAttributeArguments: + provider: [associatedTypeDecl, deinitializerDecl, enumCaseDecl, functionDecl, initializerDecl, missingDecl, subscriptDecl, typeAliasDecl, variableDecl] + accessorBlock: + leftBrace: _token + accessors: [accessorDecl, codeBlockItemList] + rightBrace: _token + accessorBlockFile: + leftBrace?: _token + accessors*: accessorDecl + rightBrace?: _token + endOfFileToken: _token + accessorDecl: + attributes*: [attribute, ifConfigDecl] + modifier?: declModifier + accessorSpecifier: _token + parameters?: accessorParameters + effectSpecifiers?: accessorEffectSpecifiers + body?: codeBlock + accessorEffectSpecifiers: + asyncSpecifier?: _token + throwsClause?: throwsClause + accessorParameters: + leftParen: _token + name: _token + rightParen: _token + actorDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + actorKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + arrayElement: + expression: expr + trailingComma?: _token + arrayExpr: + leftSquare: _token + elements*: arrayElement + rightSquare: _token + arrayType: + leftSquare: _token + element: type + rightSquare: _token + arrowExpr: + effectSpecifiers?: typeEffectSpecifiers + arrow: _token + asExpr: + expression: expr + asKeyword: _token + questionOrExclamationMark?: _token + type: type + assignmentExpr: + equal: _token + associatedTypeDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + associatedtypeKeyword: _token + name: _token + inheritanceClause?: inheritanceClause + initializer?: typeInitializerClause + genericWhereClause?: genericWhereClause + attribute: + atSign: _token + attributeName: type + leftParen?: _token + arguments?: [labeledExprList, availabilityArgumentList, specializeAttributeArgumentList, specializedAttributeArgument, objCSelectorPieceList, implementsAttributeArguments, differentiableAttributeArguments, derivativeAttributeArguments, backDeployedAttributeArguments, originallyDefinedInAttributeArguments, dynamicReplacementAttributeArguments, effectsAttributeArgumentList, documentationAttributeArgumentList, abiAttributeArguments] + rightParen?: _token + attributeClauseFile: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + endOfFileToken: _token + attributedType: + specifiers*: [simpleTypeSpecifier, lifetimeTypeSpecifier, nonisolatedTypeSpecifier] + attributes*: [attribute, ifConfigDecl] + lateSpecifiers*: [simpleTypeSpecifier, lifetimeTypeSpecifier, nonisolatedTypeSpecifier] + baseType: type + availabilityArgument: + argument: [_token, platformVersion, availabilityLabeledArgument] + trailingComma?: _token + availabilityCondition: + availabilityKeyword: _token + leftParen: _token + availabilityArguments*: availabilityArgument + rightParen: _token + availabilityLabeledArgument: + label: _token + colon: _token + value: [simpleStringLiteralExpr, versionTuple] + availabilityMacroDefinitionFile: + platformVersion: platformVersion + colon: _token + specs*: availabilityArgument + endOfFileToken: _token + awaitExpr: + awaitKeyword: _token + expression: expr + backDeployedAttributeArguments: + beforeLabel: _token + colon: _token + platforms*: platformVersionItem + binaryOperatorExpr: + operator: _token + booleanLiteralExpr: + literal: _token + borrowExpr: + borrowKeyword: _token + expression: expr + breakStmt: + breakKeyword: _token + label?: _token + catchClause: + catchKeyword: _token + catchItems*: catchItem + body: codeBlock + catchItem: + pattern?: pattern + whereClause?: whereClause + trailingComma?: _token + classDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + classKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + classRestrictionType: + classKeyword: _token + closureCapture: + specifier?: closureCaptureSpecifier + name: _token + initializer?: initializerClause + trailingComma?: _token + closureCaptureClause: + leftSquare: _token + items*: closureCapture + rightSquare: _token + closureCaptureSpecifier: + specifier: _token + leftParen?: _token + detail?: _token + rightParen?: _token + closureExpr: + leftBrace: _token + signature?: closureSignature + statements*: codeBlockItem + rightBrace: _token + closureParameter: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + firstName: _token + secondName?: _token + colon?: _token + type?: type + ellipsis?: _token + trailingComma?: _token + closureParameterClause: + leftParen: _token + parameters*: closureParameter + rightParen: _token + closureShorthandParameter: + name: _token + trailingComma?: _token + closureSignature: + attributes*: [attribute, ifConfigDecl] + capture?: closureCaptureClause + parameterClause?: [closureShorthandParameterList, closureParameterClause] + effectSpecifiers?: typeEffectSpecifiers + returnClause?: returnClause + inKeyword: _token + codeBlock: + leftBrace: _token + statements*: codeBlockItem + rightBrace: _token + codeBlockFile: + body: codeBlock + endOfFileToken: _token + codeBlockItem: + item: [decl, stmt, expr] + semicolon?: _token + compositionType: + elements*: compositionTypeElement + compositionTypeElement: + type: type + ampersand?: token + conditionElement: + condition: [expr, availabilityCondition, matchingPatternCondition, optionalBindingCondition] + trailingComma?: _token + conformanceRequirement: + leftType: type + colon: _token + rightType: type + consumeExpr: + consumeKeyword: _token + expression: expr + continueStmt: + continueKeyword: _token + label?: _token + copyExpr: + copyKeyword: _token + expression: expr + declModifier: + name: _token + detail?: declModifierDetail + declModifierDetail: + leftParen: _token + detail: _token + rightParen: _token + declNameArgument: + name: token + colon: _token + declNameArguments: + leftParen: _token + arguments*: declNameArgument + rightParen: _token + declReferenceExpr: + moduleSelector?: moduleSelector + baseName: _token + argumentNames?: declNameArguments + deferStmt: + deferKeyword: _token + body: codeBlock + deinitializerDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + deinitKeyword: _token + effectSpecifiers?: deinitializerEffectSpecifiers + body?: codeBlock + deinitializerEffectSpecifiers: + asyncSpecifier?: _token + derivativeAttributeArguments: + ofLabel: _token + colon: _token + originalDeclName: expr + period?: _token + accessorSpecifier?: _token + comma?: _token + arguments?: differentiabilityWithRespectToArgument + designatedType: + leadingComma: _token + name: token + dictionaryElement: + key: expr + colon: _token + value: expr + trailingComma?: _token + dictionaryExpr: + leftSquare: _token + content: [_token, dictionaryElementList] + rightSquare: _token + dictionaryType: + leftSquare: _token + key: type + colon: _token + value: type + rightSquare: _token + differentiabilityArgument: + argument: _token + trailingComma?: _token + differentiabilityArguments: + leftParen: _token + arguments*: differentiabilityArgument + rightParen: _token + differentiabilityWithRespectToArgument: + wrtLabel: _token + colon: _token + arguments: [differentiabilityArgument, differentiabilityArguments] + differentiableAttributeArguments: + kindSpecifier?: _token + kindSpecifierComma?: _token + arguments?: differentiabilityWithRespectToArgument + argumentsComma?: _token + genericWhereClause?: genericWhereClause + discardAssignmentExpr: + wildcard: _token + discardStmt: + discardKeyword: _token + expression: expr + doExpr: + doKeyword: _token + body: codeBlock + catchClauses*: catchClause + doStmt: + doKeyword: _token + throwsClause?: throwsClause + body: codeBlock + catchClauses*: catchClause + documentationAttributeArgument: + label: _token + colon: _token + value: [_token, stringLiteralExpr] + trailingComma?: _token + dynamicReplacementAttributeArguments: + forLabel: _token + colon: _token + declName: declReferenceExpr + editorPlaceholderDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + placeholder: _token + editorPlaceholderExpr: + placeholder: _token + enumCaseDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + caseKeyword: _token + elements*: enumCaseElement + enumCaseElement: + name: _token + parameterClause?: enumCaseParameterClause + rawValue?: initializerClause + trailingComma?: _token + enumCaseParameter: + modifiers*: declModifier + firstName?: _token + secondName?: _token + colon?: _token + type: type + defaultValue?: initializerClause + trailingComma?: _token + enumCaseParameterClause: + leftParen: _token + parameters*: enumCaseParameter + rightParen: _token + enumDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + enumKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + expressionPattern: + expression: expr + expressionSegment: + backslash: _token + pounds?: _token + leftParen: _token + expressions*: labeledExpr + rightParen: _token + expressionStmt: + expression: expr + extensionDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + extensionKeyword: _token + extendedType: type + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + fallThroughStmt: + fallthroughKeyword: _token + floatLiteralExpr: + literal: _token + forStmt: + forKeyword: _token + tryKeyword?: _token + awaitKeyword?: _token + unsafeKeyword?: _token + caseKeyword?: _token + pattern: pattern + typeAnnotation?: typeAnnotation + inKeyword: _token + sequence: expr + whereClause?: whereClause + body: codeBlock + forceUnwrapExpr: + expression: expr + exclamationMark: _token + functionCallExpr: + calledExpression: expr + leftParen?: _token + arguments*: labeledExpr + rightParen?: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + functionDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + funcKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + signature: functionSignature + genericWhereClause?: genericWhereClause + body?: codeBlock + functionEffectSpecifiers: + asyncSpecifier?: _token + throwsClause?: throwsClause + functionParameter: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + firstName: _token + secondName?: _token + colon: _token + type: type + ellipsis?: _token + defaultValue?: initializerClause + trailingComma?: _token + functionParameterClause: + leftParen: _token + parameters*: functionParameter + rightParen: _token + functionSignature: + parameterClause: functionParameterClause + effectSpecifiers?: functionEffectSpecifiers + returnClause?: returnClause + functionType: + leftParen: _token + parameters*: tupleTypeElement + rightParen: _token + effectSpecifiers?: typeEffectSpecifiers + returnClause: returnClause + genericArgument: + argument: [type, expr] + trailingComma?: _token + genericArgumentClause: + leftAngle: _token + arguments*: genericArgument + rightAngle: _token + genericParameter: + attributes*: [attribute, ifConfigDecl] + specifier?: _token + name: _token + colon?: _token + inheritedType?: type + trailingComma?: _token + genericParameterClause: + leftAngle: _token + parameters*: genericParameter + genericWhereClause?: genericWhereClause + rightAngle: _token + genericRequirement: + requirement: [sameTypeRequirement, conformanceRequirement, layoutRequirement] + trailingComma?: _token + genericSpecializationExpr: + expression: expr + genericArgumentClause: genericArgumentClause + genericWhereClause: + whereKeyword: _token + requirements*: genericRequirement + guardStmt: + guardKeyword: _token + conditions*: conditionElement + elseKeyword: _token + body: codeBlock + identifierPattern: + identifier: _token + identifierType: + moduleSelector?: moduleSelector + name: _token + genericArgumentClause?: genericArgumentClause + ifConfigClause: + poundKeyword: _token + condition?: expr + elements?: [codeBlockItemList, switchCaseList, memberBlockItemList, expr, attributeList] + ifConfigDecl: + clauses*: ifConfigClause + poundEndif: _token + ifExpr: + ifKeyword: _token + conditions*: conditionElement + body: codeBlock + elseKeyword?: _token + elseBody?: [ifExpr, codeBlock] + implementsAttributeArguments: + type: type + comma: _token + declName: declReferenceExpr + implicitlyUnwrappedOptionalType: + wrappedType: type + exclamationMark: _token + importDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + importKeyword: _token + importKindSpecifier?: _token + path*: importPathComponent + importPathComponent: + name: _token + trailingPeriod?: _token + inOutExpr: + ampersand: _token + expression: expr + infixOperatorExpr: + leftOperand: expr + operator: expr + rightOperand: expr + inheritanceClause: + colon: _token + inheritedTypes*: inheritedType + inheritedType: + type: type + trailingComma?: _token + initializerClause: + equal: _token + value: expr + initializerDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + initKeyword: _token + optionalMark?: _token + genericParameterClause?: genericParameterClause + signature: functionSignature + genericWhereClause?: genericWhereClause + body?: codeBlock + inlineArrayType: + leftSquare: _token + count: genericArgument + separator: _token + element: genericArgument + rightSquare: _token + integerLiteralExpr: + literal: _token + isExpr: + expression: expr + isKeyword: _token + type: type + isTypePattern: + isKeyword: _token + type: type + keyPathComponent: + period?: _token + component: [keyPathPropertyComponent, keyPathMethodComponent, keyPathSubscriptComponent, keyPathOptionalComponent] + keyPathExpr: + backslash: _token + root?: type + components*: keyPathComponent + keyPathMethodComponent: + declName: declReferenceExpr + leftParen: _token + arguments*: labeledExpr + rightParen: _token + keyPathOptionalComponent: + questionOrExclamationMark: _token + keyPathPropertyComponent: + declName: declReferenceExpr + genericArgumentClause?: genericArgumentClause + keyPathSubscriptComponent: + leftSquare: _token + arguments*: labeledExpr + rightSquare: _token + labeledExpr: + label?: _token + colon?: _token + expression: expr + trailingComma?: _token + labeledSpecializeArgument: + label: _token + colon: _token + value: token + trailingComma?: _token + labeledStmt: + label: _token + colon: _token + statement: stmt + layoutRequirement: + type: type + colon: _token + layoutSpecifier: _token + leftParen?: _token + size?: _token + comma?: _token + alignment?: _token + rightParen?: _token + lifetimeSpecifierArgument: + parameter: _token + trailingComma?: _token + lifetimeTypeSpecifier: + dependsOnKeyword: _token + leftParen: _token + scopedKeyword?: _token + arguments*: lifetimeSpecifierArgument + rightParen: _token + macroDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + macroKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + signature: functionSignature + definition?: initializerClause + genericWhereClause?: genericWhereClause + macroExpansionDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + pound: _token + moduleSelector?: moduleSelector + macroName: _token + genericArgumentClause?: genericArgumentClause + leftParen?: _token + arguments*: labeledExpr + rightParen?: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + macroExpansionExpr: + pound: _token + moduleSelector?: moduleSelector + macroName: _token + genericArgumentClause?: genericArgumentClause + leftParen?: _token + arguments*: labeledExpr + rightParen?: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + matchingPatternCondition: + caseKeyword: _token + pattern: pattern + typeAnnotation?: typeAnnotation + initializer: initializerClause + memberAccessExpr: + base?: expr + period: _token + declName: declReferenceExpr + memberBlock: + leftBrace: _token + members*: memberBlockItem + rightBrace: _token + memberBlockItem: + decl: decl + semicolon?: _token + memberBlockItemListFile: + members*: memberBlockItem + endOfFileToken: _token + memberType: + baseType: type + period: _token + moduleSelector?: moduleSelector + name: _token + genericArgumentClause?: genericArgumentClause + metatypeType: + baseType: type + period: _token + metatypeSpecifier: _token + missing: + placeholder: _token + missingDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + placeholder: _token + missingExpr: + placeholder: _token + missingPattern: + placeholder: _token + missingStmt: + placeholder: _token + missingType: + placeholder: _token + moduleSelector: + moduleName: _token + colonColon: _token + multipleTrailingClosureElement: + label: _token + colon: _token + closure: closureExpr + namedOpaqueReturnType: + genericParameterClause: genericParameterClause + type: type + nilLiteralExpr: + nilKeyword: _token + nonisolatedSpecifierArgument: + leftParen: _token + nonsendingKeyword: _token + rightParen: _token + nonisolatedTypeSpecifier: + nonisolatedKeyword: _token + argument?: nonisolatedSpecifierArgument + objCSelectorPiece: + name?: token + colon?: _token + operatorDecl: + fixitySpecifier: _token + operatorKeyword: _token + name: _token + operatorPrecedenceAndTypes?: operatorPrecedenceAndTypes + operatorPrecedenceAndTypes: + colon: _token + precedenceGroup: _token + designatedTypes*: designatedType + optionalBindingCondition: + bindingSpecifier: _token + pattern: pattern + typeAnnotation?: typeAnnotation + initializer?: initializerClause + optionalChainingExpr: + expression: expr + questionMark: _token + optionalType: + wrappedType: type + questionMark: _token + originallyDefinedInAttributeArguments: + moduleLabel: _token + colon: _token + moduleName: stringLiteralExpr + comma: _token + platforms*: platformVersionItem + packElementExpr: + eachKeyword: _token + pack: expr + packElementType: + eachKeyword: _token + pack: type + packExpansionExpr: + repeatKeyword: _token + repetitionPattern: expr + packExpansionType: + repeatKeyword: _token + repetitionPattern: type + patternBinding: + pattern: pattern + typeAnnotation?: typeAnnotation + initializer?: initializerClause + accessorBlock?: accessorBlock + trailingComma?: _token + patternExpr: + pattern: pattern + platformVersion: + platform: _token + version?: versionTuple + platformVersionItem: + platformVersion: platformVersion + trailingComma?: _token + postfixIfConfigExpr: + base?: expr + config: ifConfigDecl + postfixOperatorExpr: + expression: expr + operator: _token + poundSourceLocation: + poundSourceLocation: _token + leftParen: _token + arguments?: poundSourceLocationArguments + rightParen: _token + poundSourceLocationArguments: + fileLabel: _token + fileColon: _token + fileName: simpleStringLiteralExpr + comma: _token + lineLabel: _token + lineColon: _token + lineNumber: _token + precedenceGroupAssignment: + assignmentLabel: _token + colon: _token + value: _token + precedenceGroupAssociativity: + associativityLabel: _token + colon: _token + value: _token + precedenceGroupDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + precedencegroupKeyword: _token + name: _token + leftBrace: _token + groupAttributes*: [precedenceGroupRelation, precedenceGroupAssignment, precedenceGroupAssociativity] + rightBrace: _token + precedenceGroupName: + name: _token + trailingComma?: _token + precedenceGroupRelation: + higherThanOrLowerThanLabel: _token + colon: _token + precedenceGroups*: precedenceGroupName + prefixOperatorExpr: + operator: _token + expression: expr + primaryAssociatedType: + name: _token + trailingComma?: _token + primaryAssociatedTypeClause: + leftAngle: _token + primaryAssociatedTypes*: primaryAssociatedType + rightAngle: _token + protocolDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + protocolKeyword: _token + name: _token + primaryAssociatedTypeClause?: primaryAssociatedTypeClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + regexLiteralExpr: + openingPounds?: _token + openingSlash: _token + regex: _token + closingSlash: _token + closingPounds?: _token + repeatStmt: + repeatKeyword: _token + body: codeBlock + whileKeyword: _token + condition: expr + returnClause: + arrow: _token + type: type + returnStmt: + returnKeyword: _token + expression?: expr + sameTypeRequirement: + leftType: [type, expr] + equal: _token + rightType: [type, expr] + sequenceExpr: + elements*: expr + simpleStringLiteralExpr: + openingQuote: _token + segments*: stringSegment + closingQuote: _token + simpleTypeSpecifier: + specifier: _token + someOrAnyType: + someOrAnySpecifier: _token + constraint: type + sourceFile: + shebang?: _token + statements*: codeBlockItem + endOfFileToken: _token + specializeAvailabilityArgument: + availabilityLabel: _token + colon: _token + availabilityArguments*: availabilityArgument + semicolon: _token + specializeTargetFunctionArgument: + targetLabel: _token + colon: _token + declName: declReferenceExpr + trailingComma?: _token + specializedAttributeArgument: + genericWhereClause: genericWhereClause + stringLiteralExpr: + openingPounds?: _token + openingQuote: _token + segments*: [stringSegment, expressionSegment] + closingQuote: _token + closingPounds?: _token + stringSegment: + content: _token + structDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + structKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + inheritanceClause?: inheritanceClause + genericWhereClause?: genericWhereClause + memberBlock: memberBlock + subscriptCallExpr: + calledExpression: expr + leftSquare: _token + arguments*: labeledExpr + rightSquare: _token + trailingClosure?: closureExpr + additionalTrailingClosures*: multipleTrailingClosureElement + subscriptDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + subscriptKeyword: _token + genericParameterClause?: genericParameterClause + parameterClause: functionParameterClause + returnClause: returnClause + genericWhereClause?: genericWhereClause + accessorBlock?: accessorBlock + superExpr: + superKeyword: _token + suppressedType: + withoutTilde: _token + type: type + switchCase: + attribute?: attribute + label: [switchDefaultLabel, switchCaseLabel] + statements*: codeBlockItem + switchCaseItem: + pattern: pattern + whereClause?: whereClause + trailingComma?: _token + switchCaseLabel: + caseKeyword: _token + caseItems*: switchCaseItem + colon: _token + switchDefaultLabel: + defaultKeyword: _token + colon: _token + switchExpr: + switchKeyword: _token + subject: expr + leftBrace: _token + cases*: [switchCase, ifConfigDecl] + rightBrace: _token + ternaryExpr: + condition: expr + questionMark: _token + thenExpression: expr + colon: _token + elseExpression: expr + thenStmt: + thenKeyword: _token + expression: expr + throwStmt: + throwKeyword: _token + expression: expr + throwsClause: + throwsSpecifier: _token + leftParen?: _token + type?: type + rightParen?: _token + tryExpr: + tryKeyword: _token + questionOrExclamationMark?: _token + expression: expr + tupleExpr: + leftParen: _token + elements*: labeledExpr + rightParen: _token + tuplePattern: + leftParen: _token + elements*: tuplePatternElement + rightParen: _token + tuplePatternElement: + label?: _token + colon?: _token + pattern: pattern + trailingComma?: _token + tupleType: + leftParen: _token + elements*: tupleTypeElement + rightParen: _token + tupleTypeElement: + inoutKeyword?: _token + firstName?: _token + secondName?: _token + colon?: _token + type: type + ellipsis?: _token + trailingComma?: _token + typeAliasDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + typealiasKeyword: _token + name: _token + genericParameterClause?: genericParameterClause + initializer: typeInitializerClause + genericWhereClause?: genericWhereClause + typeAnnotation: + colon: _token + type: type + typeEffectSpecifiers: + asyncSpecifier?: _token + throwsClause?: throwsClause + typeExpr: + type: type + typeInitializerClause: + equal: _token + value: type + unexpectedCodeDecl: + unresolvedAsExpr: + asKeyword: _token + questionOrExclamationMark?: _token + unresolvedIsExpr: + isKeyword: _token + unresolvedTernaryExpr: + questionMark: _token + thenExpression: expr + colon: _token + unsafeExpr: + unsafeKeyword: _token + expression: expr + usingDecl: + usingKeyword: _token + specifier: [attribute, _token] + valueBindingPattern: + bindingSpecifier: _token + pattern: pattern + variableDecl: + attributes*: [attribute, ifConfigDecl] + modifiers*: declModifier + bindingSpecifier: _token + bindings*: patternBinding + versionComponent: + period: _token + number: _token + versionTuple: + major: _token + components*: versionComponent + whereClause: + whereKeyword: _token + condition: expr + whileStmt: + whileKeyword: _token + conditions*: conditionElement + body: codeBlock + wildcardPattern: + wildcard: _token + yieldStmt: + yieldKeyword: _token + yieldedExpressions: [yieldedExpressionsClause, expr] + yieldedExpression: + expression: expr + comma?: _token + yieldedExpressionsClause: + leftParen: _token + elements*: yieldedExpression + rightParen: _token + _token: + binaryOperator: + dollarIdentifier: + floatLiteral: + identifier: + integerLiteral: + postfixOperator: + prefixOperator: + rawStringPoundDelimiter: + regexLiteralPattern: + regexPoundDelimiter: + shebang: + unknown: diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output index 8f28322b4930..6833344de16d 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-capture-list.output @@ -2,41 +2,61 @@ let f = { [weak self] in self?.doThing() } --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - captures: - capture_list - item: - capture_list_item - name: simple_identifier "self" - ownership: - ownership_modifier - statement: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "doThing" - target: - optional_chain_marker - expr: - self_expression - suffix: - call_suffix - arguments: - value_arguments +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + capture: + closureCaptureClause + leftSquare: [ + rightSquare: ] + items: + closureCapture + name: self + specifier: + closureCaptureSpecifier + specifier: weak + inKeyword: in + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "doThing" + base: + optionalChainingExpr + expression: + declReferenceExpr + baseName: self + questionMark: ? + pattern: + identifierPattern + identifier: identifier "f" --- @@ -51,6 +71,12 @@ top_level identifier: identifier "f" value: function_expr + capture_declaration: + variable_declaration + modifier: modifier "weak" + pattern: + name_pattern + identifier: identifier "self" body: block stmt: @@ -61,9 +87,3 @@ top_level name_expr identifier: identifier "self" member: identifier "doThing" - capture_declaration: - variable_declaration - modifier: modifier "weak" - pattern: - name_pattern - identifier: identifier "self" diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output index 95d638118d84..c20da77c72cb 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-explicit-parameters.output @@ -2,45 +2,63 @@ let f = { (x: Int) -> Int in x * 2 } --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - statement: - multiplicative_expression - lhs: simple_identifier "x" - op: * - rhs: integer_literal "2" - type: - lambda_function_type - params: - lambda_function_type_parameters - parameter: - lambda_parameter - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + inKeyword: in + parameterClause: + closureParameterClause + leftParen: ( + rightParen: ) + parameters: + closureParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" + pattern: + identifierPattern + identifier: identifier "f" --- @@ -55,23 +73,23 @@ top_level identifier: identifier "f" value: function_expr - body: - block - stmt: - binary_expr - operator: infix_operator "*" - left: - name_expr - identifier: identifier "x" - right: int_literal "2" parameter: parameter - pattern: - name_pattern - identifier: identifier "x" type: named_type_expr name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" return_type: named_type_expr name: identifier "Int" + body: + block + stmt: + binary_expr + left: + name_expr + identifier: identifier "x" + operator: infix_operator "*" + right: int_literal "2" diff --git a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output index bd286c385799..1b07604e02c5 100644 --- a/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output +++ b/unified/extractor/tests/corpus/swift/closures/closure-with-shorthand-parameters.output @@ -2,24 +2,40 @@ let f = { $0 + $1 } --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - statement: - additive_expression - lhs: simple_identifier "$0" - op: + - rhs: simple_identifier "$1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: dollarIdentifier "$0" + rightOperand: + declReferenceExpr + baseName: dollarIdentifier "$1" + pattern: + identifierPattern + identifier: identifier "f" --- @@ -38,10 +54,10 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "$0" + operator: infix_operator "+" right: name_expr identifier: identifier "$1" diff --git a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output index 6c9a403f19c1..4fbc1c8f71f0 100644 --- a/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/multi-statement-closure.output @@ -5,62 +5,91 @@ let f = { (x: Int) -> Int in --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "f" - value: - lambda_literal - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: - additive_expression - lhs: simple_identifier "x" - op: + - rhs: integer_literal "1" - control_transfer_statement - kind: return - result: - multiplicative_expression - lhs: simple_identifier "y" - op: * - rhs: integer_literal "2" - type: - lambda_function_type - params: - lambda_function_type_parameters - parameter: - lambda_parameter - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + signature: + closureSignature + attributes: + inKeyword: in + parameterClause: + closureParameterClause + leftParen: ( + rightParen: ) + parameters: + closureParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "y" + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "y" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" + returnKeyword: return + pattern: + identifierPattern + identifier: identifier "f" --- @@ -75,6 +104,17 @@ top_level identifier: identifier "f" value: function_expr + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" + return_type: + named_type_expr + name: identifier "Int" body: block stmt: @@ -85,27 +125,16 @@ top_level identifier: identifier "y" value: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "x" + operator: infix_operator "+" right: int_literal "1" return_expr value: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "y" + operator: infix_operator "*" right: int_literal "2" - parameter: - parameter - pattern: - name_pattern - identifier: identifier "x" - type: - named_type_expr - name: identifier "Int" - return_type: - named_type_expr - name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output index 56b8bf9a7c20..3e26ff27eb58 100644 --- a/unified/extractor/tests/corpus/swift/closures/trailing-closure.output +++ b/unified/extractor/tests/corpus/swift/closures/trailing-closure.output @@ -2,24 +2,40 @@ xs.map { $0 * 2 } --- -source_file - statement: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "map" - target: simple_identifier "xs" - suffix: - call_suffix - lambda: - lambda_literal - statement: - multiplicative_expression - lhs: simple_identifier "$0" - op: * - rhs: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + arguments: + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "map" + base: + declReferenceExpr + baseName: identifier "xs" + trailingClosure: + closureExpr + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: dollarIdentifier "$0" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" --- @@ -28,6 +44,12 @@ top_level block stmt: call_expr + callee: + member_access_expr + base: + name_expr + identifier: identifier "xs" + member: identifier "map" argument: argument value: @@ -36,14 +58,8 @@ top_level block stmt: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "$0" + operator: infix_operator "*" right: int_literal "2" - callee: - member_access_expr - base: - name_expr - identifier: identifier "xs" - member: identifier "map" diff --git a/unified/extractor/tests/corpus/swift/collections/array-literal.output b/unified/extractor/tests/corpus/swift/collections/array-literal.output index f6ee44c1f809..c6ea2c2094fa 100644 --- a/unified/extractor/tests/corpus/swift/collections/array-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/array-literal.output @@ -2,23 +2,42 @@ let xs = [1, 2, 3] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "xs" - value: - array_literal - element: - integer_literal "1" - integer_literal "2" - integer_literal "3" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "xs" --- diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output index a19028d3f3bb..edd306a69cbd 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-literal.output @@ -2,30 +2,53 @@ let d = ["a": 1, "b": 2] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "d" - value: - dictionary_literal - element: - dictionary_literal_item - key: - line_string_literal - text: line_str_text "a" - value: integer_literal "1" - dictionary_literal_item - key: - line_string_literal - text: line_str_text "b" - value: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + dictionaryExpr + leftSquare: [ + rightSquare: ] + content: + dictionaryElement + colon: : + trailingComma: , + value: + integerLiteralExpr + literal: integerLiteral "1" + key: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "a" + dictionaryElement + colon: : + value: + integerLiteralExpr + literal: integerLiteral "2" + key: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "b" + pattern: + identifierPattern + identifier: identifier "d" --- diff --git a/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output b/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output index 59afc51867a2..e2f939e0683c 100644 --- a/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output +++ b/unified/extractor/tests/corpus/swift/collections/dictionary-subscript.output @@ -4,31 +4,40 @@ let v = d["key"] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "v" - value: - call_expression - function: simple_identifier "d" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "key" - comment "// TODO: same parser issue as the array subscript case above —" - comment "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`." +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + subscriptCallExpr + leftSquare: [ + rightSquare: ] + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "key" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "d" + pattern: + identifierPattern + identifier: identifier "v" --- @@ -43,9 +52,9 @@ top_level identifier: identifier "v" value: call_expr - argument: - argument - value: string_literal "\"key\"" callee: name_expr identifier: identifier "d" + argument: + argument + value: string_literal "\"key\"" diff --git a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output index 90d1a9dde368..e9a70a43bb42 100644 --- a/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output +++ b/unified/extractor/tests/corpus/swift/collections/empty-array-literal-with-type.output @@ -2,32 +2,38 @@ let xs: [Int] = [] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "xs" - type: - type_annotation - type: - type - name: - array_type +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "xs" + typeAnnotation: + typeAnnotation + colon: : + type: + arrayType + leftSquare: [ + rightSquare: ] element: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: - array_literal + identifierType + name: identifier "Int" --- diff --git a/unified/extractor/tests/corpus/swift/collections/set-literal.output b/unified/extractor/tests/corpus/swift/collections/set-literal.output index a1a1dde75f9a..a06670231ebb 100644 --- a/unified/extractor/tests/corpus/swift/collections/set-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/set-literal.output @@ -2,41 +2,57 @@ let s: Set = [1, 2, 3] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "s" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "s" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Set" + genericArgumentClause: + genericArgumentClause arguments: - type_arguments + genericArgument argument: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - name: type_identifier "Set" - value: - array_literal - element: - integer_literal "1" - integer_literal "2" - integer_literal "3" + identifierType + name: identifier "Int" + leftAngle: < + rightAngle: > --- @@ -50,8 +66,13 @@ top_level name_pattern identifier: identifier "s" type: - named_type_expr - name: identifier "Set" + generic_type_expr + base: + named_type_expr + name: identifier "Set" + type_argument: + named_type_expr + name: identifier "Int" value: array_literal element: diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.output b/unified/extractor/tests/corpus/swift/collections/subscript-access.output index 481a3e95f774..ec24f0c1f1df 100644 --- a/unified/extractor/tests/corpus/swift/collections/subscript-access.output +++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.output @@ -1,34 +1,40 @@ -// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape -// as `xs(0)`), so the mapping currently produces a call_expr. Update the -// parser / add a separate subscript_expr node and remap when fixed. +// TODO: `xs[0]` is mapped to a call_expr, even though swift-syntax reports a +// distinct subscriptCallExpr. Giving subscripts their own shape needs only a +// subscript_expr node in ast_types.yml and a remap. let first = xs[0] --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "first" - value: - call_expression - function: simple_identifier "xs" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "0" - comment "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape" - comment "// as `xs(0)`), so the mapping currently produces a call_expr. Update the" - comment "// parser / add a separate subscript_expr node and remap when fixed." +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + subscriptCallExpr + leftSquare: [ + rightSquare: ] + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "0" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "xs" + pattern: + identifierPattern + identifier: identifier "first" --- @@ -43,9 +49,9 @@ top_level identifier: identifier "first" value: call_expr - argument: - argument - value: int_literal "0" callee: name_expr identifier: identifier "xs" + argument: + argument + value: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.swift b/unified/extractor/tests/corpus/swift/collections/subscript-access.swift index 00a85bda4336..eeffca017397 100644 --- a/unified/extractor/tests/corpus/swift/collections/subscript-access.swift +++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.swift @@ -1,4 +1,4 @@ -// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape -// as `xs(0)`), so the mapping currently produces a call_expr. Update the -// parser / add a separate subscript_expr node and remap when fixed. +// TODO: `xs[0]` is mapped to a call_expr, even though swift-syntax reports a +// distinct subscriptCallExpr. Giving subscripts their own shape needs only a +// subscript_expr node in ast_types.yml and a remap. let first = xs[0] diff --git a/unified/extractor/tests/corpus/swift/collections/tuple-literal.output b/unified/extractor/tests/corpus/swift/collections/tuple-literal.output index a0ac8861674b..facbc2fcbb45 100644 --- a/unified/extractor/tests/corpus/swift/collections/tuple-literal.output +++ b/unified/extractor/tests/corpus/swift/collections/tuple-literal.output @@ -2,28 +2,46 @@ let t = (1, "two", 3.0) --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "t" - value: - tuple_expression - element: - tuple_expression_item - value: integer_literal "1" - tuple_expression_item +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = value: - line_string_literal - text: line_str_text "two" - tuple_expression_item - value: real_literal "3.0" + tupleExpr + leftParen: ( + rightParen: ) + elements: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "two" + trailingComma: , + labeledExpr + expression: + floatLiteralExpr + literal: floatLiteral "3.0" + pattern: + identifierPattern + identifier: identifier "t" --- diff --git a/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output b/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output index 29b234f30e26..6ecbd22eebe0 100644 --- a/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output +++ b/unified/extractor/tests/corpus/swift/collections/tuple-member-access.output @@ -2,23 +2,32 @@ let n = t.0 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - navigation_expression - suffix: - navigation_suffix - suffix: integer_literal "0" - target: simple_identifier "t" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: integerLiteral "0" + base: + declReferenceExpr + baseName: identifier "t" + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output index 3919b875b96a..800647eb7474 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output +++ b/unified/extractor/tests/corpus/swift/control-flow/binding-modifier-does-not-leak-to-sibling.output @@ -8,44 +8,79 @@ default: --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" - switch_statement - entry: - switch_entry - pattern: - switch_pattern +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" pattern: - pattern - kind: simple_identifier "someConstant" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "matched" - switch_entry - default: default_keyword "default" - statement: - control_transfer_statement - kind: break - expr: simple_identifier "y" + identifierPattern + identifier: identifier "x" + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + declReferenceExpr + baseName: identifier "someConstant" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "matched" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + breakStmt + breakKeyword: break + subject: + declReferenceExpr + baseName: identifier "y" + switchKeyword: switch --- @@ -60,27 +95,27 @@ top_level identifier: identifier "x" value: int_literal "1" switch_expr + value: + name_expr + identifier: identifier "y" case: switch_case + pattern: + expr_equality_pattern + expr: + name_expr + identifier: identifier "someConstant" body: block stmt: call_expr - argument: - argument - value: string_literal "\"matched\"" callee: name_expr identifier: identifier "print" - pattern: - expr_equality_pattern - expr: - name_expr - identifier: identifier "someConstant" + argument: + argument + value: string_literal "\"matched\"" switch_case body: block stmt: break_expr "break" - value: - name_expr - identifier: identifier "y" diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output new file mode 100644 index 000000000000..6e8ec9ae3b9a --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output @@ -0,0 +1,94 @@ +func withCleanup() { + defer { print("cleanup") } + print("work") +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + deferStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "cleanup" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + deferKeyword: defer + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "work" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "withCleanup" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "withCleanup" + body: + block + stmt: + unsupported_node "defer { print(\"cleanup\") }" + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"work\"" diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift new file mode 100644 index 000000000000..0bb8820326db --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift @@ -0,0 +1,4 @@ +func withCleanup() { + defer { print("cleanup") } + print("work") +} diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output new file mode 100644 index 000000000000..7e0eac29c0fc --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output @@ -0,0 +1,81 @@ +struct Resource: ~Copyable { + consuming func close() { + discard self + } +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "Resource" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + type: + suppressedType + type: + identifierType + name: identifier "Copyable" + withoutTilde: prefixOperator "~" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + discardStmt + expression: + declReferenceExpr + baseName: self + discardKeyword: discard + name: identifier "close" + modifiers: + declModifier + name: consuming + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + modifiers: + structKeyword: struct + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "struct" + name: identifier "Resource" + base_type: + base_type + type: unsupported_node "~Copyable" + member: + function_declaration + name: identifier "close" + body: + block + stmt: unsupported_node "discard self" diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift new file mode 100644 index 000000000000..8f207d03da9c --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift @@ -0,0 +1,5 @@ +struct Resource: ~Copyable { + consuming func close() { + discard self + } +} diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output new file mode 100644 index 000000000000..9cfe81048402 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output @@ -0,0 +1,118 @@ +func classify(_ x: Int) { + switch x { + case 1: + fallthrough + default: + break + } +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "1" + statements: + codeBlockItem + item: + fallThroughStmt + fallthroughKeyword: fallthrough + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + breakStmt + breakKeyword: break + subject: + declReferenceExpr + baseName: identifier "x" + switchKeyword: switch + name: identifier "classify" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "x" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "classify" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" + body: + block + stmt: + switch_expr + value: + name_expr + identifier: identifier "x" + case: + switch_case + pattern: + expr_equality_pattern + expr: int_literal "1" + body: + block + stmt: unsupported_node "fallthrough" + switch_case + body: + block + stmt: break_expr "break" diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift new file mode 100644 index 000000000000..bedbf0590753 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift @@ -0,0 +1,8 @@ +func classify(_ x: Int) { + switch x { + case 1: + fallthrough + default: + break + } +} diff --git a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output index a21962341217..d739eca564b5 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/guard-let.output +++ b/unified/extractor/tests/corpus/swift/control-flow/guard-let.output @@ -2,25 +2,37 @@ guard let value = optional else { return } --- -source_file - statement: - guard_statement - body: - block - statement: - control_transfer_statement - kind: return - condition: - if_condition - kind: - if_let_binding - pattern: - pattern - binding: - value_binding_pattern - mutability: let - bound_identifier: simple_identifier "value" - value: simple_identifier "optional" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + guardStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + returnKeyword: return + conditions: + conditionElement + condition: + optionalBindingCondition + initializer: + initializerClause + equal: = + value: + declReferenceExpr + baseName: identifier "optional" + pattern: + identifierPattern + identifier: identifier "value" + bindingSpecifier: let + elseKeyword: else + guardKeyword: guard --- @@ -33,17 +45,17 @@ top_level pattern_guard_expr pattern: constructor_pattern - element: - pattern_element - pattern: - name_pattern - identifier: identifier "value" constructor: member_access_expr base: named_type_expr name: identifier "Optional" member: identifier "some" + element: + pattern_element + pattern: + name_pattern + identifier: identifier "value" value: name_expr identifier: identifier "optional" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output index 6a53c87d21a2..2a0676513f23 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-case-let-with-shadowing-in-condition-value.output @@ -4,40 +4,59 @@ if case let x = x + 10 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - condition: - if_condition - kind: - if_let_binding - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + matchingPatternCondition + initializer: + initializerClause + equal: = + value: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "10" pattern: - pattern - bound_identifier: simple_identifier "x" - value: - additive_expression - lhs: simple_identifier "x" - op: + - rhs: integer_literal "10" + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "x" + bindingSpecifier: let + caseKeyword: case + ifKeyword: if --- @@ -53,20 +72,20 @@ top_level identifier: identifier "x" value: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "x" + operator: infix_operator "+" right: int_literal "10" then: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output b/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output index e8f413726466..35f1c2c46d2c 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-else-if-chain.output @@ -8,61 +8,103 @@ if x > 0 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - else_branch: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "2" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: < - rhs: integer_literal "0" - else_branch: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "3" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + elseKeyword: else + elseBody: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "2" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + elseKeyword: else + elseBody: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "3" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + ifKeyword: if + ifKeyword: if --- @@ -73,47 +115,47 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" + then: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: int_literal "1" else: if_expr condition: binary_expr - operator: infix_operator "<" left: name_expr identifier: identifier "x" + operator: infix_operator "<" right: int_literal "0" - else: + then: block stmt: call_expr - argument: - argument - value: int_literal "3" callee: name_expr identifier: identifier "print" - then: - block - stmt: - call_expr argument: argument value: int_literal "2" + else: + block + stmt: + call_expr callee: name_expr identifier: identifier "print" - then: - block - stmt: - call_expr - argument: - argument - value: int_literal "1" - callee: - name_expr - identifier: identifier "print" + argument: + argument + value: int_literal "3" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-else.output b/unified/extractor/tests/corpus/swift/control-flow/if-else.output index 469861214676..744b5c51ab24 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-else.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-else.output @@ -6,43 +6,70 @@ if x > 0 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - else_branch: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - prefix_expression - operation: - - target: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + elseKeyword: else + elseBody: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + prefixOperatorExpr + expression: + declReferenceExpr + baseName: identifier "x" + operator: prefixOperator "-" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + ifKeyword: if --- @@ -53,35 +80,35 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" - else: + then: block stmt: call_expr - argument: - argument - value: - unary_expr - operand: - name_expr - identifier: identifier "x" - operator: prefix_operator "-" callee: name_expr identifier: identifier "print" - then: - block - stmt: - call_expr argument: argument value: name_expr identifier: identifier "x" + else: + block + stmt: + call_expr callee: name_expr identifier: identifier "print" + argument: + argument + value: + unary_expr + operand: + name_expr + identifier: identifier "x" + operator: prefix_operator "-" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output index f6b605a7461c..d1bcf82b0faa 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-let-optional-binding.output @@ -4,32 +4,48 @@ if let value = optional { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "value" - condition: - if_condition - kind: - if_let_binding - pattern: - pattern - binding: - value_binding_pattern - mutability: let - bound_identifier: simple_identifier "value" - value: simple_identifier "optional" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "value" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + optionalBindingCondition + initializer: + initializerClause + equal: = + value: + declReferenceExpr + baseName: identifier "optional" + pattern: + identifierPattern + identifier: identifier "value" + bindingSpecifier: let + ifKeyword: if --- @@ -42,17 +58,17 @@ top_level pattern_guard_expr pattern: constructor_pattern - element: - pattern_element - pattern: - name_pattern - identifier: identifier "value" constructor: member_access_expr base: named_type_expr name: identifier "Optional" member: identifier "some" + element: + pattern_element + pattern: + name_pattern + identifier: identifier "value" value: name_expr identifier: identifier "optional" @@ -60,11 +76,11 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "value" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/if-statement.output b/unified/extractor/tests/corpus/swift/control-flow/if-statement.output index 2c29ab1dc69b..77bba019ffb9 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/if-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/if-statement.output @@ -4,28 +4,47 @@ if x > 0 { --- -source_file - statement: - if_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + ifKeyword: if --- @@ -36,20 +55,20 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" then: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output new file mode 100644 index 000000000000..9d2041aa2ad1 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output @@ -0,0 +1,222 @@ +switch n { +case let x where x > 0: + print("positive") +case let y where y < 0, 0: + print("non-positive") +default: + print("other") +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "x" + bindingSpecifier: let + whereClause: + whereClause + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whereKeyword: where + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "positive" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + trailingComma: , + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "y" + bindingSpecifier: let + whereClause: + whereClause + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "y" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whereKeyword: where + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "0" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "non-positive" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "other" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "n" + switchKeyword: switch + +--- + +top_level + body: + block + stmt: + switch_expr + value: + name_expr + identifier: identifier "n" + case: + switch_case + pattern: + conditional_pattern + condition: + binary_expr + left: + name_expr + identifier: identifier "x" + operator: infix_operator ">" + right: int_literal "0" + pattern: + name_pattern + identifier: identifier "x" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"positive\"" + switch_case + pattern: + or_pattern + pattern: + conditional_pattern + condition: + binary_expr + left: + name_expr + identifier: identifier "y" + operator: infix_operator "<" + right: int_literal "0" + pattern: + name_pattern + identifier: identifier "y" + expr_equality_pattern + expr: int_literal "0" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"non-positive\"" + switch_case + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"other\"" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift new file mode 100644 index 000000000000..50003cb1fbca --- /dev/null +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift @@ -0,0 +1,8 @@ +switch n { +case let x where x > 0: + print("positive") +case let y where y < 0, 0: + print("non-positive") +default: + print("other") +} diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output index bb90cb60fc5b..a88579852947 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-statement.output @@ -9,65 +9,114 @@ default: --- -source_file - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: integer_literal "1" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "one" - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: integer_literal "2" - switch_pattern - pattern: - pattern - kind: integer_literal "3" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "two or three" - switch_entry - default: default_keyword "default" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "other" - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "1" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "one" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + trailingComma: , + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "2" + switchCaseItem + pattern: + expressionPattern + expression: + integerLiteralExpr + literal: integerLiteral "3" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "two or three" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "other" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "x" + switchKeyword: switch --- @@ -76,32 +125,25 @@ top_level block stmt: switch_expr + value: + name_expr + identifier: identifier "x" case: switch_case - body: - block - stmt: - call_expr - argument: - argument - value: string_literal "\"one\"" - callee: - name_expr - identifier: identifier "print" pattern: expr_equality_pattern expr: int_literal "1" - switch_case body: block stmt: call_expr - argument: - argument - value: string_literal "\"two or three\"" callee: name_expr identifier: identifier "print" + argument: + argument + value: string_literal "\"one\"" + switch_case pattern: or_pattern pattern: @@ -109,17 +151,24 @@ top_level expr: int_literal "2" expr_equality_pattern expr: int_literal "3" - switch_case body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument - value: string_literal "\"other\"" + value: string_literal "\"two or three\"" + switch_case + body: + block + stmt: + call_expr callee: name_expr identifier: identifier "print" - value: - name_expr - identifier: identifier "x" + argument: + argument + value: string_literal "\"other\"" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output index 4d98620fe8f4..90bb6b44e6e5 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-binding-pattern.output @@ -7,77 +7,111 @@ case .square(let s): --- -source_file - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let - pattern: - pattern - bound_identifier: simple_identifier "r" - dot: . - name: simple_identifier "circle" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "r" - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let - pattern: - pattern - bound_identifier: simple_identifier "s" - dot: . - name: simple_identifier "square" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "s" - expr: simple_identifier "shape" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + patternExpr + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "r" + bindingSpecifier: let + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "circle" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "r" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + patternExpr + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "s" + bindingSpecifier: let + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "square" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "s" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "shape" + switchKeyword: switch --- @@ -86,55 +120,55 @@ top_level block stmt: switch_expr + value: + name_expr + identifier: identifier "shape" case: switch_case + pattern: + constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "circle" + element: + pattern_element + pattern: + name_pattern + identifier: identifier "r" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "r" - callee: - name_expr - identifier: identifier "print" + switch_case pattern: constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "square" element: pattern_element pattern: name_pattern - identifier: identifier "r" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "circle" - switch_case + identifier: identifier "s" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "s" - callee: - name_expr - identifier: identifier "print" - pattern: - constructor_pattern - element: - pattern_element - pattern: - name_pattern - identifier: identifier "s" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "square" - value: - name_expr - identifier: identifier "shape" diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output index aef36c168558..20b17d160e44 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output +++ b/unified/extractor/tests/corpus/swift/control-flow/switch-with-labeled-case-pattern-arguments.output @@ -7,79 +7,119 @@ case .thread(threadRowId: _, let rowId): --- -source_file - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - name: simple_identifier "isAcknowledged" - pattern: - pattern - kind: - boolean_literal - dot: . - name: simple_identifier "implicit" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "yes" - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: - case_pattern - arguments: - tuple_pattern - item: - tuple_pattern_item - name: simple_identifier "threadRowId" - pattern: - pattern - kind: wildcard_pattern "_" - tuple_pattern_item - pattern: - pattern - kind: - binding_pattern - binding: - value_binding_pattern - mutability: let - pattern: - pattern - bound_identifier: simple_identifier "rowId" - dot: . - name: simple_identifier "thread" - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "rowId" - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + colon: : + label: identifier "isAcknowledged" + expression: + booleanLiteralExpr + literal: false + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "implicit" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "yes" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + colon: : + label: identifier "threadRowId" + expression: + discardAssignmentExpr + wildcard: _ + trailingComma: , + labeledExpr + expression: + patternExpr + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "rowId" + bindingSpecifier: let + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "thread" + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "rowId" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + subject: + declReferenceExpr + baseName: identifier "x" + switchKeyword: switch --- @@ -88,45 +128,40 @@ top_level block stmt: switch_expr + value: + name_expr + identifier: identifier "x" case: switch_case - body: - block - stmt: - call_expr - argument: - argument - value: string_literal "\"yes\"" - callee: - name_expr - identifier: identifier "print" pattern: constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "implicit" element: pattern_element key: identifier "isAcknowledged" pattern: expr_equality_pattern expr: boolean_literal "false" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "implicit" - switch_case body: block stmt: call_expr - argument: - argument - value: - name_expr - identifier: identifier "rowId" callee: name_expr identifier: identifier "print" + argument: + argument + value: string_literal "\"yes\"" + switch_case pattern: constructor_pattern + constructor: + member_access_expr + base: inferred_type_expr "." + member: identifier "thread" element: pattern_element key: identifier "threadRowId" @@ -135,10 +170,15 @@ top_level pattern: name_pattern identifier: identifier "rowId" - constructor: - member_access_expr - base: inferred_type_expr "." - member: identifier "thread" - value: - name_expr - identifier: identifier "x" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: + name_expr + identifier: identifier "rowId" diff --git a/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output b/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output index 7f9da80d34ac..88c7bc1b886c 100644 --- a/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output +++ b/unified/extractor/tests/corpus/swift/control-flow/ternary-expression.output @@ -2,29 +2,47 @@ let y = x > 0 ? 1 : -1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: - ternary_expression - condition: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - if_false: - prefix_expression - operation: - - target: integer_literal "1" - if_true: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + ternaryExpr + colon: : + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + questionMark: ? + elseExpression: + prefixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + operator: prefixOperator "-" + thenExpression: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "y" --- @@ -41,13 +59,13 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" + then: int_literal "1" else: unary_expr operand: int_literal "1" operator: prefix_operator "-" - then: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output b/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output index 07aa40618bd1..30d9570f3bee 100644 --- a/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output +++ b/unified/extractor/tests/corpus/swift/desugar/additive-expression-is-desugared.output @@ -2,12 +2,21 @@ --- -source_file - statement: - additive_expression - lhs: integer_literal "1" - op: + - rhs: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + integerLiteralExpr + literal: integerLiteral "1" + rightOperand: + integerLiteralExpr + literal: integerLiteral "2" --- @@ -16,6 +25,6 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: int_literal "1" + operator: infix_operator "+" right: int_literal "2" diff --git a/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output b/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output index ff830fd4b894..982309ffa5af 100644 --- a/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output +++ b/unified/extractor/tests/corpus/swift/desugar/another-additive-expression-is-desugared.output @@ -2,12 +2,21 @@ foo + bar --- -source_file - statement: - additive_expression - lhs: simple_identifier "foo" - op: + - rhs: simple_identifier "bar" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "foo" + rightOperand: + declReferenceExpr + baseName: identifier "bar" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "foo" + operator: infix_operator "+" right: name_expr identifier: identifier "bar" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output index 4f312dabb151..cacdc64a46de 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-deeply-nested-path-three-parts.output @@ -2,15 +2,24 @@ import Foundation.Networking.URLSession --- -source_file - statement: - import_declaration - name: - identifier - part: - simple_identifier "Foundation" - simple_identifier "Networking" - simple_identifier "URLSession" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + path: + importPathComponent + name: identifier "Foundation" + trailingPeriod: . + importPathComponent + name: identifier "Networking" + trailingPeriod: . + importPathComponent + name: identifier "URLSession" --- @@ -19,7 +28,6 @@ top_level block stmt: import_declaration - pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" imported_expr: member_access_expr base: @@ -29,3 +37,4 @@ top_level identifier: identifier "Foundation" member: identifier "Networking" member: identifier "URLSession" + pattern: bulk_importing_pattern "import Foundation.Networking.URLSession" diff --git a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output index efd2a6461243..4fc053a7bc53 100644 --- a/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output +++ b/unified/extractor/tests/corpus/swift/desugar/import-with-dotted-path-two-parts.output @@ -2,14 +2,21 @@ import Foundation.Networking --- -source_file - statement: - import_declaration - name: - identifier - part: - simple_identifier "Foundation" - simple_identifier "Networking" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + path: + importPathComponent + name: identifier "Foundation" + trailingPeriod: . + importPathComponent + name: identifier "Networking" --- @@ -18,10 +25,10 @@ top_level block stmt: import_declaration - pattern: bulk_importing_pattern "import Foundation.Networking" imported_expr: member_access_expr base: name_expr identifier: identifier "Foundation" member: identifier "Networking" + pattern: bulk_importing_pattern "import Foundation.Networking" diff --git a/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output b/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output index fbf8e8100af7..93319c522981 100644 --- a/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output +++ b/unified/extractor/tests/corpus/swift/desugar/scoped-import-uses-name-pattern.output @@ -2,15 +2,22 @@ import struct Foundation.Date --- -source_file - statement: - import_declaration - name: - identifier - part: - simple_identifier "Foundation" - simple_identifier "Date" - scoped_import_kind: struct +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + importKindSpecifier: struct + path: + importPathComponent + name: identifier "Foundation" + trailingPeriod: . + importPathComponent + name: identifier "Date" --- @@ -20,12 +27,12 @@ top_level stmt: import_declaration modifier: modifier "struct" - pattern: - name_pattern - identifier: identifier "Date" imported_expr: member_access_expr base: name_expr identifier: identifier "Foundation" member: identifier "Date" + pattern: + name_pattern + identifier: identifier "Date" diff --git a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output index 7a6be1c35e4c..583f33563d13 100644 --- a/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output +++ b/unified/extractor/tests/corpus/swift/desugar/simple-import-with-single-name.output @@ -2,12 +2,18 @@ import Foundation --- -source_file - statement: - import_declaration - name: - identifier - part: simple_identifier "Foundation" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + importDecl + attributes: + modifiers: + importKeyword: import + path: + importPathComponent + name: identifier "Foundation" --- @@ -16,7 +22,7 @@ top_level block stmt: import_declaration - pattern: bulk_importing_pattern "import Foundation" imported_expr: name_expr identifier: identifier "Foundation" + pattern: bulk_importing_pattern "import Foundation" diff --git a/unified/extractor/tests/corpus/swift/expressions/consume-expression.output b/unified/extractor/tests/corpus/swift/expressions/consume-expression.output new file mode 100644 index 000000000000..f20f89b72558 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/consume-expression.output @@ -0,0 +1,85 @@ +let original = [1, 2, 3] +let consumed = consume original + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "original" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + consumeExpr + expression: + declReferenceExpr + baseName: identifier "original" + consumeKeyword: consume + pattern: + identifierPattern + identifier: identifier "consumed" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "original" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "consumed" + value: unsupported_node "consume original" diff --git a/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift b/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift new file mode 100644 index 000000000000..37922e036792 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift @@ -0,0 +1,2 @@ +let original = [1, 2, 3] +let consumed = consume original diff --git a/unified/extractor/tests/corpus/swift/expressions/copy-expression.output b/unified/extractor/tests/corpus/swift/expressions/copy-expression.output new file mode 100644 index 000000000000..9f065b046a90 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/copy-expression.output @@ -0,0 +1,85 @@ +let original = [1, 2, 3] +let copied = copy original + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "original" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + copyExpr + expression: + declReferenceExpr + baseName: identifier "original" + copyKeyword: copy + pattern: + identifierPattern + identifier: identifier "copied" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "original" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "copied" + value: unsupported_node "copy original" diff --git a/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift b/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift new file mode 100644 index 000000000000..9b7fa65909b1 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift @@ -0,0 +1,2 @@ +let original = [1, 2, 3] +let copied = copy original diff --git a/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output new file mode 100644 index 000000000000..4f3bd0214411 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output @@ -0,0 +1,56 @@ +let numbers = Array() + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + genericSpecializationExpr + expression: + declReferenceExpr + baseName: identifier "Array" + genericArgumentClause: + genericArgumentClause + arguments: + genericArgument + argument: + identifierType + name: identifier "Int" + leftAngle: < + rightAngle: > + pattern: + identifierPattern + identifier: identifier "numbers" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "numbers" + value: + call_expr + callee: unsupported_node "Array" diff --git a/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift new file mode 100644 index 000000000000..8e5f07de5562 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift @@ -0,0 +1 @@ +let numbers = Array() diff --git a/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output new file mode 100644 index 000000000000..a803e9e594fd --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output @@ -0,0 +1,48 @@ +let keyPath = \String.count + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + keyPathExpr + backslash: \ + components: + keyPathComponent + period: . + component: + keyPathPropertyComponent + declName: + declReferenceExpr + baseName: identifier "count" + root: + identifierType + name: identifier "String" + pattern: + identifierPattern + identifier: identifier "keyPath" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "keyPath" + value: unsupported_node "\\String.count" diff --git a/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift new file mode 100644 index 000000000000..943f181b3404 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift @@ -0,0 +1 @@ +let keyPath = \String.count diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output new file mode 100644 index 000000000000..2bdc964ddeaa --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output @@ -0,0 +1,51 @@ +func doWork() {} +unsafe doWork() + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + name: identifier "doWork" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + codeBlockItem + item: + unsafeExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "doWork" + unsafeKeyword: unsafe + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "doWork" + body: block "func doWork() {}" + unsupported_node "unsafe doWork()" diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift new file mode 100644 index 000000000000..e398f9cb6596 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift @@ -0,0 +1,2 @@ +func doWork() {} +unsafe doWork() diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output new file mode 100644 index 000000000000..3dae9884c81e --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output @@ -0,0 +1,96 @@ +var a = 1 +var b = 2 +swap(&a, &b) + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "a" + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "2" + pattern: + identifierPattern + identifier: identifier "b" + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + inOutExpr + expression: + declReferenceExpr + baseName: identifier "a" + ampersand: & + trailingComma: , + labeledExpr + expression: + inOutExpr + expression: + declReferenceExpr + baseName: identifier "b" + ampersand: & + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "swap" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "a" + value: int_literal "1" + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "b" + value: int_literal "2" + call_expr + callee: + name_expr + identifier: identifier "swap" + argument: + argument + value: unsupported_node "&a" + argument + value: unsupported_node "&b" diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift new file mode 100644 index 000000000000..fb71b4c89bf3 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift @@ -0,0 +1,3 @@ +var a = 1 +var b = 2 +swap(&a, &b) diff --git a/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output b/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output index ba0c002a4527..f885d5762f2d 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call-with-labelled-arguments.output @@ -2,22 +2,29 @@ greet(person: "Bob") --- -source_file - statement: - call_expression - function: simple_identifier "greet" - suffix: - call_suffix +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) arguments: - value_arguments - argument: - value_argument - name: - value_argument_label - name: simple_identifier "person" - value: - line_string_literal - text: line_str_text "Bob" + labeledExpr + colon: : + label: identifier "person" + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "Bob" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "greet" --- @@ -26,10 +33,10 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "greet" argument: argument name: identifier "person" value: string_literal "\"Bob\"" - callee: - name_expr - identifier: identifier "greet" diff --git a/unified/extractor/tests/corpus/swift/functions/function-call.output b/unified/extractor/tests/corpus/swift/functions/function-call.output index ed604730d33c..a1e2859ccd6a 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-call.output +++ b/unified/extractor/tests/corpus/swift/functions/function-call.output @@ -2,19 +2,28 @@ foo(1, 2) --- -source_file - statement: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" - value_argument - value: integer_literal "2" + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "2" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" --- @@ -23,11 +32,11 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "foo" argument: argument value: int_literal "1" argument value: int_literal "2" - callee: - name_expr - identifier: identifier "foo" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output index fdd737e1258d..3495a13106fb 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output @@ -4,37 +4,60 @@ func greet(name: String = "world") { --- -source_file - statement: - function_declaration - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "name" - name: simple_identifier "greet" - parameter: - function_parameter - default_value: - line_string_literal - text: line_str_text "world" - parameter: - parameter - name: simple_identifier "name" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "name" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "greet" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "String" + firstName: identifier "name" + defaultValue: + initializerClause + equal: = + value: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "world" + funcKeyword: func --- @@ -43,22 +66,25 @@ top_level block stmt: function_declaration + name: identifier "greet" + parameter: + parameter + type: + named_type_expr + name: identifier "String" + pattern: + name_pattern + identifier: identifier "name" + default: string_literal "\"world\"" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "name" - callee: - name_expr - identifier: identifier "print" - name: identifier "greet" - parameter: - parameter - default: string_literal "\"world\"" - pattern: - name_pattern - identifier: identifier "name" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output new file mode 100644 index 000000000000..232fb6dc2dbc --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output @@ -0,0 +1,81 @@ +func increment(_ x: inout Int) { + x += 1 +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + name: identifier "increment" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + attributedType + attributes: + baseType: + identifierType + name: identifier "Int" + lateSpecifiers: + specifiers: + simpleTypeSpecifier + specifier: inout + firstName: _ + secondName: identifier "x" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "increment" + parameter: + parameter + external_name: identifier "_" + type: unsupported_node "inout Int" + pattern: + name_pattern + identifier: identifier "x" + body: + block + stmt: + compound_assign_expr + target: + name_expr + identifier: identifier "x" + operator: infix_operator "+=" + value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift new file mode 100644 index 000000000000..5741998e8b53 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift @@ -0,0 +1,3 @@ +func increment(_ x: inout Int) { + x += 1 +} diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output index bfa68c645ea1..7488edbcb231 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output @@ -4,35 +4,51 @@ func greet(person name: String) { --- -source_file - statement: - function_declaration - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "name" - name: simple_identifier "greet" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "person" - name: simple_identifier "name" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "name" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "greet" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "String" + firstName: identifier "person" + secondName: identifier "name" + funcKeyword: func --- @@ -41,22 +57,25 @@ top_level block stmt: function_declaration + name: identifier "greet" + parameter: + parameter + external_name: identifier "person" + type: + named_type_expr + name: identifier "String" + pattern: + name_pattern + identifier: identifier "name" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "name" - callee: - name_expr - identifier: identifier "print" - name: identifier "greet" - parameter: - parameter - external_name: identifier "person" - pattern: - name_pattern - identifier: identifier "name" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output index b5cdfd73d48f..4ddc26ae94d6 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-no-parameters.output @@ -4,24 +4,46 @@ func greet() { --- -source_file - statement: - function_declaration - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: - line_string_literal - text: line_str_text "hello" - name: simple_identifier "greet" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "hello" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + name: identifier "greet" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func --- @@ -30,14 +52,14 @@ top_level block stmt: function_declaration + name: identifier "greet" body: block stmt: call_expr - argument: - argument - value: string_literal "\"hello\"" callee: name_expr identifier: identifier "print" - name: identifier "greet" + argument: + argument + value: string_literal "\"hello\"" diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output index 6544f4313cd7..e69b19307674 100644 --- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output +++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output @@ -4,52 +4,68 @@ func add(_ a: Int, _ b: Int) -> Int { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: simple_identifier "b" - name: simple_identifier "add" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "a" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "b" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" + returnKeyword: return + name: identifier "add" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func --- @@ -58,31 +74,37 @@ top_level block stmt: function_declaration - body: - block - stmt: - return_expr - value: - binary_expr - operator: infix_operator "+" - left: - name_expr - identifier: identifier "a" - right: - name_expr - identifier: identifier "b" name: identifier "add" parameter: parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "a" parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" pattern: name_pattern identifier: identifier "b" return_type: named_type_expr name: identifier "Int" + body: + block + stmt: + return_expr + value: + binary_expr + left: + name_expr + identifier: identifier "a" + operator: infix_operator "+" + right: + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output index f42367a8fca2..d09aac2744a2 100644 --- a/unified/extractor/tests/corpus/swift/functions/generic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output @@ -4,41 +4,58 @@ func identity(_ x: T) -> T { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: simple_identifier "x" - name: simple_identifier "identity" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "T" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "T" - type_parameters: - type_parameters - parameter: - type_parameter - name: type_identifier "T" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + declReferenceExpr + baseName: identifier "x" + returnKeyword: return + name: identifier "identity" + genericParameterClause: + genericParameterClause + parameters: + genericParameter + attributes: + name: identifier "T" + leftAngle: < + rightAngle: > + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "T" + firstName: _ + secondName: identifier "x" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "T" + funcKeyword: func --- @@ -47,20 +64,23 @@ top_level block stmt: function_declaration - body: - block - stmt: - return_expr - value: - name_expr - identifier: identifier "x" name: identifier "identity" parameter: parameter external_name: identifier "_" + type: + named_type_expr + name: identifier "T" pattern: name_pattern identifier: identifier "x" return_type: named_type_expr name: identifier "T" + body: + block + stmt: + return_expr + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output index 8db16da8ab8b..d0a844d02afa 100644 --- a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output +++ b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-call.output @@ -2,30 +2,39 @@ let y = .some(1) --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: - call_expression - function: - prefix_expression - operation: . - target: simple_identifier "some" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "some" + pattern: + identifierPattern + identifier: identifier "y" --- @@ -40,10 +49,10 @@ top_level identifier: identifier "y" value: call_expr - argument: - argument - value: int_literal "1" callee: member_access_expr base: inferred_type_expr ".some" member: identifier "some" + argument: + argument + value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output index 85aeeffde6eb..bec014593d91 100644 --- a/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output +++ b/unified/extractor/tests/corpus/swift/functions/leading-dot-expression-value.output @@ -2,21 +2,29 @@ let x = .foo --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: - prefix_expression - operation: . - target: simple_identifier "foo" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "foo" + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/functions/method-call.output b/unified/extractor/tests/corpus/swift/functions/method-call.output index 5a8a23f5658a..3c0b150b8235 100644 --- a/unified/extractor/tests/corpus/swift/functions/method-call.output +++ b/unified/extractor/tests/corpus/swift/functions/method-call.output @@ -2,22 +2,29 @@ list.append(1) --- -source_file - statement: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "append" - target: simple_identifier "list" - suffix: - call_suffix +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) arguments: - value_arguments - argument: - value_argument - value: integer_literal "1" + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "1" + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "append" + base: + declReferenceExpr + baseName: identifier "list" --- @@ -26,12 +33,12 @@ top_level block stmt: call_expr - argument: - argument - value: int_literal "1" callee: member_access_expr base: name_expr identifier: identifier "list" member: identifier "append" + argument: + argument + value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/functions/nested-function-type.output b/unified/extractor/tests/corpus/swift/functions/nested-function-type.output new file mode 100644 index 000000000000..d9ce0cd7a976 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/nested-function-type.output @@ -0,0 +1,156 @@ +typealias NestedFunction = ((Int) -> Bool) -> Bool + +typealias MixedParametersAndTuples = ((Int) -> Bool, String) -> (Bool, Int) + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + typeAliasDecl + attributes: + name: identifier "NestedFunction" + modifiers: + initializer: + typeInitializerClause + equal: = + value: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + identifierType + name: identifier "Int" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Bool" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Bool" + typealiasKeyword: typealias + codeBlockItem + item: + typeAliasDecl + attributes: + name: identifier "MixedParametersAndTuples" + modifiers: + initializer: + typeInitializerClause + equal: = + value: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + trailingComma: , + type: + functionType + leftParen: ( + rightParen: ) + parameters: + tupleTypeElement + type: + identifierType + name: identifier "Int" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Bool" + tupleTypeElement + type: + identifierType + name: identifier "String" + returnClause: + returnClause + arrow: -> + type: + tupleType + leftParen: ( + rightParen: ) + elements: + tupleTypeElement + trailingComma: , + type: + identifierType + name: identifier "Bool" + tupleTypeElement + type: + identifierType + name: identifier "Int" + typealiasKeyword: typealias + +--- + +top_level + body: + block + stmt: + type_alias_declaration + name: identifier "NestedFunction" + type: + function_type_expr + parameter: + parameter + type: + function_type_expr + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Bool" + return_type: + named_type_expr + name: identifier "Bool" + type_alias_declaration + name: identifier "MixedParametersAndTuples" + type: + function_type_expr + parameter: + parameter + type: + function_type_expr + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Bool" + parameter + type: + named_type_expr + name: identifier "String" + return_type: + tuple_type_expr + element: + tuple_type_element + type: + named_type_expr + name: identifier "Bool" + tuple_type_element + type: + named_type_expr + name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/functions/nested-function-type.swift b/unified/extractor/tests/corpus/swift/functions/nested-function-type.swift new file mode 100644 index 000000000000..b19128965f34 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/functions/nested-function-type.swift @@ -0,0 +1,3 @@ +typealias NestedFunction = ((Int) -> Bool) -> Bool + +typealias MixedParametersAndTuples = ((Int) -> Bool, String) -> (Bool, Int) diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output index 7ca1dfbad4eb..78c20ffc01e9 100644 --- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output +++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output @@ -4,54 +4,72 @@ func sum(_ values: Int...) -> Int { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - call_expression - function: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "reduce" - target: simple_identifier "values" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: integer_literal "0" - value_argument - value: - referenceable_operator - operator: + - name: simple_identifier "sum" - parameter: - function_parameter - parameter: - parameter - external_name: simple_identifier "_" - name: simple_identifier "values" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + integerLiteralExpr + literal: integerLiteral "0" + trailingComma: , + labeledExpr + expression: + declReferenceExpr + baseName: binaryOperator "+" + additionalTrailingClosures: + calledExpression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "reduce" + base: + declReferenceExpr + baseName: identifier "values" + returnKeyword: return + name: identifier "sum" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + ellipsis: ... + firstName: _ + secondName: identifier "values" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func --- @@ -60,12 +78,31 @@ top_level block stmt: function_declaration + name: identifier "sum" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "values" + return_type: + named_type_expr + name: identifier "Int" body: block stmt: return_expr value: call_expr + callee: + member_access_expr + base: + name_expr + identifier: identifier "values" + member: identifier "reduce" argument: argument value: int_literal "0" @@ -73,19 +110,3 @@ top_level value: name_expr identifier: identifier "+" - callee: - member_access_expr - base: - name_expr - identifier: identifier "values" - member: identifier "reduce" - name: identifier "sum" - parameter: - parameter - external_name: identifier "_" - pattern: - name_pattern - identifier: identifier "values" - return_type: - named_type_expr - name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/literals/boolean-literals.output b/unified/extractor/tests/corpus/swift/literals/boolean-literals.output index d31893de0522..34b394712a35 100644 --- a/unified/extractor/tests/corpus/swift/literals/boolean-literals.output +++ b/unified/extractor/tests/corpus/swift/literals/boolean-literals.output @@ -3,10 +3,17 @@ false --- -source_file - statement: - boolean_literal - boolean_literal +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + booleanLiteralExpr + literal: true + codeBlockItem + item: + booleanLiteralExpr + literal: false --- diff --git a/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output b/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output index 0c374dc4452c..19fa40aac776 100644 --- a/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/floating-point-literal.output @@ -2,8 +2,13 @@ --- -source_file - statement: real_literal "3.14" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + floatLiteralExpr + literal: floatLiteral "3.14" --- diff --git a/unified/extractor/tests/corpus/swift/literals/integer-literal.output b/unified/extractor/tests/corpus/swift/literals/integer-literal.output index 018c57983948..9df79925753c 100644 --- a/unified/extractor/tests/corpus/swift/literals/integer-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/integer-literal.output @@ -2,8 +2,13 @@ --- -source_file - statement: integer_literal "42" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + integerLiteralExpr + literal: integerLiteral "42" --- diff --git a/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output new file mode 100644 index 000000000000..1616055fc16c --- /dev/null +++ b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output @@ -0,0 +1,40 @@ +let currentLine = #line + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + macroExpansionExpr + arguments: + additionalTrailingClosures: + macroName: identifier "line" + pound: # + pattern: + identifierPattern + identifier: identifier "currentLine" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "currentLine" + value: unsupported_node "#line" diff --git a/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift new file mode 100644 index 000000000000..11bb1ab77a92 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift @@ -0,0 +1 @@ +let currentLine = #line diff --git a/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output b/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output index e1ca11e070ab..907944054782 100644 --- a/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/negative-integer-literal.output @@ -2,11 +2,16 @@ --- -source_file - statement: - prefix_expression - operation: - - target: integer_literal "7" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + prefixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "7" + operator: prefixOperator "-" --- diff --git a/unified/extractor/tests/corpus/swift/literals/nil-literal.output b/unified/extractor/tests/corpus/swift/literals/nil-literal.output index 6c826cabe7db..c7da232131fd 100644 --- a/unified/extractor/tests/corpus/swift/literals/nil-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/nil-literal.output @@ -2,8 +2,13 @@ nil --- -source_file - statement: nil +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + nilLiteralExpr + nilKeyword: nil --- diff --git a/unified/extractor/tests/corpus/swift/literals/string-literal.output b/unified/extractor/tests/corpus/swift/literals/string-literal.output index ca2ac6df325d..8d3ea8e796c0 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-literal.output +++ b/unified/extractor/tests/corpus/swift/literals/string-literal.output @@ -2,10 +2,17 @@ --- -source_file - statement: - line_string_literal - text: line_str_text "hello" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "hello" --- diff --git a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output index eb56fbbbb03f..5207085d174c 100644 --- a/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output +++ b/unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output @@ -2,13 +2,28 @@ --- -source_file - statement: - line_string_literal - interpolation: - interpolated_expression - value: simple_identifier "name" - text: line_str_text "hello " +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "hello " + expressionSegment + leftParen: ( + rightParen: ) + backslash: \ + expressions: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "name" + stringSegment + content: stringSegment --- diff --git a/unified/extractor/tests/corpus/swift/loops/break-and-continue.output b/unified/extractor/tests/corpus/swift/loops/break-and-continue.output index 702cd0cbc68b..7ce869998272 100644 --- a/unified/extractor/tests/corpus/swift/loops/break-and-continue.output +++ b/unified/extractor/tests/corpus/swift/loops/break-and-continue.output @@ -6,51 +6,95 @@ for x in xs { --- -source_file - statement: - for_statement - body: - block - statement: - if_statement - body: - block - statement: - control_transfer_statement - kind: continue - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: < - rhs: integer_literal "0" - if_statement - body: - block - statement: - control_transfer_statement - kind: break - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "100" - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - collection: simple_identifier "xs" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "x" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + continueStmt + continueKeyword: continue + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + ifKeyword: if + codeBlockItem + item: + expressionStmt + expression: + ifExpr + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + breakStmt + breakKeyword: break + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "100" + ifKeyword: if + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "x" + inKeyword: in + forKeyword: for + sequence: + declReferenceExpr + baseName: identifier "xs" --- @@ -59,16 +103,22 @@ top_level block stmt: for_each_stmt + pattern: + name_pattern + identifier: identifier "x" + iterable: + name_expr + identifier: identifier "xs" body: block stmt: if_expr condition: binary_expr - operator: infix_operator "<" left: name_expr identifier: identifier "x" + operator: infix_operator "<" right: int_literal "0" then: block @@ -76,26 +126,20 @@ top_level if_expr condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "100" then: block stmt: break_expr "break" call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" - pattern: - name_pattern - identifier: identifier "x" - iterable: - name_expr - identifier: identifier "xs" diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output b/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output index bb1711a23412..2d8db27bfe85 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-over-array-literal.output @@ -4,30 +4,55 @@ for x in [1, 2, 3] { --- -source_file - statement: - for_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - collection: - array_literal - element: - integer_literal "1" - integer_literal "2" - integer_literal "3" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "x" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "x" + inKeyword: in + forKeyword: for + sequence: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] --- @@ -36,18 +61,6 @@ top_level block stmt: for_each_stmt - body: - block - stmt: - call_expr - argument: - argument - value: - name_expr - identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" pattern: name_pattern identifier: identifier "x" @@ -57,3 +70,15 @@ top_level int_literal "1" int_literal "2" int_literal "3" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output b/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output index 87a0baf328b0..cb8b4e67b68d 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-over-range.output @@ -4,29 +4,47 @@ for i in 0..<10 { --- -source_file - statement: - for_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "i" - collection: - range_expression - end: integer_literal "10" - op: ..< - start: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "i" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "i" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "i" + inKeyword: in + forKeyword: for + sequence: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "..<" + leftOperand: + integerLiteralExpr + literal: integerLiteral "0" + rightOperand: + integerLiteralExpr + literal: integerLiteral "10" --- @@ -35,23 +53,23 @@ top_level block stmt: for_each_stmt + pattern: + name_pattern + identifier: identifier "i" + iterable: + binary_expr + left: int_literal "0" + operator: infix_operator "..<" + right: int_literal "10" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "i" - callee: - name_expr - identifier: identifier "print" - pattern: - name_pattern - identifier: identifier "i" - iterable: - binary_expr - operator: infix_operator "..<" - left: int_literal "0" - right: int_literal "10" diff --git a/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output b/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output index 84e832c2be5d..6659039029f3 100644 --- a/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output +++ b/unified/extractor/tests/corpus/swift/loops/for-in-with-where-clause.output @@ -4,33 +4,53 @@ for x in xs where x > 0 { --- -source_file - statement: - for_statement - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "x" - collection: simple_identifier "xs" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem item: - pattern - bound_identifier: simple_identifier "x" - where: - where_clause - expr: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" - keyword: where_keyword "where" + forStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "x" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + pattern: + identifierPattern + identifier: identifier "x" + whereClause: + whereClause + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whereKeyword: where + inKeyword: in + forKeyword: for + sequence: + declReferenceExpr + baseName: identifier "xs" --- @@ -39,28 +59,28 @@ top_level block stmt: for_each_stmt - body: - block - stmt: - call_expr - argument: - argument - value: - name_expr - identifier: identifier "x" - callee: - name_expr - identifier: identifier "print" pattern: name_pattern identifier: identifier "x" + iterable: + name_expr + identifier: identifier "xs" guard: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" - iterable: - name_expr - identifier: identifier "xs" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: + name_expr + identifier: identifier "x" diff --git a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output index 15b673109f2f..71c49fd2cd10 100644 --- a/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/repeat-while-loop.output @@ -4,25 +4,42 @@ repeat { --- -source_file - statement: - repeat_while_statement - body: - block - statement: - assignment - operator: -= - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + repeatStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "-=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + repeatKeyword: repeat + whileKeyword: while --- @@ -35,15 +52,15 @@ top_level block stmt: compound_assign_expr - operator: infix_operator "-=" target: name_expr identifier: identifier "x" + operator: infix_operator "-=" value: int_literal "1" condition: binary_expr - operator: infix_operator ">" left: name_expr identifier: identifier "x" + operator: infix_operator ">" right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/loops/while-loop.output b/unified/extractor/tests/corpus/swift/loops/while-loop.output index 516ab43a2ee5..1132c6f9f819 100644 --- a/unified/extractor/tests/corpus/swift/loops/while-loop.output +++ b/unified/extractor/tests/corpus/swift/loops/while-loop.output @@ -4,25 +4,43 @@ while x > 0 { --- -source_file - statement: - while_statement - body: - block - statement: - assignment - operator: -= - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" - condition: - if_condition - kind: - comparison_expression - lhs: simple_identifier "x" - op: > - rhs: integer_literal "0" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + whileStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "-=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + conditions: + conditionElement + condition: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator ">" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + whileKeyword: while --- @@ -31,19 +49,19 @@ top_level block stmt: while_stmt + condition: + binary_expr + left: + name_expr + identifier: identifier "x" + operator: infix_operator ">" + right: int_literal "0" body: block stmt: compound_assign_expr - operator: infix_operator "-=" target: name_expr identifier: identifier "x" + operator: infix_operator "-=" value: int_literal "1" - condition: - binary_expr - operator: infix_operator ">" - left: - name_expr - identifier: identifier "x" - right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/operators/addition.output b/unified/extractor/tests/corpus/swift/operators/addition.output index 42c0ca9de617..9ba0f4de4770 100644 --- a/unified/extractor/tests/corpus/swift/operators/addition.output +++ b/unified/extractor/tests/corpus/swift/operators/addition.output @@ -2,12 +2,21 @@ a + b --- -source_file - statement: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "a" + operator: infix_operator "+" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/comparison.output b/unified/extractor/tests/corpus/swift/operators/comparison.output index f9428ad17589..49bb8c996f2c 100644 --- a/unified/extractor/tests/corpus/swift/operators/comparison.output +++ b/unified/extractor/tests/corpus/swift/operators/comparison.output @@ -2,12 +2,21 @@ a < b --- -source_file - statement: - comparison_expression - lhs: simple_identifier "a" - op: < - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "<" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "<" left: name_expr identifier: identifier "a" + operator: infix_operator "<" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output new file mode 100644 index 000000000000..5067671aa997 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output @@ -0,0 +1,48 @@ +postfix operator ^^ +let squared = 3^^ + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + operatorDecl + name: binaryOperator "^^" + fixitySpecifier: postfix + operatorKeyword: operator + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + postfixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "3" + operator: postfixOperator "^^" + pattern: + identifierPattern + identifier: identifier "squared" + +--- + +top_level + body: + block + stmt: + unsupported_node "postfix operator ^^" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "squared" + value: unsupported_node "3^^" diff --git a/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift new file mode 100644 index 000000000000..719517400392 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift @@ -0,0 +1,2 @@ +postfix operator ^^ +let squared = 3^^ diff --git a/unified/extractor/tests/corpus/swift/operators/division.output b/unified/extractor/tests/corpus/swift/operators/division.output index 765549543023..f15dce8e8ea5 100644 --- a/unified/extractor/tests/corpus/swift/operators/division.output +++ b/unified/extractor/tests/corpus/swift/operators/division.output @@ -2,12 +2,21 @@ a / b --- -source_file - statement: - multiplicative_expression - lhs: simple_identifier "a" - op: / - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "/" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "/" left: name_expr identifier: identifier "a" + operator: infix_operator "/" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/equality.output b/unified/extractor/tests/corpus/swift/operators/equality.output index cc891492c75f..7cf139ffa18d 100644 --- a/unified/extractor/tests/corpus/swift/operators/equality.output +++ b/unified/extractor/tests/corpus/swift/operators/equality.output @@ -2,12 +2,21 @@ a == b --- -source_file - statement: - equality_expression - lhs: simple_identifier "a" - op: == - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "==" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "==" left: name_expr identifier: identifier "a" + operator: infix_operator "==" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/logical-and.output b/unified/extractor/tests/corpus/swift/operators/logical-and.output index bf852cd46146..32a71ed1088c 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-and.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-and.output @@ -2,12 +2,21 @@ a && b --- -source_file - statement: - conjunction_expression - lhs: simple_identifier "a" - op: && - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "&&" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "&&" left: name_expr identifier: identifier "a" + operator: infix_operator "&&" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/logical-not.output b/unified/extractor/tests/corpus/swift/operators/logical-not.output index d07e357620fd..1e80aa2ca71e 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-not.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-not.output @@ -2,11 +2,16 @@ --- -source_file - statement: - prefix_expression - operation: bang "!" - target: simple_identifier "a" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + prefixOperatorExpr + expression: + declReferenceExpr + baseName: identifier "a" + operator: prefixOperator "!" --- diff --git a/unified/extractor/tests/corpus/swift/operators/logical-or.output b/unified/extractor/tests/corpus/swift/operators/logical-or.output index e246174844c1..b75d018dea71 100644 --- a/unified/extractor/tests/corpus/swift/operators/logical-or.output +++ b/unified/extractor/tests/corpus/swift/operators/logical-or.output @@ -2,12 +2,21 @@ a || b --- -source_file - statement: - disjunction_expression - lhs: simple_identifier "a" - op: || - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "||" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "||" left: name_expr identifier: identifier "a" + operator: infix_operator "||" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/multiplication.output b/unified/extractor/tests/corpus/swift/operators/multiplication.output index b4c33b132863..387c16439c48 100644 --- a/unified/extractor/tests/corpus/swift/operators/multiplication.output +++ b/unified/extractor/tests/corpus/swift/operators/multiplication.output @@ -2,12 +2,21 @@ a * b --- -source_file - statement: - multiplicative_expression - lhs: simple_identifier "a" - op: * - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "a" + operator: infix_operator "*" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output b/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output index b1467474e7c6..f458c3ef847c 100644 --- a/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output +++ b/unified/extractor/tests/corpus/swift/operators/operator-precedence-addition-and-multiplication.output @@ -2,16 +2,29 @@ a + b * c --- -source_file - statement: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: - multiplicative_expression - lhs: simple_identifier "b" - op: * - rhs: simple_identifier "c" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "b" + rightOperand: + declReferenceExpr + baseName: identifier "c" --- @@ -20,16 +33,16 @@ top_level block stmt: binary_expr - operator: infix_operator "+" left: name_expr identifier: identifier "a" + operator: infix_operator "+" right: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "b" + operator: infix_operator "*" right: name_expr identifier: identifier "c" diff --git a/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output b/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output index dfc60e5b7f72..0324476ce994 100644 --- a/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output +++ b/unified/extractor/tests/corpus/swift/operators/parenthesised-expression.output @@ -2,20 +2,35 @@ --- -source_file - statement: - multiplicative_expression - lhs: - tuple_expression - element: - tuple_expression_item - value: - additive_expression - lhs: simple_identifier "a" - op: + - rhs: simple_identifier "b" - op: * - rhs: simple_identifier "c" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + tupleExpr + leftParen: ( + rightParen: ) + elements: + labeledExpr + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" + rightOperand: + declReferenceExpr + baseName: identifier "c" --- @@ -24,8 +39,8 @@ top_level block stmt: binary_expr - operator: infix_operator "*" left: tuple_expr "(a + b)" + operator: infix_operator "*" right: name_expr identifier: identifier "c" diff --git a/unified/extractor/tests/corpus/swift/operators/partial-range-from.output b/unified/extractor/tests/corpus/swift/operators/partial-range-from.output new file mode 100644 index 000000000000..1b9208cedf8b --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/partial-range-from.output @@ -0,0 +1,40 @@ +let range = 3... + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + postfixOperatorExpr + expression: + integerLiteralExpr + literal: integerLiteral "3" + operator: postfixOperator "..." + pattern: + identifierPattern + identifier: identifier "range" + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "range" + value: unsupported_node "3..." diff --git a/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift b/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift new file mode 100644 index 000000000000..e223dc295165 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift @@ -0,0 +1 @@ +let range = 3... diff --git a/unified/extractor/tests/corpus/swift/operators/range-operator.output b/unified/extractor/tests/corpus/swift/operators/range-operator.output index 03d0290bb7c5..55ed3ab971a7 100644 --- a/unified/extractor/tests/corpus/swift/operators/range-operator.output +++ b/unified/extractor/tests/corpus/swift/operators/range-operator.output @@ -2,12 +2,21 @@ --- -source_file - statement: - range_expression - end: integer_literal "10" - op: ... - start: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "..." + leftOperand: + integerLiteralExpr + literal: integerLiteral "1" + rightOperand: + integerLiteralExpr + literal: integerLiteral "10" --- @@ -16,6 +25,6 @@ top_level block stmt: binary_expr - operator: infix_operator "..." left: int_literal "1" + operator: infix_operator "..." right: int_literal "10" diff --git a/unified/extractor/tests/corpus/swift/operators/subtraction.output b/unified/extractor/tests/corpus/swift/operators/subtraction.output index 69f75e720408..5c6fd51a2d38 100644 --- a/unified/extractor/tests/corpus/swift/operators/subtraction.output +++ b/unified/extractor/tests/corpus/swift/operators/subtraction.output @@ -2,12 +2,21 @@ a - b --- -source_file - statement: - additive_expression - lhs: simple_identifier "a" - op: - - rhs: simple_identifier "b" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "-" + leftOperand: + declReferenceExpr + baseName: identifier "a" + rightOperand: + declReferenceExpr + baseName: identifier "b" --- @@ -16,10 +25,10 @@ top_level block stmt: binary_expr - operator: infix_operator "-" left: name_expr identifier: identifier "a" + operator: infix_operator "-" right: name_expr identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output new file mode 100644 index 000000000000..a0563c7bc88b --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output @@ -0,0 +1,141 @@ +func casts(_ a: Any, _ b: Int) { + _ = a as Int .& b + _ = a is Int .& b +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + unresolvedAsExpr + asKeyword: as + typeExpr + type: + identifierType + name: identifier "Int" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + unresolvedIsExpr + isKeyword: is + typeExpr + type: + identifierType + name: identifier "Int" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + name: identifier "casts" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: Any + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "casts" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Any" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + body: + block + stmt: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator "as" + unsupported_node "Int" + infix_operator ".&" + name_expr + identifier: identifier "b" + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator "is" + unsupported_node "Int" + infix_operator ".&" + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift new file mode 100644 index 000000000000..b22c93eb31e7 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift @@ -0,0 +1,4 @@ +func casts(_ a: Any, _ b: Int) { + _ = a as Int .& b + _ = a is Int .& b +} diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output new file mode 100644 index 000000000000..57274c32a9c2 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output @@ -0,0 +1,157 @@ +func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int { + return c ? a : b .& d +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + sequenceExpr + elements: + declReferenceExpr + baseName: identifier "c" + unresolvedTernaryExpr + colon: : + questionMark: ? + thenExpression: + declReferenceExpr + baseName: identifier "a" + declReferenceExpr + baseName: identifier "b" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "d" + returnKeyword: return + name: identifier "choose" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Bool" + firstName: _ + secondName: identifier "c" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "d" + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "choose" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Bool" + pattern: + name_pattern + identifier: identifier "c" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "d" + return_type: + named_type_expr + name: identifier "Int" + body: + block + stmt: + return_expr + value: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "c" + infix_operator "?" + name_expr + identifier: identifier "a" + infix_operator ":" + name_expr + identifier: identifier "b" + infix_operator ".&" + name_expr + identifier: identifier "d" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift new file mode 100644 index 000000000000..54f164eee9a2 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift @@ -0,0 +1,3 @@ +func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int { + return c ? a : b .& d +} diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output new file mode 100644 index 000000000000..46dc8ca6ae89 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output @@ -0,0 +1,100 @@ +func combine(_ a: Int, _ b: Int) { + _ = a .& b +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + sequenceExpr + elements: + discardAssignmentExpr + wildcard: _ + assignmentExpr + equal: = + declReferenceExpr + baseName: identifier "a" + binaryOperatorExpr + operator: binaryOperator ".&" + declReferenceExpr + baseName: identifier "b" + name: identifier "combine" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "a" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: _ + secondName: identifier "b" + funcKeyword: func + +--- + +top_level + body: + block + stmt: + function_declaration + name: identifier "combine" + parameter: + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "a" + parameter + external_name: identifier "_" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "b" + body: + block + stmt: + unresolved_operator_sequence + element: + name_expr + identifier: identifier "_" + infix_operator "=" + name_expr + identifier: identifier "a" + infix_operator ".&" + name_expr + identifier: identifier "b" diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift new file mode 100644 index 000000000000..6ab759752d28 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift @@ -0,0 +1,3 @@ +func combine(_ a: Int, _ b: Int) { + _ = a .& b +} diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output new file mode 100644 index 000000000000..79b7879d35fa --- /dev/null +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output @@ -0,0 +1,207 @@ +do { + try foo() +} catch let e where isNetworkError(e), let f where isTimeout(f) { + print("retry") +} catch { + print("fallback") +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + doStmt + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + tryKeyword: try + catchClauses: + catchClause + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "retry" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + catchItems: + catchItem + trailingComma: , + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "e" + bindingSpecifier: let + whereClause: + whereClause + condition: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "e" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "isNetworkError" + whereKeyword: where + catchItem + pattern: + valueBindingPattern + pattern: + identifierPattern + identifier: identifier "f" + bindingSpecifier: let + whereClause: + whereClause + condition: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "f" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "isTimeout" + whereKeyword: where + catchKeyword: catch + catchClause + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment "fallback" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + catchItems: + catchKeyword: catch + doKeyword: do + +--- + +top_level + body: + block + stmt: + try_expr + body: + block + stmt: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try" + catch_clause: + catch_clause + pattern: + or_pattern + pattern: + conditional_pattern + condition: + call_expr + callee: + name_expr + identifier: identifier "isNetworkError" + argument: + argument + value: + name_expr + identifier: identifier "e" + pattern: + name_pattern + identifier: identifier "e" + conditional_pattern + condition: + call_expr + callee: + name_expr + identifier: identifier "isTimeout" + argument: + argument + value: + name_expr + identifier: identifier "f" + pattern: + name_pattern + identifier: identifier "f" + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"retry\"" + catch_clause + body: + block + stmt: + call_expr + callee: + name_expr + identifier: identifier "print" + argument: + argument + value: string_literal "\"fallback\"" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift new file mode 100644 index 000000000000..48995b818e51 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift @@ -0,0 +1,7 @@ +do { + try foo() +} catch let e where isNetworkError(e), let f where isTimeout(f) { + print("retry") +} catch { + print("fallback") +} diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output index c807bd9b7b9c..81491b295fc1 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/do-catch.output @@ -6,37 +6,54 @@ do { --- -source_file - statement: - do_statement - body: - block - statement: - try_expression - expr: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix - arguments: - value_arguments - operator: - try_operator - catch: - catch_block +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + doStmt body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "error" - keyword: catch_keyword "catch" + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + tryKeyword: try + catchClauses: + catchClause + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "error" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + catchItems: + catchKeyword: catch + doKeyword: do --- @@ -61,11 +78,11 @@ top_level block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "error" - callee: - name_expr - identifier: identifier "print" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output index 96fb627e18b1..2c6fd1a6f763 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/force-unwrap.output @@ -2,21 +2,29 @@ let n = opt! --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - postfix_expression - operation: bang "!" - target: simple_identifier "opt" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + forceUnwrapExpr + expression: + declReferenceExpr + baseName: identifier "opt" + exclamationMark: ! + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output index 81a9a9187c04..31a039ad0065 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/nil-coalescing.output @@ -2,21 +2,34 @@ let n = opt ?? 0 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - nil_coalescing_expression - if_nil: integer_literal "0" - value: simple_identifier "opt" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "??" + leftOperand: + declReferenceExpr + baseName: identifier "opt" + rightOperand: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "n" --- @@ -31,8 +44,8 @@ top_level identifier: identifier "n" value: binary_expr - operator: infix_operator "??" left: name_expr identifier: identifier "opt" + operator: infix_operator "??" right: int_literal "0" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output index 6c5b27a64fe2..b69b0ae47d50 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-chaining.output @@ -2,32 +2,44 @@ let n = obj?.foo?.bar --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "bar" - target: - optional_chain_marker - expr: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "foo" - target: - optional_chain_marker - expr: simple_identifier "obj" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "bar" + base: + optionalChainingExpr + expression: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "foo" + base: + optionalChainingExpr + expression: + declReferenceExpr + baseName: identifier "obj" + questionMark: ? + questionMark: ? + pattern: + identifierPattern + identifier: identifier "n" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output index 06191891496e..1927b494ef9a 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/optional-type-annotation.output @@ -2,29 +2,35 @@ let x: Int? = nil --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - optional_type - wrapped: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: nil +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + nilLiteralExpr + nilKeyword: nil + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + optionalType + wrappedType: + identifierType + name: identifier "Int" + questionMark: ? --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output index f1240bd0b3ef..e68b4c3c57ac 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/throwing-function.output @@ -4,25 +4,50 @@ func read() throws -> String { --- -source_file - statement: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - line_string_literal - name: simple_identifier "read" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" - throws: throws "throws" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + stringLiteralExpr + closingQuote: " + openingQuote: " + segments: + stringSegment + content: stringSegment + returnKeyword: return + name: identifier "read" + modifiers: + signature: + functionSignature + effectSpecifiers: + functionEffectSpecifiers + throwsClause: + throwsClause + throwsSpecifier: throws + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "String" + funcKeyword: func --- @@ -31,12 +56,12 @@ top_level block stmt: function_declaration + name: identifier "read" + return_type: + named_type_expr + name: identifier "String" body: block stmt: return_expr value: string_literal "\"\"" - name: identifier "read" - return_type: - named_type_expr - name: identifier "String" diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output index 9d5ff032d75c..aafc0c67c217 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression-2.output @@ -2,28 +2,36 @@ let result = try! foo() --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "result" - value: - try_expression - expr: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix - arguments: - value_arguments - operator: - try_operator +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + questionOrExclamationMark: ! + tryKeyword: try + pattern: + identifierPattern + identifier: identifier "result" --- diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output index e6a7bfef3444..5b1b0b24d0fa 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/try-expression.output @@ -2,28 +2,36 @@ let result = try? foo() --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "result" - value: - try_expression - expr: - call_expression - function: simple_identifier "foo" - suffix: - call_suffix - arguments: - value_arguments - operator: - try_operator +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + tryExpr + expression: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "foo" + questionOrExclamationMark: ? + tryKeyword: try + pattern: + identifierPattern + identifier: identifier "result" --- diff --git a/unified/extractor/tests/corpus/swift/types/actor-declaration.output b/unified/extractor/tests/corpus/swift/types/actor-declaration.output new file mode 100644 index 000000000000..b4fcd605b9e9 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/actor-declaration.output @@ -0,0 +1,45 @@ +actor Counter { + var value = 0 +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + actorDecl + attributes: + name: identifier "Counter" + actorKeyword: actor + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "value" + modifiers: + +--- + +top_level + body: + block + stmt: unsupported_node "actor Counter {\n var value = 0\n}" diff --git a/unified/extractor/tests/corpus/swift/types/actor-declaration.swift b/unified/extractor/tests/corpus/swift/types/actor-declaration.swift new file mode 100644 index 000000000000..a4c13e4e8761 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/actor-declaration.swift @@ -0,0 +1,3 @@ +actor Counter { + var value = 0 +} diff --git a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output index 4ee195672bb2..c05bc7794437 100644 --- a/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output +++ b/unified/extractor/tests/corpus/swift/types/binding-modifier-does-not-leak-into-accessor-body.output @@ -11,54 +11,84 @@ var p: Int { --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - computed_value: - computed_property - accessor: - computed_getter - body: - block - statement: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: simple_identifier "someConstant" - statement: - control_transfer_statement - kind: return - result: integer_literal "1" - switch_entry - default: default_keyword "default" - statement: - control_transfer_statement - kind: return - result: integer_literal "2" - expr: simple_identifier "y" - specifier: - getter_specifier - name: - pattern - bound_identifier: simple_identifier "p" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "p" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + expressionStmt + expression: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + declReferenceExpr + baseName: identifier "someConstant" + statements: + codeBlockItem + item: + returnStmt + expression: + integerLiteralExpr + literal: integerLiteral "1" + returnKeyword: return + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + returnStmt + expression: + integerLiteralExpr + literal: integerLiteral "2" + returnKeyword: return + subject: + declReferenceExpr + baseName: identifier "y" + switchKeyword: switch + leftBrace: { + rightBrace: } --- @@ -67,34 +97,34 @@ top_level block stmt: accessor_declaration + modifier: modifier "var" + name: identifier "p" + accessor_kind: accessor_kind "get" + type: + named_type_expr + name: identifier "Int" body: block stmt: switch_expr + value: + name_expr + identifier: identifier "y" case: switch_case - body: - block - stmt: - return_expr - value: int_literal "1" pattern: expr_equality_pattern expr: name_expr identifier: identifier "someConstant" + body: + block + stmt: + return_expr + value: int_literal "1" switch_case body: block stmt: return_expr value: int_literal "2" - value: - name_expr - identifier: identifier "y" - modifier: modifier "var" - name: identifier "p" - type: - named_type_expr - name: identifier "Int" - accessor_kind: accessor_kind "get" diff --git a/unified/extractor/tests/corpus/swift/types/class-inheritance.output b/unified/extractor/tests/corpus/swift/types/class-inheritance.output index e90cccc4a8b6..12328f4acb0d 100644 --- a/unified/extractor/tests/corpus/swift/types/class-inheritance.output +++ b/unified/extractor/tests/corpus/swift/types/class-inheritance.output @@ -2,20 +2,29 @@ class Dog: Animal {} --- -source_file - statement: - class_declaration - body: - class_body - declaration_kind: class - inherits: - inheritance_specifier - inherits_from: - user_type - part: - simple_user_type - name: type_identifier "Animal" - name: type_identifier "Dog" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Dog" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + type: + identifierType + name: identifier "Animal" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + modifiers: + classKeyword: class --- @@ -26,3 +35,8 @@ top_level class_like_declaration modifier: modifier "class" name: identifier "Dog" + base_type: + base_type + type: + named_type_expr + name: identifier "Animal" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output index 13e0097172cc..83945d89e3a0 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output @@ -7,60 +7,82 @@ class Point { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - init_declaration - body: - block - statement: - assignment - operator: = - result: simple_identifier "x" - target: - directly_assignable_expression - expr: - navigation_expression - suffix: - navigation_suffix - suffix: simple_identifier "x" - target: - self_expression - parameter: - function_parameter - parameter: - parameter - name: simple_identifier "x" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: class - name: type_identifier "Point" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Point" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + memberBlockItem + decl: + initializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + assignmentExpr + equal: = + leftOperand: + memberAccessExpr + period: . + declName: + declReferenceExpr + baseName: identifier "x" + base: + declReferenceExpr + baseName: self + rightOperand: + declReferenceExpr + baseName: identifier "x" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + initKeyword: init + modifiers: + classKeyword: class --- @@ -69,6 +91,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Point" member: variable_declaration modifier: modifier "var" @@ -79,6 +103,14 @@ top_level named_type_expr name: identifier "Int" constructor_declaration + parameter: + parameter + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "x" body: block stmt: @@ -92,5 +124,3 @@ top_level value: name_expr identifier: identifier "x" - modifier: modifier "class" - name: identifier "Point" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-method.output b/unified/extractor/tests/corpus/swift/types/class-with-method.output index 770030d884a7..f45cb31e53ad 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-method.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-method.output @@ -7,35 +7,69 @@ class Counter { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "n" - value: integer_literal "0" - function_declaration - body: - block - statement: - assignment - operator: += - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "n" - name: simple_identifier "bump" - declaration_kind: class - name: type_identifier "Counter" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Counter" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "n" + memberBlockItem + decl: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+=" + leftOperand: + declReferenceExpr + baseName: identifier "n" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" + name: identifier "bump" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + modifiers: + classKeyword: class --- @@ -44,6 +78,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Counter" member: variable_declaration modifier: modifier "var" @@ -52,15 +88,13 @@ top_level identifier: identifier "n" value: int_literal "0" function_declaration + name: identifier "bump" body: block stmt: compound_assign_expr - operator: infix_operator "+=" target: name_expr identifier: identifier "n" + operator: infix_operator "+=" value: int_literal "1" - name: identifier "bump" - modifier: modifier "class" - name: identifier "Counter" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output new file mode 100644 index 000000000000..e66b88e9be3d --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output @@ -0,0 +1,51 @@ +class Button: Control, Drawable {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Button" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + trailingComma: , + type: + identifierType + name: identifier "Control" + inheritedType + type: + identifierType + name: identifier "Drawable" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + modifiers: + classKeyword: class + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "Button" + base_type: + base_type + type: + named_type_expr + name: identifier "Control" + base_type + type: + named_type_expr + name: identifier "Drawable" diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift new file mode 100644 index 000000000000..b4f45e5c7a03 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift @@ -0,0 +1 @@ +class Button: Control, Drawable {} diff --git a/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output b/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output index 9d28afe6ae0e..e184426eb755 100644 --- a/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output +++ b/unified/extractor/tests/corpus/swift/types/class-with-stored-properties.output @@ -5,50 +5,55 @@ class Point { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: class - name: type_identifier "Point" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Point" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "y" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + modifiers: + classKeyword: class --- @@ -57,6 +62,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Point" member: variable_declaration modifier: modifier "var" @@ -74,5 +81,3 @@ top_level type: named_type_expr name: identifier "Int" - modifier: modifier "class" - name: identifier "Point" diff --git a/unified/extractor/tests/corpus/swift/types/computed-property.output b/unified/extractor/tests/corpus/swift/types/computed-property.output index 8803e652d316..24e816be0091 100644 --- a/unified/extractor/tests/corpus/swift/types/computed-property.output +++ b/unified/extractor/tests/corpus/swift/types/computed-property.output @@ -8,78 +8,92 @@ class Rect { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "w" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "h" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - computed_value: - computed_property - statement: - control_transfer_statement - kind: return - result: - multiplicative_expression - lhs: simple_identifier "w" - op: * - rhs: simple_identifier "h" - name: - pattern - bound_identifier: simple_identifier "area" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - declaration_kind: class - name: type_identifier "Rect" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Rect" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "w" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Double" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "h" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Double" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "area" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Double" + accessorBlock: + accessorBlock + accessors: + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: identifier "w" + rightOperand: + declReferenceExpr + baseName: identifier "h" + returnKeyword: return + leftBrace: { + rightBrace: } + modifiers: + classKeyword: class --- @@ -88,6 +102,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Rect" member: variable_declaration modifier: modifier "var" @@ -106,24 +122,22 @@ top_level named_type_expr name: identifier "Double" accessor_declaration + modifier: modifier "var" + name: identifier "area" + accessor_kind: accessor_kind "get" + type: + named_type_expr + name: identifier "Double" body: block stmt: return_expr value: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "w" + operator: infix_operator "*" right: name_expr identifier: identifier "h" - modifier: modifier "var" - name: identifier "area" - type: - named_type_expr - name: identifier "Double" - accessor_kind: accessor_kind "get" - modifier: modifier "class" - name: identifier "Rect" diff --git a/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output new file mode 100644 index 000000000000..2c530111b9ca --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output @@ -0,0 +1,87 @@ +// Conditional compilation is not yet supported: swift-syntax reports a +// structured `ifConfigDecl` (whose branches hold ordinary member items), but +// the mapping has no rule for it, so the whole block becomes one +// `unsupported_node` and its members are not extracted. +class C { +#if DEBUG + init(x: Int) {} + deinit {} +#endif +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "C" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + ifConfigDecl + clauses: + ifConfigClause + elements: + memberBlockItem + decl: + initializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "x" + initKeyword: init + memberBlockItem + decl: + deinitializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + modifiers: + deinitKeyword: deinit + condition: + declReferenceExpr + baseName: identifier "DEBUG" + poundKeyword: #if + poundEndif: #endif + modifiers: + classKeyword: class + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "C" + member: unsupported_node "#if DEBUG\n init(x: Int) {}\n deinit {}\n#endif" diff --git a/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift new file mode 100644 index 000000000000..fe50583118c9 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift @@ -0,0 +1,10 @@ +// Conditional compilation is not yet supported: swift-syntax reports a +// structured `ifConfigDecl` (whose branches hold ordinary member items), but +// the mapping has no rule for it, so the whole block becomes one +// `unsupported_node` and its members are not extracted. +class C { +#if DEBUG + init(x: Int) {} + deinit {} +#endif +} diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output new file mode 100644 index 000000000000..c9be21dd156a --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output @@ -0,0 +1,88 @@ +struct Size { + init(width w: Int, height h: Int) {} +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "Size" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + initializerDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + functionParameter + colon: : + attributes: + modifiers: + trailingComma: , + type: + identifierType + name: identifier "Int" + firstName: identifier "width" + secondName: identifier "w" + functionParameter + colon: : + attributes: + modifiers: + type: + identifierType + name: identifier "Int" + firstName: identifier "height" + secondName: identifier "h" + initKeyword: init + modifiers: + structKeyword: struct + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "struct" + name: identifier "Size" + member: + constructor_declaration + parameter: + parameter + external_name: identifier "width" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "w" + parameter + external_name: identifier "height" + type: + named_type_expr + name: identifier "Int" + pattern: + name_pattern + identifier: identifier "h" + body: block "init(width w: Int, height h: Int) {}" diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift new file mode 100644 index 000000000000..4f6377fc7803 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift @@ -0,0 +1,3 @@ +struct Size { + init(width w: Int, height h: Int) {} +} diff --git a/unified/extractor/tests/corpus/swift/types/empty-class.output b/unified/extractor/tests/corpus/swift/types/empty-class.output index 761de778543d..6693744c9b43 100644 --- a/unified/extractor/tests/corpus/swift/types/empty-class.output +++ b/unified/extractor/tests/corpus/swift/types/empty-class.output @@ -2,13 +2,21 @@ class Foo {} --- -source_file - statement: - class_declaration - body: - class_body - declaration_kind: class - name: type_identifier "Foo" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Foo" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + modifiers: + classKeyword: class --- diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output index 12b5191f69f9..399239bbea30 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-associated-values.output @@ -5,46 +5,63 @@ enum Shape { --- -source_file - statement: - class_declaration - body: - enum_class_body - member: - enum_entry - case: - enum_case_entry - data_contents: - enum_type_parameters - parameter: - enum_type_parameter - name: simple_identifier "radius" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - name: simple_identifier "circle" - enum_entry - case: - enum_case_entry - data_contents: - enum_type_parameters - parameter: - enum_type_parameter - name: simple_identifier "side" - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Double" - name: simple_identifier "square" - declaration_kind: enum - name: type_identifier "Shape" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + enumDecl + attributes: + name: identifier "Shape" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "circle" + parameterClause: + enumCaseParameterClause + leftParen: ( + rightParen: ) + parameters: + enumCaseParameter + colon: : + modifiers: + type: + identifierType + name: identifier "Double" + firstName: identifier "radius" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "square" + parameterClause: + enumCaseParameterClause + leftParen: ( + rightParen: ) + parameters: + enumCaseParameter + colon: : + modifiers: + type: + identifierType + name: identifier "Double" + firstName: identifier "side" + caseKeyword: case + modifiers: + enumKeyword: enum --- @@ -53,34 +70,34 @@ top_level block stmt: class_like_declaration + modifier: modifier "enum" + name: identifier "Shape" member: class_like_declaration + modifier: modifier "enum_case" + name: identifier "circle" member: constructor_declaration - body: block "circle(radius: Double)" parameter: parameter - pattern: - name_pattern - identifier: identifier "radius" type: named_type_expr name: identifier "Double" - modifier: modifier "enum_case" - name: identifier "circle" + pattern: + name_pattern + identifier: identifier "radius" + body: block "circle(radius: Double)" class_like_declaration + modifier: modifier "enum_case" + name: identifier "square" member: constructor_declaration - body: block "square(side: Double)" parameter: parameter - pattern: - name_pattern - identifier: identifier "side" type: named_type_expr name: identifier "Double" - modifier: modifier "enum_case" - name: identifier "square" - modifier: modifier "enum" - name: identifier "Shape" + pattern: + name_pattern + identifier: identifier "side" + body: block "square(side: Double)" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output index 72435fd2b1f7..f081c2a82046 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-cases.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-cases.output @@ -7,30 +7,57 @@ enum Direction { --- -source_file - statement: - class_declaration - body: - enum_class_body - member: - enum_entry - case: - enum_case_entry - name: simple_identifier "north" - enum_entry - case: - enum_case_entry - name: simple_identifier "south" - enum_entry - case: - enum_case_entry - name: simple_identifier "east" - enum_entry - case: - enum_case_entry - name: simple_identifier "west" - declaration_kind: enum - name: type_identifier "Direction" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + enumDecl + attributes: + name: identifier "Direction" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "north" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "south" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "east" + caseKeyword: case + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "west" + caseKeyword: case + modifiers: + enumKeyword: enum --- @@ -39,6 +66,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "enum" + name: identifier "Direction" member: variable_declaration modifier: modifier "enum_case" @@ -60,5 +89,3 @@ top_level pattern: name_pattern identifier: identifier "west" - modifier: modifier "enum" - name: identifier "Direction" diff --git a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output index 6a4aac4b552d..6a4ea95e9a62 100644 --- a/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/enum-with-comma-separated-cases-chained-declaration.output @@ -4,24 +4,39 @@ enum Suit { --- -source_file - statement: - class_declaration - body: - enum_class_body - member: - enum_entry - case: - enum_case_entry - name: simple_identifier "clubs" - enum_case_entry - name: simple_identifier "diamonds" - enum_case_entry - name: simple_identifier "hearts" - enum_case_entry - name: simple_identifier "spades" - declaration_kind: enum - name: type_identifier "Suit" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + enumDecl + attributes: + name: identifier "Suit" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + enumCaseDecl + attributes: + modifiers: + elements: + enumCaseElement + name: identifier "clubs" + trailingComma: , + enumCaseElement + name: identifier "diamonds" + trailingComma: , + enumCaseElement + name: identifier "hearts" + trailingComma: , + enumCaseElement + name: identifier "spades" + caseKeyword: case + modifiers: + enumKeyword: enum --- @@ -30,6 +45,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "enum" + name: identifier "Suit" member: variable_declaration modifier: modifier "enum_case" @@ -57,5 +74,3 @@ top_level pattern: name_pattern identifier: identifier "spades" - modifier: modifier "enum" - name: identifier "Suit" diff --git a/unified/extractor/tests/corpus/swift/types/extension.output b/unified/extractor/tests/corpus/swift/types/extension.output index ad663cb86e16..1b1d02ebddad 100644 --- a/unified/extractor/tests/corpus/swift/types/extension.output +++ b/unified/extractor/tests/corpus/swift/types/extension.output @@ -4,39 +4,63 @@ extension Int { --- -source_file - statement: - class_declaration - body: - class_body - member: - function_declaration - body: - block - statement: - control_transfer_statement - kind: return - result: - multiplicative_expression - lhs: - self_expression - op: * - rhs: - self_expression - name: simple_identifier "squared" - return_type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: extension - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + extensionDecl + attributes: + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + functionDecl + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "*" + leftOperand: + declReferenceExpr + baseName: self + rightOperand: + declReferenceExpr + baseName: self + returnKeyword: return + name: identifier "squared" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Int" + funcKeyword: func + modifiers: + extendedType: + identifierType + name: identifier "Int" + extensionKeyword: extension --- @@ -45,24 +69,24 @@ top_level block stmt: class_like_declaration + modifier: modifier "extension" + name: identifier "Int" member: function_declaration + name: identifier "squared" + return_type: + named_type_expr + name: identifier "Int" body: block stmt: return_expr value: binary_expr - operator: infix_operator "*" left: name_expr identifier: identifier "self" + operator: infix_operator "*" right: name_expr identifier: identifier "self" - name: identifier "squared" - return_type: - named_type_expr - name: identifier "Int" - modifier: modifier "extension" - name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output new file mode 100644 index 000000000000..3d484d6f65d8 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output @@ -0,0 +1,73 @@ +let callback: @convention(c) () -> Void = {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + statements: + pattern: + identifierPattern + identifier: identifier "callback" + typeAnnotation: + typeAnnotation + colon: : + type: + attributedType + attributes: + attribute + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "c" + atSign: @ + attributeName: + identifierType + name: identifier "convention" + baseType: + functionType + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Void" + lateSpecifiers: + specifiers: + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "callback" + type: unsupported_node "@convention(c) () -> Void" + value: + function_expr + body: block "{}" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift new file mode 100644 index 000000000000..f84fa5270093 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift @@ -0,0 +1 @@ +let callback: @convention(c) () -> Void = {} diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output new file mode 100644 index 000000000000..ef9f838dadbe --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output @@ -0,0 +1,66 @@ +let handler: @Sendable () -> Void = {} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + closureExpr + leftBrace: { + rightBrace: } + statements: + pattern: + identifierPattern + identifier: identifier "handler" + typeAnnotation: + typeAnnotation + colon: : + type: + attributedType + attributes: + attribute + atSign: @ + attributeName: + identifierType + name: identifier "Sendable" + baseType: + functionType + leftParen: ( + rightParen: ) + parameters: + returnClause: + returnClause + arrow: -> + type: + identifierType + name: identifier "Void" + lateSpecifiers: + specifiers: + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "handler" + type: unsupported_node "@Sendable () -> Void" + value: + function_expr + body: block "{}" diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift new file mode 100644 index 000000000000..00810b921e84 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift @@ -0,0 +1 @@ +let handler: @Sendable () -> Void = {} diff --git a/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output new file mode 100644 index 000000000000..ce12c853d9d5 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output @@ -0,0 +1,83 @@ +let cache: Dictionary> = [:] + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + dictionaryExpr + leftSquare: [ + rightSquare: ] + content: : + pattern: + identifierPattern + identifier: identifier "cache" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Dictionary" + genericArgumentClause: + genericArgumentClause + arguments: + genericArgument + trailingComma: , + argument: + identifierType + name: identifier "String" + genericArgument + argument: + identifierType + name: identifier "Array" + genericArgumentClause: + genericArgumentClause + arguments: + genericArgument + argument: + identifierType + name: identifier "Int" + leftAngle: < + rightAngle: > + leftAngle: < + rightAngle: > + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "cache" + type: + generic_type_expr + base: + named_type_expr + name: identifier "Dictionary" + type_argument: + named_type_expr + name: identifier "String" + generic_type_expr + base: + named_type_expr + name: identifier "Array" + type_argument: + named_type_expr + name: identifier "Int" + value: map_literal "[:]" diff --git a/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift new file mode 100644 index 000000000000..d2156f9cee76 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift @@ -0,0 +1 @@ +let cache: Dictionary> = [:] diff --git a/unified/extractor/tests/corpus/swift/types/inline-array-type.output b/unified/extractor/tests/corpus/swift/types/inline-array-type.output new file mode 100644 index 000000000000..5f70d9d55168 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/inline-array-type.output @@ -0,0 +1,77 @@ +let triple: [3 of Int] = [1, 2, 3] + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + arrayExpr + elements: + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "1" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "2" + trailingComma: , + arrayElement + expression: + integerLiteralExpr + literal: integerLiteral "3" + leftSquare: [ + rightSquare: ] + pattern: + identifierPattern + identifier: identifier "triple" + typeAnnotation: + typeAnnotation + colon: : + type: + inlineArrayType + leftSquare: [ + rightSquare: ] + element: + genericArgument + argument: + identifierType + name: identifier "Int" + count: + genericArgument + argument: + integerLiteralExpr + literal: integerLiteral "3" + separator: of + +--- + +top_level + body: + block + stmt: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "triple" + type: unsupported_node "[3 of Int]" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" diff --git a/unified/extractor/tests/corpus/swift/types/inline-array-type.swift b/unified/extractor/tests/corpus/swift/types/inline-array-type.swift new file mode 100644 index 000000000000..3d27c8dca5c5 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/inline-array-type.swift @@ -0,0 +1 @@ +let triple: [3 of Int] = [1, 2, 3] diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.output b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output new file mode 100644 index 000000000000..4fb13ca13ece --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output @@ -0,0 +1,71 @@ +struct FileHandle: ~Copyable { + let descriptor: Int +} + +--- + +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "FileHandle" + inheritanceClause: + inheritanceClause + colon: : + inheritedTypes: + inheritedType + type: + suppressedType + type: + identifierType + name: identifier "Copyable" + withoutTilde: prefixOperator "~" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "descriptor" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + modifiers: + structKeyword: struct + +--- + +top_level + body: + block + stmt: + class_like_declaration + modifier: modifier "struct" + name: identifier "FileHandle" + base_type: + base_type + type: unsupported_node "~Copyable" + member: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "descriptor" + type: + named_type_expr + name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift b/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift new file mode 100644 index 000000000000..55390c9e6d13 --- /dev/null +++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift @@ -0,0 +1,3 @@ +struct FileHandle: ~Copyable { + let descriptor: Int +} diff --git a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output index 0a8b2d8cc5d7..951768cd8444 100644 --- a/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output +++ b/unified/extractor/tests/corpus/swift/types/property-with-getter-and-setter.output @@ -8,70 +8,97 @@ class Box { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "_v" - value: integer_literal "0" - modifiers: - modifiers - modifier: - visibility_modifier - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - computed_value: - computed_property - accessor: - computed_getter - body: - block - statement: - control_transfer_statement - kind: return - result: simple_identifier "_v" - specifier: - getter_specifier - computed_setter - body: - block - statement: - assignment - operator: = - result: simple_identifier "newValue" - target: - directly_assignable_expression - expr: simple_identifier "_v" - specifier: - setter_specifier - name: - pattern - bound_identifier: simple_identifier "v" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: class - name: type_identifier "Box" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "Box" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + declModifier + name: private + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "_v" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "v" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + returnStmt + expression: + declReferenceExpr + baseName: identifier "_v" + returnKeyword: return + accessorDecl + accessorSpecifier: set + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + assignmentExpr + equal: = + leftOperand: + declReferenceExpr + baseName: identifier "_v" + rightOperand: + declReferenceExpr + baseName: identifier "newValue" + leftBrace: { + rightBrace: } + modifiers: + classKeyword: class --- @@ -80,14 +107,24 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "Box" member: variable_declaration - modifier: modifier "var" + modifier: + modifier "var" + modifier "private" pattern: name_pattern identifier: identifier "_v" value: int_literal "0" accessor_declaration + modifier: modifier "var" + name: identifier "v" + accessor_kind: accessor_kind "get" + type: + named_type_expr + name: identifier "Int" body: block stmt: @@ -95,13 +132,15 @@ top_level value: name_expr identifier: identifier "_v" - modifier: modifier "var" + accessor_declaration + modifier: + modifier "var" + modifier "chained_declaration" name: identifier "v" + accessor_kind: accessor_kind "set" type: named_type_expr name: identifier "Int" - accessor_kind: accessor_kind "get" - accessor_declaration body: block stmt: @@ -112,13 +151,3 @@ top_level value: name_expr identifier: identifier "newValue" - modifier: - modifier "var" - modifier "chained_declaration" - name: identifier "v" - type: - named_type_expr - name: identifier "Int" - accessor_kind: accessor_kind "set" - modifier: modifier "class" - name: identifier "Box" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output index 55a71218c18c..e848fb23eb3f 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-declaration.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-declaration.output @@ -4,15 +4,35 @@ protocol Drawable { --- -source_file - statement: - protocol_declaration - body: - protocol_body - member: - protocol_function_declaration - name: simple_identifier "draw" - name: type_identifier "Drawable" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + protocolDecl + attributes: + name: identifier "Drawable" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + functionDecl + attributes: + name: identifier "draw" + modifiers: + signature: + functionSignature + parameterClause: + functionParameterClause + leftParen: ( + rightParen: ) + parameters: + funcKeyword: func + modifiers: + protocolKeyword: protocol --- @@ -21,9 +41,9 @@ top_level block stmt: class_like_declaration + modifier: modifier "protocol" + name: identifier "Drawable" member: function_declaration - body: block "func draw()" name: identifier "draw" - modifier: modifier "protocol" - name: identifier "Drawable" + body: block "func draw()" diff --git a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output index 0293534adf76..83362740bb1e 100644 --- a/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output +++ b/unified/extractor/tests/corpus/swift/types/protocol-with-read-only-and-read-write-property-requirements.output @@ -5,54 +5,74 @@ protocol P { --- -source_file - statement: - protocol_declaration - body: - protocol_body - member: - protocol_property_declaration - name: - pattern - binding: - value_binding_pattern - mutability: var - bound_identifier: simple_identifier "foo" - requirements: - protocol_property_requirements - accessor: - getter_specifier - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - protocol_property_declaration - name: - pattern - binding: - value_binding_pattern - mutability: var - bound_identifier: simple_identifier "bar" - requirements: - protocol_property_requirements - accessor: - getter_specifier - setter_specifier - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "String" - name: type_identifier "P" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + protocolDecl + attributes: + name: identifier "P" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "foo" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + leftBrace: { + rightBrace: } + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "bar" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "String" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: get + attributes: + accessorDecl + accessorSpecifier: set + attributes: + leftBrace: { + rightBrace: } + modifiers: + protocolKeyword: protocol --- @@ -61,25 +81,25 @@ top_level block stmt: class_like_declaration + modifier: modifier "protocol" + name: identifier "P" member: accessor_declaration name: identifier "foo" + accessor_kind: accessor_kind "get" type: named_type_expr name: identifier "Int" - accessor_kind: accessor_kind "get" accessor_declaration name: identifier "bar" + accessor_kind: accessor_kind "get" type: named_type_expr name: identifier "String" - accessor_kind: accessor_kind "get" accessor_declaration modifier: modifier "chained_declaration" name: identifier "bar" + accessor_kind: accessor_kind "set" type: named_type_expr name: identifier "String" - accessor_kind: accessor_kind "set" - modifier: modifier "protocol" - name: identifier "P" diff --git a/unified/extractor/tests/corpus/swift/types/struct.output b/unified/extractor/tests/corpus/swift/types/struct.output index e130ef9b8623..57fb25c9e193 100644 --- a/unified/extractor/tests/corpus/swift/types/struct.output +++ b/unified/extractor/tests/corpus/swift/types/struct.output @@ -5,50 +5,55 @@ struct Point { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - declaration_kind: struct - name: type_identifier "Point" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + structDecl + attributes: + name: identifier "Point" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "y" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + modifiers: + structKeyword: struct --- @@ -57,6 +62,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "struct" + name: identifier "Point" member: variable_declaration modifier: modifier "let" @@ -74,5 +81,3 @@ top_level type: named_type_expr name: identifier "Int" - modifier: modifier "struct" - name: identifier "Point" diff --git a/unified/extractor/tests/corpus/swift/variables/assignment.output b/unified/extractor/tests/corpus/swift/variables/assignment.output index 9d1a61e89a82..a011eb76cafc 100644 --- a/unified/extractor/tests/corpus/swift/variables/assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/assignment.output @@ -2,14 +2,21 @@ x = 1 --- -source_file - statement: - assignment - operator: = - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + assignmentExpr + equal: = + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" --- diff --git a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output index 65364c1ef918..d159cd6b37cb 100644 --- a/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output +++ b/unified/extractor/tests/corpus/swift/variables/binding-modifier-does-not-leak-into-initializer.output @@ -5,31 +5,59 @@ default: 2 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: - switch_statement - entry: - switch_entry - pattern: - switch_pattern - pattern: - pattern - kind: simple_identifier "someConstant" - statement: integer_literal "1" - switch_entry - default: default_keyword "default" - statement: integer_literal "2" - expr: simple_identifier "y" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + switchExpr + leftBrace: { + rightBrace: } + cases: + switchCase + label: + switchCaseLabel + colon: : + caseKeyword: case + caseItems: + switchCaseItem + pattern: + expressionPattern + expression: + declReferenceExpr + baseName: identifier "someConstant" + statements: + codeBlockItem + item: + integerLiteralExpr + literal: integerLiteral "1" + switchCase + label: + switchDefaultLabel + colon: : + defaultKeyword: default + statements: + codeBlockItem + item: + integerLiteralExpr + literal: integerLiteral "2" + subject: + declReferenceExpr + baseName: identifier "y" + switchKeyword: switch + pattern: + identifierPattern + identifier: identifier "x" --- @@ -44,20 +72,20 @@ top_level identifier: identifier "x" value: switch_expr + value: + name_expr + identifier: identifier "y" case: switch_case - body: - block - stmt: int_literal "1" pattern: expr_equality_pattern expr: name_expr identifier: identifier "someConstant" + body: + block + stmt: int_literal "1" switch_case body: block stmt: int_literal "2" - value: - name_expr - identifier: identifier "y" diff --git a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output index 95b7edb0a6ba..485b5044ad69 100644 --- a/unified/extractor/tests/corpus/swift/variables/compound-assignment.output +++ b/unified/extractor/tests/corpus/swift/variables/compound-assignment.output @@ -2,14 +2,21 @@ x += 1 --- -source_file - statement: - assignment - operator: += - result: integer_literal "1" - target: - directly_assignable_expression - expr: simple_identifier "x" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + infixOperatorExpr + operator: + binaryOperatorExpr + operator: binaryOperator "+=" + leftOperand: + declReferenceExpr + baseName: identifier "x" + rightOperand: + integerLiteralExpr + literal: integerLiteral "1" --- @@ -18,8 +25,8 @@ top_level block stmt: compound_assign_expr - operator: infix_operator "+=" target: name_expr identifier: identifier "x" + operator: infix_operator "+=" value: int_literal "1" diff --git a/unified/extractor/tests/corpus/swift/variables/let-binding.output b/unified/extractor/tests/corpus/swift/variables/let-binding.output index b8b16dc80144..4774eb3eeca8 100644 --- a/unified/extractor/tests/corpus/swift/variables/let-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/let-binding.output @@ -2,18 +2,26 @@ let x = 1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output b/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output index 3fd78d09fa42..a56feb445ace 100644 --- a/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output +++ b/unified/extractor/tests/corpus/swift/variables/let-with-type-annotation.output @@ -2,27 +2,32 @@ let x: Int = 1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" --- diff --git a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output index 7f202885b9be..9470a578ad62 100644 --- a/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output +++ b/unified/extractor/tests/corpus/swift/variables/multiple-bindings-on-one-line.output @@ -2,23 +2,37 @@ let x = 1, y = 2 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" - property_binding - name: - pattern - bound_identifier: simple_identifier "y" - value: integer_literal "2" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + trailingComma: , + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "2" + pattern: + identifierPattern + identifier: identifier "y" --- diff --git a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output index 2d612e1d950e..8071d5d52900 100644 --- a/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output +++ b/unified/extractor/tests/corpus/swift/variables/property-with-willset-and-didset-observers.output @@ -7,63 +7,93 @@ class C { --- -source_file - statement: - class_declaration - body: - class_body - member: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - observers: - willset_didset_block - didset: - didset_clause - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "oldValue" - willset: - willset_clause - body: - block - statement: - call_expression - function: simple_identifier "print" - suffix: - call_suffix - arguments: - value_arguments - argument: - value_argument - value: simple_identifier "newValue" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" - value: integer_literal "0" - declaration_kind: class - name: type_identifier "C" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + classDecl + attributes: + name: identifier "C" + memberBlock: + memberBlock + leftBrace: { + rightBrace: } + members: + memberBlockItem + decl: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "0" + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" + accessorBlock: + accessorBlock + accessors: + accessorDecl + accessorSpecifier: willSet + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "newValue" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + accessorDecl + accessorSpecifier: didSet + attributes: + body: + codeBlock + leftBrace: { + rightBrace: } + statements: + codeBlockItem + item: + functionCallExpr + leftParen: ( + rightParen: ) + arguments: + labeledExpr + expression: + declReferenceExpr + baseName: identifier "oldValue" + additionalTrailingClosures: + calledExpression: + declReferenceExpr + baseName: identifier "print" + leftBrace: { + rightBrace: } + modifiers: + classKeyword: class --- @@ -72,6 +102,8 @@ top_level block stmt: class_like_declaration + modifier: modifier "class" + name: identifier "C" member: variable_declaration modifier: modifier "var" @@ -83,40 +115,38 @@ top_level name: identifier "Int" value: int_literal "0" accessor_declaration + modifier: + modifier "var" + modifier "chained_declaration" + name: identifier "x" + accessor_kind: accessor_kind "willSet" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "newValue" - callee: - name_expr - identifier: identifier "print" + accessor_declaration modifier: modifier "var" modifier "chained_declaration" name: identifier "x" - accessor_kind: accessor_kind "willSet" - accessor_declaration + accessor_kind: accessor_kind "didSet" body: block stmt: call_expr + callee: + name_expr + identifier: identifier "print" argument: argument value: name_expr identifier: identifier "oldValue" - callee: - name_expr - identifier: identifier "print" - modifier: - modifier "var" - modifier "chained_declaration" - name: identifier "x" - accessor_kind: accessor_kind "didSet" - modifier: modifier "class" - name: identifier "C" diff --git a/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output b/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output index 5709911171c1..6b6bd81115ed 100644 --- a/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/tuple-destructuring-binding.output @@ -2,28 +2,37 @@ let (a, b) = pair --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: let - declarator: - property_binding - name: - pattern - kind: - tuple_pattern - item: - tuple_pattern_item +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: let + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + declReferenceExpr + baseName: identifier "pair" + pattern: + tuplePattern + leftParen: ( + rightParen: ) + elements: + tuplePatternElement + trailingComma: , pattern: - pattern - kind: simple_identifier "a" - tuple_pattern_item + identifierPattern + identifier: identifier "a" + tuplePatternElement pattern: - pattern - kind: simple_identifier "b" - value: simple_identifier "pair" + identifierPattern + identifier: identifier "b" --- diff --git a/unified/extractor/tests/corpus/swift/variables/var-binding.output b/unified/extractor/tests/corpus/swift/variables/var-binding.output index b7dc8e772700..63498105dc75 100644 --- a/unified/extractor/tests/corpus/swift/variables/var-binding.output +++ b/unified/extractor/tests/corpus/swift/variables/var-binding.output @@ -2,18 +2,26 @@ var x = 1 --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - value: integer_literal "1" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + initializer: + initializerClause + equal: = + value: + integerLiteralExpr + literal: integerLiteral "1" + pattern: + identifierPattern + identifier: identifier "x" --- diff --git a/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output b/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output index 692befea8553..d841ce2bb583 100644 --- a/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output +++ b/unified/extractor/tests/corpus/swift/variables/var-without-initialiser.output @@ -2,26 +2,26 @@ var x: Int --- -source_file - statement: - property_declaration - binding: - value_binding_pattern - mutability: var - declarator: - property_binding - name: - pattern - bound_identifier: simple_identifier "x" - type: - type_annotation - type: - type - name: - user_type - part: - simple_user_type - name: type_identifier "Int" +sourceFile + endOfFileToken: endOfFile + statements: + codeBlockItem + item: + variableDecl + attributes: + modifiers: + bindingSpecifier: var + bindings: + patternBinding + pattern: + identifierPattern + identifier: identifier "x" + typeAnnotation: + typeAnnotation + colon: : + type: + identifierType + name: identifier "Int" --- diff --git a/unified/extractor/tests/corpus_tests.rs b/unified/extractor/tests/corpus_tests.rs index ac93f06622cf..b2700b999b7c 100644 --- a/unified/extractor/tests/corpus_tests.rs +++ b/unified/extractor/tests/corpus_tests.rs @@ -1,8 +1,8 @@ use std::fs; use std::path::Path; -use codeql_extractor::extractor::simple; -use yeast::{Runner, dump::dump_ast, dump::dump_ast_with_type_errors}; +use codeql_extractor::extractor::desugaring; +use yeast::{dump::dump_ast, dump::dump_ast_with_type_errors}; #[path = "../src/languages/mod.rs"] mod languages; @@ -20,6 +20,20 @@ fn update_mode_enabled() -> bool { .unwrap_or(false) } +/// Whether the external swift-syntax parser is available. When the parser +/// binary genuinely cannot be found/launched (e.g. no Swift toolchain, and +/// neither `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` nor a `swift-syntax-parse` +/// on `PATH`), the corpus test is skipped rather than failed — it cannot run +/// without the Swift-backed parser. +/// +/// Crucially this checks only that the executable *launches*: a parser that is +/// present but crashes, emits invalid JSON, or otherwise regresses is +/// considered available, so the suite runs and fails (rather than silently +/// skipping the very failures CI needs to catch). +fn parser_available() -> bool { + languages::swift_parse::binary_available() +} + /// Parse a corpus `.output` file. The file holds a single test case made of /// three sections separated by `---` delimiter lines: /// @@ -28,7 +42,7 @@ fn update_mode_enabled() -> bool { /// /// --- /// -/// +/// /// /// --- /// @@ -59,40 +73,21 @@ fn render_corpus(case: &CorpusCase) -> String { ) } -fn run_desugaring(lang: &simple::LanguageSpec, input: &str) -> Result { - match lang.desugar.as_deref() { - Some(desugarer) => { - // Parse the input ourselves so we don't depend on the desugarer - // knowing about the language. - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&lang.ts_language) - .map_err(|e| format!("Failed to set language: {e}"))?; - let tree = parser - .parse(input, None) - .ok_or_else(|| "Failed to parse input".to_string())?; - desugarer - .run_from_tree(&tree, input.as_bytes()) - .map_err(|e| format!("Desugaring failed: {e}")) - } - None => { - let runner: Runner = Runner::new(lang.ts_language.clone(), &[]); - runner - .run(input) - .map_err(|e| format!("Failed to parse input: {e}")) - } - } +/// Parse `input` through the language's parser and desugar it, returning the +/// mapped AST. +fn run_desugaring(lang: &desugaring::LanguageSpec, input: &str) -> Result { + let parsed = (lang.parser)(input.as_bytes())?; + lang.desugarer + .run_from_ast(parsed.ast) + .map_err(|e| format!("Desugaring failed: {e}")) } -/// Produce the raw tree-sitter parse tree dump for `input`, with no -/// desugaring rules applied. Uses a `Runner` with an empty phase list and -/// the input grammar's own schema. -fn dump_raw_parse(lang: &simple::LanguageSpec, input: &str) -> Result { - let runner: Runner = Runner::new(lang.ts_language.clone(), &[]); - let ast = runner - .run(input) - .map_err(|e| format!("Failed to parse input: {e}"))?; - Ok(dump_ast(&ast, ast.get_root(), input)) +/// Produce the raw (pre-desugar) parse tree dump for `input` — the `yeast::Ast` +/// the language's parser builds, before any desugaring rules. Useful for seeing +/// what the mapping rules operate on. +fn dump_raw_parse(lang: &desugaring::LanguageSpec, input: &str) -> Result { + let parsed = (lang.parser)(input.as_bytes())?; + Ok(dump_ast(&parsed.ast, parsed.ast.get_root(), input)) } /// Collect the set of corpus test "stems" (paths without an extension) under @@ -117,16 +112,21 @@ fn collect_corpus_stems(dir: &Path, out: &mut Vec) { #[test] fn test_corpus() { + if !parser_available() { + eprintln!( + "skipping test_corpus: the swift-syntax parser is unavailable \ + (set CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE or put \ + `swift-syntax-parse` on PATH)" + ); + return; + } let update_mode = update_mode_enabled(); let all_languages = languages::all_language_specs(); let corpus_dir = Path::new("tests/corpus"); for lang in all_languages { - let output_schema = yeast::node_types_yaml::schema_from_yaml_with_language( - languages::OUTPUT_AST_SCHEMA, - &lang.ts_language, - ) - .expect("Failed to parse OUTPUT_AST_SCHEMA YAML"); + let output_schema = yeast::node_types_yaml::schema_from_yaml(languages::OUTPUT_AST_SCHEMA) + .expect("Failed to parse OUTPUT_AST_SCHEMA YAML"); let lang_corpus_dir = corpus_dir.join(&lang.prefix); if !lang_corpus_dir.exists() { @@ -236,8 +236,7 @@ fn test_corpus() { ); if update_mode { case.expected = actual_dump.trim().to_string(); - } else if output_path.exists() - && case.expected.trim() != actual_dump.trim() + } else if output_path.exists() && case.expected.trim() != actual_dump.trim() { failures.push(format!( "Test failed in {}:\nEXPECTED:\n\n{}\n\nACTUAL:\n\n{}", diff --git a/unified/extractor/tests/rules_macro_smoke.rs b/unified/extractor/tests/rules_macro_smoke.rs deleted file mode 100644 index cde8ae3ca4ab..000000000000 --- a/unified/extractor/tests/rules_macro_smoke.rs +++ /dev/null @@ -1,25 +0,0 @@ -/// Smoke test: load a few real Swift translation rules through the new -/// `yeast::rules!` macro using the bare-rule-body syntax, and confirm the -/// input + output schemas accept them. Compiles only — any type-checking -/// error surfaces as a compile-time error. -#[test] -fn rules_macro_compiles_against_real_swift_schemas() { - let _rules: Vec = yeast::rules! { - input: "tree-sitter-swift/node-types.yml", - output: "ast_types.yml", - [ - (simple_identifier) @name - => - (name_expr - identifier: (identifier #{name})), - - (integer_literal) @lit - => - (int_literal #{lit}), - - (line_string_literal) @lit - => - (string_literal #{lit}), - ] - }; -} diff --git a/unified/extractor/tests/swift_syntax_pipeline.rs b/unified/extractor/tests/swift_syntax_pipeline.rs index cdaae1f47c6e..fde060f98203 100644 --- a/unified/extractor/tests/swift_syntax_pipeline.rs +++ b/unified/extractor/tests/swift_syntax_pipeline.rs @@ -22,7 +22,7 @@ fn swift_syntax_json_runs_through_the_desugarer() { .into_iter() .find(|l| l.file_globs.iter().any(|g| g.contains("swift"))) .expect("swift language spec"); - let desugarer = lang.desugar.as_deref().expect("swift desugarer"); + let desugarer = lang.desugarer.as_ref(); // Adapt the swift-syntax JSON into a yeast AST (pure Rust, no Swift FFI). let adapted = diff --git a/unified/extractor/tree-sitter-swift/.gitignore b/unified/extractor/tree-sitter-swift/.gitignore deleted file mode 100644 index 53796875297e..000000000000 --- a/unified/extractor/tree-sitter-swift/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -# Generated by tree-sitter from grammar.js. The Cargo build script -# (bindings/rust/build.rs) and Bazel's cargo_build_script regenerate them into -# OUT_DIR. The tree-sitter CLI (parse, test, playground, etc.) expects them in -# src/, so contributors can run `tree-sitter generate` locally to populate -# these — they are intentionally untracked. -src/parser.c -src/grammar.json -src/node-types.json -src/tree_sitter/ diff --git a/unified/extractor/tree-sitter-swift/BUILD.bazel b/unified/extractor/tree-sitter-swift/BUILD.bazel deleted file mode 100644 index f865f22a1420..000000000000 --- a/unified/extractor/tree-sitter-swift/BUILD.bazel +++ /dev/null @@ -1,42 +0,0 @@ -load("@rules_rust//cargo:defs.bzl", "cargo_build_script") -load("@rules_rust//rust:defs.bzl", "rust_library") -load("//misc/bazel/3rdparty/tree_sitter_extractors_deps:defs.bzl", "aliases", "all_crate_deps") - -package(default_visibility = ["//visibility:public"]) - -# This will run the build script from the root of the workspace, and -# collect the outputs. -cargo_build_script( - name = "tree-sitter-swift-build", - srcs = ["bindings/rust/build.rs"], - data = glob([ - "src/scanner.c", - ]) + [ - "grammar.js", - ], - deps = all_crate_deps( - build = True, - ), -) - -rust_library( - name = "tree-sitter-swift", - srcs = [ - "bindings/rust/lib.rs", - ], - aliases = aliases(), - compile_data = glob([ - "src/**", - "queries/**", - ]) + [ - "grammar.js", - ], - proc_macro_deps = all_crate_deps( - proc_macro = True, - ), - deps = [":tree-sitter-swift-build"] + all_crate_deps( - normal = True, - ), -) - -exports_files(["Cargo.toml"]) diff --git a/unified/extractor/tree-sitter-swift/Cargo.toml b/unified/extractor/tree-sitter-swift/Cargo.toml deleted file mode 100644 index 8cec03889a83..000000000000 --- a/unified/extractor/tree-sitter-swift/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "tree-sitter-swift" -description = "Swift grammar for the tree-sitter parsing library (vendored copy for the unified extractor)" -version = "0.7.2" -keywords = ["incremental", "parsing", "swift"] -categories = ["parsing", "text-editors"] -repository = "https://github.com/alex-pinkus/tree-sitter-swift" -edition = "2024" -license = "MIT" - -build = "bindings/rust/build.rs" - -[lib] -path = "bindings/rust/lib.rs" - -# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh` -[dependencies] -tree-sitter-language = "0.1" - -[build-dependencies] -cc = "1.2" -tree-sitter-generate = "0.26.8" diff --git a/unified/extractor/tree-sitter-swift/LICENSE b/unified/extractor/tree-sitter-swift/LICENSE deleted file mode 100644 index f158d7005311..000000000000 --- a/unified/extractor/tree-sitter-swift/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 alex-pinkus - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/unified/extractor/tree-sitter-swift/README.md b/unified/extractor/tree-sitter-swift/README.md deleted file mode 100644 index 5b54f4b617f6..000000000000 --- a/unified/extractor/tree-sitter-swift/README.md +++ /dev/null @@ -1,127 +0,0 @@ -![Parse rate badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/parse_rate) -[![Crates.io badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/crates_io_version)](https://crates.io/crates/tree-sitter-swift) -[![NPM badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/npm_version)](https://www.npmjs.com/package/tree-sitter-swift) -[![Build](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml/badge.svg)](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml) - -# tree-sitter-swift - -This contains a [`tree-sitter`](https://tree-sitter.github.io/tree-sitter) grammar for the Swift programming language. - -## Getting started - -To use this parser to parse Swift code, you'll want to depend on either the Rust crate or the NPM package. - -### Rust - -To use the Rust crate, you'll add this to your `Cargo.toml`: - -``` -tree-sitter = "0.23.0" -tree-sitter-swift = "=0.7.0" -``` - -Then you can use a `tree-sitter` parser with the language declared here: - -``` -let mut parser = tree_sitter::Parser::new(); -parser.set_language(tree_sitter_swift::language())?; - -// ... - -let tree = parser.parse(&my_source_code, None) - .ok_or_else(|| /* error handling code */)?; -``` - -### Javascript - -To use this from NPM, you'll add similar dependencies to `package.json`: - -``` -"dependencies: { - "tree-sitter-swift": "0.7.0", - "tree-sitter": "^0.22.1" -} -``` - -Your usage of the parser will look like: - -``` -const Parser = require("tree-sitter"); -const Swift = require("tree-sitter-swift"); - -const parser = new Parser(); -parser.setLanguage(Swift); - -// ... - -const tree = parser.parse(mySourceCode); -``` - -### Editing the grammar - -With this package checked out, a common workflow for editing the grammar will look something like: - -1. Make a change to `grammar.ts`. -2. Run `npm install && npm test` to see whether the change has had impact on existing parsing behavior. The default - `npm test` target requires `valgrind` to be installed; if you do not have it installed, and do not wish to, you can - substitute `tree-sitter test` directly. -3. Run `tree-sitter parse` on some real Swift codebase and see whether (or where) it fails. -4. Use any failures to create new corpus test cases. - -## Contributions - -All contributions to this repository are welcome. - -If said contribution is to check generated files (e.g., `parser.c`) into the repository, be aware that your contribution will not be accepted. Make sure to read the [FAQ entry](https://github.com/alex-pinkus/tree-sitter-swift?tab=readme-ov-file#where-is-your-parserc) and the [prior](https://github.com/alex-pinkus/tree-sitter-swift/issues/362) [discussions](https://github.com/alex-pinkus/tree-sitter-swift/pull/315) and [compromises](https://github.com/alex-pinkus/tree-sitter-swift/issues/149) that have occurred already on this topic. - -## Using tree-sitter-swift in Web Assembly - -To use tree-sitter-swift as a language for the web bindings version tree-sitter, which will likely be a more modern version than the published node -module. [see](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md). Follow the instructions below - -1. Install the node modules `npm install web-tree-sitter tree-sitter-swift` -2. Run the tree-sitter cli to create the wasm bundle - ```sh - $ npx tree-sitter build-asm ./node_modules/tree-sitter - ``` -3. Boot tree-sitter wasm like this. - -```js -const Parser = require("web-tree-sitter"); -async function run() { - //needs to happen first - await Parser.init(); - //wait for the load of swift - const Swift = await Parser.Language.load("./tree-sitter-swift.wasm"); - - const parser = new Parser(); - parser.setLanguage(Swift); - - //Parse your swift code here. - const tree = parser.parse('print("Hello, World!")'); -} -//if you want to run this -run().then(console.log, console.error); -``` - -## Frequently asked questions - -### Where is your `parser.c`? - -This repository currently omits most of the code that is autogenerated during a build. This means, for instance, that -`grammar.json` and `parser.c` are both only available following a build. It also significantly reduces noise during -diffs. - -The side benefit of not checking in `parser.c` is that you can guarantee backwards compatibility. Parsers generated by -the tree-sitter CLI aren't always backwards compatible. If you need a parser, generate it yourself using the CLI; all -the information to do so is available in this package. By doing that, you'll also know for sure that your parser version -and your library version are compatible. - -If you need a `parser.c`, and you don't care about the tree-sitter version, but you don't have a local setup that would -allow you to obtain the parser, you can just download one from a recent workflow run in this package. To do so: - -- Go to the [GitHub actions page](https://github.com/alex-pinkus/tree-sitter-swift/actions) for this - repository. -- Click on the "Publish `grammar.json` and `parser.c`" action for the appropriate commit. -- Go down to `Artifacts` and click on `generated-parser-src`. All the relevant parser files will be available in your - download. diff --git a/unified/extractor/tree-sitter-swift/binding.gyp b/unified/extractor/tree-sitter-swift/binding.gyp deleted file mode 100644 index 4d9270af7d47..000000000000 --- a/unified/extractor/tree-sitter-swift/binding.gyp +++ /dev/null @@ -1,44 +0,0 @@ -{ - "targets": [ - { - "target_name": "tree_sitter_swift_binding", - "dependencies": [ - " - -typedef struct TSLanguage TSLanguage; - -extern "C" TSLanguage *tree_sitter_swift(); - -// "tree-sitter", "language" hashed with BLAKE2 -const napi_type_tag LANGUAGE_TYPE_TAG = { - 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 -}; - -Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports["name"] = Napi::String::New(env, "swift"); - auto language = Napi::External::New(env, tree_sitter_swift()); - language.TypeTag(&LANGUAGE_TYPE_TAG); - exports["language"] = language; - return exports; -} - -NODE_API_MODULE(tree_sitter_swift_binding, Init) diff --git a/unified/extractor/tree-sitter-swift/bindings/node/index.js b/unified/extractor/tree-sitter-swift/bindings/node/index.js deleted file mode 100644 index 6657bcf42dec..000000000000 --- a/unified/extractor/tree-sitter-swift/bindings/node/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const root = require("path").join(__dirname, "..", ".."); - -module.exports = require("node-gyp-build")(root); - -try { - module.exports.nodeTypeInfo = require("../../src/node-types.json"); -} catch (_) {} diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs b/unified/extractor/tree-sitter-swift/bindings/rust/build.rs deleted file mode 100644 index 2dd899ea5213..000000000000 --- a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::env; -use std::path::PathBuf; - -fn main() { - // tree-sitter-generate produces parser.c, grammar.json, node-types.json, - // and src/tree_sitter/*.h headers from grammar.js. We write them into - // OUT_DIR so the build is sandbox-friendly and we don't litter the source - // tree. - let crate_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into(); - let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into(); - let grammar_js = crate_dir.join("grammar.js"); - - tree_sitter_generate::generate_parser_in_directory( - &crate_dir, - Some(&out_dir), - Some(&grammar_js), - tree_sitter_generate::ABI_VERSION_MAX, - None, - // Evaluate grammar.js with the embedded QuickJS runtime instead of - // spawning `node`, which isn't available inside Bazel's sandbox. - Some("native"), - true, - tree_sitter_generate::OptLevel::default(), - ) - .expect("failed to generate tree-sitter-swift parser"); - - let mut c_config = cc::Build::new(); - c_config - .std("c11") - .include(&out_dir) - .include(out_dir.join("tree_sitter")); - - #[cfg(target_env = "msvc")] - c_config.flag("-utf-8"); - - c_config.file(out_dir.join("parser.c")); - - // scanner.c is hand-written and lives in the source tree. - let scanner_path = crate_dir.join("src").join("scanner.c"); - c_config.include(crate_dir.join("src")).file(&scanner_path); - - println!("cargo:rerun-if-changed={}", grammar_js.to_str().unwrap()); - println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); - // Re-export OUT_DIR so consumers can include_str! the generated files. - println!( - "cargo:rustc-env=TREE_SITTER_SWIFT_OUT_DIR={}", - out_dir.to_str().unwrap() - ); - - c_config.compile("tree-sitter-swift"); -} diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs b/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs deleted file mode 100644 index 891df87778f0..000000000000 --- a/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! This crate provides Swift language support for the [tree-sitter][] parsing library. -//! -//! Typically, you will use the [language][language func] function to add this language to a -//! tree-sitter [Parser][], and then use the parser to parse some code: -//! -//! ``` -//! let code = r#" -//! "#; -//! let mut parser = tree_sitter::Parser::new(); -//! let language = tree_sitter_swift::LANGUAGE; -//! parser -//! .set_language(&language.into()) -//! .expect("Error loading Swift parser"); -//! let tree = parser.parse(code, None).unwrap(); -//! assert!(!tree.root_node().has_error()); -//! ``` -//! -//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html -//! [language func]: fn.language.html -//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html -//! [tree-sitter]: https://tree-sitter.github.io/ - -use tree_sitter_language::LanguageFn; - -unsafe extern "C" { - fn tree_sitter_swift() -> *const (); -} - -/// The tree-sitter [`LanguageFn`] for this grammar. -pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_swift) }; - -/// The content of the [`node-types.json`][] file for this grammar. -/// -/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types -pub const NODE_TYPES: &str = include_str!(concat!(env!("TREE_SITTER_SWIFT_OUT_DIR"), "/node-types.json")); - -pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); -pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); -pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); -pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); - -#[cfg(test)] -mod tests { - #[test] - fn test_can_load_grammar() { - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&super::LANGUAGE.into()) - .expect("Error loading Swift parser"); - } - - #[test] - fn test_can_parse_basic_file() { - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&super::LANGUAGE.into()) - .expect("Error loading Swift parser"); - - let tree = parser - .parse("_ = \"Hello!\"\n", None) - .expect("Unable to parse!"); - - assert_eq!( - "(source_file (assignment target: (directly_assignable_expression (simple_identifier)) result: (line_string_literal text: (line_str_text))))", - tree.root_node().to_sexp(), - ); - } -} diff --git a/unified/extractor/tree-sitter-swift/grammar.js b/unified/extractor/tree-sitter-swift/grammar.js deleted file mode 100644 index 7052d2ebdd5b..000000000000 --- a/unified/extractor/tree-sitter-swift/grammar.js +++ /dev/null @@ -1,2113 +0,0 @@ -"use strict"; -/* - * MIT License - * - * Copyright (c) 2021 alex-pinkus - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -const PRECS = { - multiplication: 11, - addition: 10, - infix_operations: 9, - nil_coalescing: 8, - check: 7, - prefix_operations: 7, - comparison: 6, - postfix_operations: 6, - equality: 5, - conjunction: 4, - disjunction: 3, - block: 2, - loop: 1, - keypath: 1, - parameter_pack: 1, - control_transfer: 0, - as: -1, - tuple: -1, - if: -1, - switch: -1, - do: -1, - fully_open_range: -1, - range: -1, - navigation: -1, - expr: -1, - ty: -1, - call: -2, - ternary: -2, - try: -2, - call_suffix: -2, - range_suffix: -2, - ternary_binary_suffix: -2, - await: -2, - assignment: -3, - comment: -3, - lambda: -3, - regex: -4, -}; - -const DYNAMIC_PRECS = { - call: 1, -}; - -const DEC_DIGITS = token(sep1(/[0-9]+/, /_+/)); -const HEX_DIGITS = token(sep1(/[0-9a-fA-F]+/, /_+/)); -const OCT_DIGITS = token(sep1(/[0-7]+/, /_+/)); -const BIN_DIGITS = token(sep1(/[01]+/, /_+/)); -const REAL_EXPONENT = token(seq(/[eE]/, optional(/[+-]/), DEC_DIGITS)); -const HEX_REAL_EXPONENT = token(seq(/[pP]/, optional(/[+-]/), DEC_DIGITS)); - -var LEXICAL_IDENTIFIER; - -if (tree_sitter_version_supports_emoji()) { - LEXICAL_IDENTIFIER = - /[_\p{XID_Start}\p{Emoji}&&[^0-9#*]](\p{EMod}|\x{FE0F}\x{20E3}?)?([_\p{XID_Continue}\p{Emoji}\x{200D}](\p{EMod}|\x{FE0F}\x{20E3}?)?)*/; -} else { - LEXICAL_IDENTIFIER = /[_\p{XID_Start}][_\p{XID_Continue}]*/; -} - -module.exports = grammar({ - name: "swift", - supertypes: ($) => [ - $.expression, - $.unannotated_type, - $.global_declaration, - $.type_level_declaration, - $.local_declaration, - $.protocol_member_declaration, - ], - conflicts: ($) => [ - // @Type(... could either be an annotation constructor invocation or an annotated expression - [$.attribute], - [$._attribute_argument], - // Is `foo { ... }` a constructor invocation or function invocation? - [$.simple_user_type, $.expression], - // To support nested types A.B not being interpreted as `(navigation_expression ... (type_identifier)) (navigation_suffix)` - [$.user_type], - // How to tell the difference between Foo.bar(with:and:), and Foo.bar(with: smth, and: other)? You need GLR - [$.value_argument], - // { (foo, bar) ... - [$.expression, $.lambda_parameter], - [$._primary_expression, $.lambda_parameter], - // (foo) where foo could be a binding pattern or a tuple expression item. - [$._binding_pattern_with_expr, $.tuple_expression_item], - // After a `{` in a function or switch context, it's ambigous whether we're starting a set of local statements or - // applying some modifiers to a capture or pattern. - [$.modifiers], - // `+(...)` is ambigously either "call the function produced by a reference to the operator `+`" or "use the unary - // operator `+` on the result of the parenthetical expression." - [$._additive_operator, $._prefix_unary_operator], - [$.referenceable_operator, $._prefix_unary_operator], - // `{ [self, b, c] ...` could be a capture list or an array literal depending on what else happens. - [$.capture_list_item, $.expression], - [$.capture_list_item, $.expression, $.simple_user_type], - [$._primary_expression, $.capture_list_item], - // a ? b : c () could be calling c(), or it could be calling a function that's produced by the result of - // `(a ? b : c)`. We have a small hack to force it to be the former of these by intentionally introducing a - // conflict. - [$.call_suffix, $.expr_hack_at_ternary_binary_call_suffix], - // try {expression} is a bit magic and applies quite broadly: `try foo()` and `try foo { }` show that this is right - // associative, and `try foo ? bar() : baz` even more so. But it doesn't always win: something like - // `if try foo { } ...` should award its braces to the `if`. In order to make this actually happen, we need to parse - // all the options and pick the best one that doesn't error out. - [$.try_expression, $._unary_expression], - [$.try_expression, $.expression], - // await {expression} has the same special cases as `try`. - [$.await_expression, $._unary_expression], - [$.await_expression, $.expression], - // In a computed property, when you see an @attribute, it's not yet clear if that's going to be for a - // locally-declared class or a getter / setter specifier. - [ - $._local_property_declaration, - $._local_typealias_declaration, - $._local_function_declaration, - $._local_class_declaration, - $.computed_getter, - $.computed_modify, - $.computed_setter, - ], - // The `class` modifier is legal in many of the same positions that a class declaration itself would be. - [$._bodyless_function_declaration, $.property_modifier], - [$.init_declaration, $.property_modifier], - // Patterns, man - [$._navigable_type_expression, $.case_pattern], - [$._no_expr_pattern_already_bound, $._binding_pattern_no_expr], - - // On encountering a closure starting with `{ @Foo ...`, we don't yet know if that attribute applies to the closure - // type or to a declaration within the closure. What a mess! We just have to hope that if we keep going, only one of - // those will parse (because there will be an `in` or a `let`). - [ - $._lambda_type_declaration, - $._local_property_declaration, - $._local_typealias_declaration, - $._local_function_declaration, - $._local_class_declaration, - ], - - // We want `foo() { }` to be treated as one function call, but we _also_ want `if foo() { ... }` to be treated as a - // full if-statement. This means we have to treat it as a conflict rather than purely a left or right associative - // construct, and let the parser realize that the second expression won't parse properly with the `{ ... }` as a - // lambda. - [$.constructor_suffix], - [$.call_suffix], - - // `actor` is allowed to be an identifier, even though it is also a locally permitted declaration. If we encounter - // it, the only way to know what it's meant to be is to keep going. - [$._modifierless_class_declaration, $.property_modifier], - [$._fn_call_lambda_arguments], - - // `borrowing` and `consuming` are legal as identifiers, but are also legal modifiers - [$.parameter_modifiers], - - // These are keywords sometimes, but simple identifiers other times, and it just depends on the rest of their usage. - [$._contextual_simple_identifier, $._modifierless_class_declaration], - [$._contextual_simple_identifier, $.property_behavior_modifier], - [$._contextual_simple_identifier, $.parameter_modifier], - [$._contextual_simple_identifier, $.type_parameter_pack], - [$._contextual_simple_identifier, $.type_pack_expansion], - [$._contextual_simple_identifier, $.visibility_modifier], - ], - extras: ($) => [ - $.comment, - $.multiline_comment, - /\s+/, // Whitespace - ], - externals: ($) => [ - // Comments and raw strings are parsed in a custom scanner because they require us to carry forward state to - // maintain symmetry. For instance, parsing a multiline comment requires us to increment a counter whenever we see - // `/*`, and decrement it whenever we see `*/`. A standard grammar would only be able to exit the comment at the - // first `*/` (like C does). Similarly, when you start a string with `##"`, you're required to include the same - // number of `#` symbols to end it. - $._multiline_comment, - $.raw_str_part, - $.raw_str_continuing_indicator, - $.raw_str_end_part, - // Because Swift doesn't have explicit semicolons, we also do some whitespace handling in a custom scanner. Line - // breaks are _sometimes_ meaningful as the end of a statement: try to write `let foo: Foo let bar: Bar`, for - // instance and the compiler will complain, but add either a newline or a semicolon and it's fine. We borrow the - // idea from the Kotlin grammar that a newline is sometimes a "semicolon". By including `\n` in both `_semi` and - // an anonymous `whitespace` extras, we _should_ be able to let the parser decide if a newline is meaningful. If the - // parser sees something like `foo.bar(1\n)`, it knows that a "semicolon" would not be valid there, so it parses - // that as whitespace. On the other hand, `let foo: Foo\n let bar: Bar` has a meaningful newline. - // Unfortunately, we can't simply stop at that. There are some expressions and statements that remain valid if you - // end them early, but are expected to be parsed across multiple lines. One particular nefarious example is a - // function declaration, where you might have something like `func foo(args: A) -> Foo throws where A: Hashable`. - // This would still be a valid declaration even if it ended after the `)`, the `Foo`, or the `throws`, so a grammar - // that simply interprets a newline as "sometimes a semi" would parse those incorrectly. - // To solve that case, our custom scanner must do a bit of extra lookahead itself. If we're about to generate a - // `_semi`, we advance a bit further to see if the next non-whitespace token would be one of these other operators. - // If so, we ignore the `_semi` and just produce the operator; if not, we produce the `_semi` and let the rest of - // the grammar sort it out. This isn't perfect, but it works well enough most of the time. - $._implicit_semi, - $._explicit_semi, - // Every one of the below operators will suppress a `_semi` if we encounter it after a newline. - $._arrow_operator_custom, - $._dot_custom, - $._conjunction_operator_custom, - $._disjunction_operator_custom, - $._nil_coalescing_operator_custom, - $._eq_custom, - $._eq_eq_custom, - $._plus_then_ws, - $._minus_then_ws, - $._bang_custom, - $._throws_keyword, - $._rethrows_keyword, - $.default_keyword, - $.where_keyword, - $["else"], - $.catch_keyword, - $._as_custom, - $._as_quest_custom, - $._as_bang_custom, - $._async_keyword_custom, - $._custom_operator, - $._hash_symbol_custom, - $._directive_if, - $._directive_elseif, - $._directive_else, - $._directive_endif, - - // Fake operator that will never get triggered, but follows the sequence of characters for `try!`. Tracked by the - // custom scanner so that it can avoid triggering `$.bang` for that case. - $._fake_try_bang, - ], - inline: ($) => [$._locally_permitted_modifiers], - rules: { - //////////////////////////////// - // File Structure - //////////////////////////////// - source_file: ($) => - seq( - optional(field("shebang", $.shebang_line)), - optional( - seq( - field("statement", $._top_level_statement), - repeat(seq($._semi, field("statement", $._top_level_statement))), - optional($._semi) - ) - ) - ), - _semi: ($) => choice($._implicit_semi, $._explicit_semi), - shebang_line: ($) => seq($._hash_symbol, "!", /[^\r\n]*/), - //////////////////////////////// - // Lexical Structure - https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html - //////////////////////////////// - comment: ($) => token(prec(PRECS.comment, seq("//", /.*/))), - // Named wrapper for the unnamed `_multiline_comment` external token, so - // that multi-line comments still appear in the AST (e.g. as extras between - // top-level statements) without being extracted as class body members when - // used only to separate those members. - multiline_comment: ($) => $._multiline_comment, - // Identifiers - simple_identifier: ($) => - choice( - LEXICAL_IDENTIFIER, - /`[^\r\n` ]*`/, - /\$[0-9]+/, - token(seq("$", LEXICAL_IDENTIFIER)), - $._contextual_simple_identifier - ), - // Keywords that were added after they were already legal as identifiers. `tree-sitter` will prefer exact matches - // when parsing so unless we explicitly say that these are legal, the parser will interpret them as their keyword. - _contextual_simple_identifier: ($) => - choice( - "actor", - "async", - "each", - "lazy", - "repeat", - "package", - $._parameter_ownership_modifier - ), - identifier: ($) => sep1(field("part", $.simple_identifier), $._dot), - // Literals - _basic_literal: ($) => - choice( - $.integer_literal, - $.hex_literal, - $.oct_literal, - $.bin_literal, - $.real_literal, - $.boolean_literal, - $._string_literal, - $.regex_literal, - "nil" - ), - real_literal: ($) => - token( - choice( - seq(DEC_DIGITS, REAL_EXPONENT), - seq(optional(DEC_DIGITS), ".", DEC_DIGITS, optional(REAL_EXPONENT)), - seq( - "0x", - HEX_DIGITS, - optional(seq(".", HEX_DIGITS)), - HEX_REAL_EXPONENT - ) - ) - ), - integer_literal: ($) => token(seq(optional(/[1-9]/), DEC_DIGITS)), - hex_literal: ($) => token(seq("0", /[xX]/, HEX_DIGITS)), - oct_literal: ($) => token(seq("0", /[oO]/, OCT_DIGITS)), - bin_literal: ($) => token(seq("0", /[bB]/, BIN_DIGITS)), - boolean_literal: ($) => choice("true", "false"), - // String literals - _string_literal: ($) => - choice( - $.line_string_literal, - $.multi_line_string_literal, - $.raw_string_literal - ), - line_string_literal: ($) => - seq( - '"', - repeat(choice(field("text", $._line_string_content), $._interpolation)), - '"' - ), - _line_string_content: ($) => choice($.line_str_text, $.str_escaped_char), - line_str_text: ($) => /[^\\"]+/, - str_escaped_char: ($) => - choice($._escaped_identifier, $._uni_character_literal), - _uni_character_literal: ($) => seq("\\", "u", /\{[0-9a-fA-F]+\}/), - multi_line_string_literal: ($) => - seq( - '"""', - repeat( - choice(field("text", $._multi_line_string_content), $._interpolation) - ), - '"""' - ), - raw_string_literal: ($) => - seq( - repeat( - seq( - field("text", $.raw_str_part), - field("interpolation", $.raw_str_interpolation), - field("continuing", optional($.raw_str_continuing_indicator)) - ) - ), - field("text", $.raw_str_end_part) - ), - raw_str_interpolation: ($) => - seq(field("start", $.raw_str_interpolation_start), $._interpolation_contents, ")"), - raw_str_interpolation_start: ($) => /\\#*\(/, - _multi_line_string_content: ($) => - choice($.multi_line_str_text, $.str_escaped_char, '"'), - _interpolation: ($) => seq("\\(", $._interpolation_contents, ")"), - _interpolation_contents: ($) => - sep1Opt( - field( - "interpolation", - alias($.value_argument, $.interpolated_expression) - ), - "," - ), - _escaped_identifier: ($) => /\\[0\\tnr"'\n]/, - multi_line_str_text: ($) => /[^\\"]+/, - // Based on https://gitlab.com/woolsweater/tree-sitter-swifter/-/blob/3d47c85bd47ce54cdf2023a9c0e01eb90adfcc1d/grammar.js#L1019 - // But required modifications to hit all of the cases in SE-354 - regex_literal: ($) => - choice( - $._extended_regex_literal, - $._multiline_regex_literal, - $._oneline_regex_literal - ), - - _extended_regex_literal: ($) => - seq($._hash_symbol, /\/((\/[^#])|[^\n])+\/#/), - - _multiline_regex_literal: ($) => - seq($._hash_symbol, /\/\n/, /(\/[^#]|[^/])*?\n\/#/), - - _oneline_regex_literal: ($) => - token( - prec( - PRECS.regex, - seq( - "/", - token.immediate(/[^ \t\n]?[^/\n]*[^ \t\n/]/), - token.immediate("/") - ) - ) - ), - //////////////////////////////// - // Types - https://docs.swift.org/swift-book/ReferenceManual/Types.html - //////////////////////////////// - type_annotation: ($) => - seq(":", field("type", $._possibly_implicitly_unwrapped_type)), - _possibly_implicitly_unwrapped_type: ($) => - choice($.type, $.implicitly_unwrapped_type), - implicitly_unwrapped_type: ($) => - seq(field("name", $.type), token.immediate("!")), - type: ($) => - prec.right( - PRECS.ty, - seq(field("modifiers", optional($.type_modifiers)), field("name", $.unannotated_type)) - ), - unannotated_type: ($) => - prec.right( - PRECS.ty, - choice( - $.user_type, - $.tuple_type, - $.function_type, - $.array_type, - $.dictionary_type, - $.optional_type, - $.metatype, - $.opaque_type, - $.existential_type, - $.protocol_composition_type, - $.type_parameter_pack, - $.type_pack_expansion, - $.suppressed_constraint - ) - ), - // The grammar just calls this whole thing a `type-identifier` but that's a bit confusing. - user_type: ($) => sep1(field("part", $.simple_user_type), $._dot), - simple_user_type: ($) => - prec.right( - PRECS.ty, - seq( - field("name", alias($.simple_identifier, $.type_identifier)), - field("arguments", optional($.type_arguments)) - ) - ), - tuple_type: ($) => - choice( - seq( - "(", - optional(sep1Opt(field("element", $.tuple_type_item), ",")), - ")" - ), - field("element", alias($.parenthesized_type, $.tuple_type_item)) - ), - tuple_type_item: ($) => - prec( - PRECS.expr, - seq( - optional($._tuple_type_item_identifier), - field("modifiers", optional($.parameter_modifiers)), - field("type", $.type) - ) - ), - _tuple_type_item_identifier: ($) => - prec( - PRECS.expr, - seq( - optional(field("external_name", $.wildcard_pattern)), - field("name", $.simple_identifier), - ":" - ) - ), - function_type: ($) => - seq( - field("params", choice($.tuple_type, $.unannotated_type)), - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - $._arrow_operator, - field("return_type", $.type) - ), - array_type: ($) => seq("[", field("element", $.type), "]"), - dictionary_type: ($) => - seq("[", field("key", $.type), ":", field("value", $.type), "]"), - optional_type: ($) => - prec.left( - seq( - field( - "wrapped", - choice($.user_type, $.tuple_type, $.array_type, $.dictionary_type) - ), - repeat1(alias($._immediate_quest, "?")) - ) - ), - metatype: ($) => seq(field("name", $.unannotated_type), ".", choice("Type", "Protocol")), - _quest: ($) => "?", - _immediate_quest: ($) => token.immediate("?"), - opaque_type: ($) => prec.right(seq("some", field("name", $.unannotated_type))), - existential_type: ($) => prec.right(seq("any", field("name", $.unannotated_type))), - type_parameter_pack: ($) => prec.left(seq("each", field("name", $.unannotated_type))), - type_pack_expansion: ($) => prec.left(seq("repeat", field("name", $.unannotated_type))), - protocol_composition_type: ($) => - prec.left( - seq( - field("type", $.unannotated_type), - repeat1(seq("&", prec.right(field("type", $.unannotated_type)))) - ) - ), - suppressed_constraint: ($) => - prec.right( - seq( - "~", - field("suppressed", alias($.simple_identifier, $.type_identifier)) - ) - ), - //////////////////////////////// - // Expressions - https://docs.swift.org/swift-book/ReferenceManual/Expressions.html - //////////////////////////////// - expression: ($) => - prec( - PRECS.expr, - choice( - $.simple_identifier, - $._unary_expression, - $._binary_expression, - $.ternary_expression, - $._primary_expression, - $.if_statement, - $.switch_statement, - $.assignment, - $.value_parameter_pack, - $.value_pack_expansion, - $.optional_chain_marker - ) - ), - optional_chain_marker: ($) => - seq(field("expr", $.expression), alias($._immediate_quest, "?")), - // Unary expressions - _unary_expression: ($) => - choice( - $.postfix_expression, - $.call_expression, - $.macro_invocation, - $.constructor_expression, - $.navigation_expression, - $.prefix_expression, - $.as_expression, - $.selector_expression, - $.open_start_range_expression, - $.open_end_range_expression, - $.directive, - $.diagnostic - ), - postfix_expression: ($) => - prec.left( - PRECS.postfix_operations, - seq( - field("target", $.expression), - field("operation", $._postfix_unary_operator) - ) - ), - constructor_expression: ($) => - prec( - PRECS.call, - seq( - field( - "constructed_type", - choice($.array_type, $.dictionary_type, $.user_type) - ), - field("suffix", $.constructor_suffix) - ) - ), - parenthesized_type: ($) => - seq( - "(", - field("type", choice($.opaque_type, $.existential_type, $.dictionary_type)), - ")" - ), - navigation_expression: ($) => - prec.left( - PRECS.navigation, - seq( - field( - "target", - choice( - $._navigable_type_expression, - $.expression, - $.parenthesized_type - ) - ), - field("suffix", $.navigation_suffix) - ) - ), - _navigable_type_expression: ($) => - choice($.user_type, $.array_type, $.dictionary_type), - open_start_range_expression: ($) => - prec.right( - PRECS.range, - seq( - $._range_operator, - prec.right(PRECS.range_suffix, field("end", $.expression)) - ) - ), - _range_operator: ($) => - choice($._open_ended_range_operator, $._three_dot_operator), - open_end_range_expression: ($) => - prec.right( - PRECS.range, - seq(field("start", $.expression), $._three_dot_operator) - ), - prefix_expression: ($) => - prec.left( - PRECS.prefix_operations, - seq( - field("operation", $._prefix_unary_operator), - field( - "target", - choice( - $.expression, - alias(choice("async", "if", "switch"), $.expression) - ) - ) - ) - ), - as_expression: ($) => - prec.left( - PRECS.as, - seq(field("expr", $.expression), field("operator", $.as_operator), field("type", $.type)) - ), - selector_expression: ($) => - seq( - $._hash_symbol, - "selector", - "(", - optional(choice("getter:", "setter:")), - field("expr", $.expression), - ")" - ), - // Binary expressions - _binary_expression: ($) => - choice( - $.multiplicative_expression, - $.additive_expression, - $.range_expression, - $.infix_expression, - $.nil_coalescing_expression, - $.check_expression, - $.equality_expression, - $.comparison_expression, - $.conjunction_expression, - $.disjunction_expression, - $.bitwise_operation - ), - multiplicative_expression: ($) => - prec.left( - PRECS.multiplication, - seq( - field("lhs", $.expression), - field("op", $._multiplicative_operator), - field("rhs", $.expression) - ) - ), - additive_expression: ($) => - prec.left( - PRECS.addition, - seq( - field("lhs", $.expression), - field("op", $._additive_operator), - field("rhs", $.expression) - ) - ), - range_expression: ($) => - prec.right( - PRECS.range, - seq( - field("start", $.expression), - field("op", $._range_operator), - field("end", $._expr_hack_at_ternary_binary_suffix) - ) - ), - infix_expression: ($) => - prec.left( - PRECS.infix_operations, - seq( - field("lhs", $.expression), - field("op", $.custom_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - nil_coalescing_expression: ($) => - prec.right( - PRECS.nil_coalescing, - seq( - field("value", $.expression), - $._nil_coalescing_operator, - field("if_nil", $._expr_hack_at_ternary_binary_suffix) - ) - ), - check_expression: ($) => - prec.left( - PRECS.check, - seq( - field("target", $.expression), - field("op", $._is_operator), - field("type", $.type) - ) - ), - comparison_expression: ($) => - prec.left( - seq( - field("lhs", $.expression), - field("op", $._comparison_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - equality_expression: ($) => - prec.left( - PRECS.equality, - seq( - field("lhs", $.expression), - field("op", $._equality_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - conjunction_expression: ($) => - prec.left( - PRECS.conjunction, - seq( - field("lhs", $.expression), - field("op", $._conjunction_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - disjunction_expression: ($) => - prec.left( - PRECS.disjunction, - seq( - field("lhs", $.expression), - field("op", $._disjunction_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - bitwise_operation: ($) => - prec.left( - seq( - field("lhs", $.expression), - field("op", $._bitwise_binary_operator), - field("rhs", $._expr_hack_at_ternary_binary_suffix) - ) - ), - custom_operator: ($) => choice(token(/[\/]+[*]+/), $._custom_operator), - // Suffixes - navigation_suffix: ($) => - seq( - $._dot, - field("suffix", choice($.simple_identifier, $.integer_literal)) - ), - call_suffix: ($) => - prec( - PRECS.call_suffix, - choice( - field("arguments", $.value_arguments), - prec.dynamic(-1, $._fn_call_lambda_arguments), // Prefer to treat `foo() { }` as one call not two - seq(field("arguments", $.value_arguments), $._fn_call_lambda_arguments) - ) - ), - constructor_suffix: ($) => - prec( - PRECS.call_suffix, - choice( - field("arguments", alias($._constructor_value_arguments, $.value_arguments)), - prec.dynamic(-1, $._fn_call_lambda_arguments), // As above - seq( - field("arguments", alias($._constructor_value_arguments, $.value_arguments)), - $._fn_call_lambda_arguments - ) - ) - ), - _constructor_value_arguments: ($) => - seq("(", optional(sep1Opt(field("argument", $.value_argument), ",")), ")"), - _fn_call_lambda_arguments: ($) => - sep1(field("lambda", $.lambda_literal), seq(field("name", $.simple_identifier), ":")), - type_arguments: ($) => prec.left(seq("<", sep1Opt(field("argument", $.type), ","), ">")), - value_arguments: ($) => - seq( - choice( - seq("(", optional(sep1Opt(field("argument", $.value_argument), ",")), ")"), - seq("[", optional(sep1Opt(field("argument", $.value_argument), ",")), "]") - ) - ), - value_argument_label: ($) => - prec.left( - field("name", choice( - $.simple_identifier, - // We don't rely on $._contextual_simple_identifier here because - // these don't usually fall into that category. - alias("if", $.simple_identifier), - alias("switch", $.simple_identifier) - )) - ), - value_argument: ($) => - prec.left( - seq( - field("type_modifiers", optional($.type_modifiers)), - choice( - repeat1( - seq(field("reference_specifier", $.value_argument_label), ":") - ), - seq( - optional(seq(field("name", $.value_argument_label), ":")), - field("value", $.expression) - ) - ) - ) - ), - try_expression: ($) => - prec.right( - PRECS["try"], - seq( - field("operator", $.try_operator), - field( - "expr", - choice( - // Prefer direct calls, e.g. `try foo()`, over indirect like `try a ? b() : c`. This allows us to have - // left associativity for the direct calls, which is technically wrong but is the only way to resolve the - // ambiguity of `if foo { ... }` in the correct direction. - prec.right(-2, $.expression), - prec.left(0, $._binary_expression), - prec.left(0, $.call_expression), - // Similarly special case the ternary expression, where `try` may come earlier than it is actually needed. - // When the parser just encounters some identifier after a `try`, it should prefer the `call_expression` (so - // this should be lower in priority than that), but when we encounter an ambiguous expression that might be - // either `try (foo() ? ...)` or `(try foo()) ? ...`, we should prefer the former. We accomplish that by - // giving it a _static precedence_ of -1 but a _dynamic precedence_ of 1. - prec.dynamic(1, prec.left(-1, $.ternary_expression)) - ) - ) - ) - ), - await_expression: ($) => - prec.right( - PRECS.await, - seq( - $._await_operator, - field( - "expr", - choice( - // Prefer direct calls over indirect (same as with `try`). - prec.right(-2, $.expression), - prec.left(0, $.call_expression), - // Special case ternary to `await` the whole thing (same as with `try`). - prec.dynamic(1, prec.left(-1, $.ternary_expression)) - ) - ) - ) - ), - _await_operator: ($) => alias("await", "await"), - ternary_expression: ($) => - prec.right( - PRECS.ternary, - seq( - field("condition", $.expression), - $._quest, - field("if_true", $.expression), - ":", - field("if_false", $._expr_hack_at_ternary_binary_suffix) - ) - ), - _expr_hack_at_ternary_binary_suffix: ($) => - prec.left( - PRECS.ternary_binary_suffix, - choice( - $.expression, - alias($.expr_hack_at_ternary_binary_call, $.call_expression) - ) - ), - expr_hack_at_ternary_binary_call: ($) => - seq( - field("function", $.expression), - field("suffix", alias($.expr_hack_at_ternary_binary_call_suffix, $.call_suffix)) - ), - expr_hack_at_ternary_binary_call_suffix: ($) => - prec(PRECS.call_suffix, field("arguments", $.value_arguments)), - call_expression: ($) => - prec( - PRECS.call, - prec.dynamic(DYNAMIC_PRECS.call, seq(field("function", $.expression), field("suffix", $.call_suffix))) - ), - macro_invocation: ($) => - prec( - PRECS.call, - prec.dynamic( - DYNAMIC_PRECS.call, - seq( - $._hash_symbol, - field("name", $.simple_identifier), - field("type_parameters", optional($.type_parameters)), - field("suffix", $.call_suffix) - ) - ) - ), - _primary_expression: ($) => - choice( - $.tuple_expression, - $._basic_literal, - $.lambda_literal, - $.special_literal, - $.playground_literal, - $.array_literal, - $.dictionary_literal, - $.self_expression, - $.super_expression, - $.try_expression, - $.await_expression, - $.referenceable_operator, - $.key_path_expression, - $.key_path_string_expression, - prec.right( - PRECS.fully_open_range, - alias($._three_dot_operator, $.fully_open_range) - ) - ), - tuple_expression: ($) => - prec.right( - PRECS.tuple, - seq( - "(", - sep1Opt(field("element", $.tuple_expression_item), ","), - ")" - ) - ), - tuple_expression_item: ($) => - seq( - optional(seq(field("name", $.simple_identifier), ":")), - field("value", $.expression) - ), - array_literal: ($) => - seq("[", optional(sep1Opt(field("element", $.expression), ",")), "]"), - dictionary_literal: ($) => - seq( - "[", - choice(":", sep1Opt(field("element", $.dictionary_literal_item), ",")), - optional(","), - "]" - ), - dictionary_literal_item: ($) => - seq(field("key", $.expression), ":", field("value", $.expression)), - special_literal: ($) => - seq( - $._hash_symbol, - choice( - "file", - "fileID", - "filePath", - "line", - "column", - "function", - "dsohandle" - ) - ), - playground_literal: ($) => - seq( - $._hash_symbol, - field("kind", choice("colorLiteral", "fileLiteral", "imageLiteral")), - "(", - sep1Opt(field("argument", $.playground_literal_argument), ","), - ")" - ), - playground_literal_argument: ($) => - seq(field("name", $.simple_identifier), ":", field("value", $.expression)), - lambda_literal: ($) => - prec.left( - PRECS.lambda, - seq( - choice("{", "^{"), - optional($._lambda_type_declaration), - optional($._statements), - "}" - ) - ), - _lambda_type_declaration: ($) => - seq( - repeat(field("attribute", $.attribute)), - prec(PRECS.expr, optional(field("captures", $.capture_list))), - optional(field("type", $.lambda_function_type)), - "in" - ), - capture_list: ($) => seq("[", sep1Opt(field("item", $.capture_list_item), ","), "]"), - capture_list_item: ($) => - choice( - field("name", $.self_expression), - prec( - PRECS.expr, - seq( - field("ownership", optional($.ownership_modifier)), - field("name", $.simple_identifier), - optional(seq($._equal_sign, field("value", $.expression))) - ) - ) - ), - lambda_function_type: ($) => - prec( - PRECS.expr, - seq( - choice( - field("params", $.lambda_function_type_parameters), - seq("(", field("params", optional($.lambda_function_type_parameters)), ")") - ), - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - optional( - seq( - $._arrow_operator, - field("return_type", $._possibly_implicitly_unwrapped_type) - ) - ) - ) - ), - lambda_function_type_parameters: ($) => sep1Opt(field("parameter", $.lambda_parameter), ","), - lambda_parameter: ($) => - seq( - choice( - field("name", $.self_expression), - prec(PRECS.expr, field("name", $.simple_identifier)), - prec( - PRECS.expr, - seq( - optional(field("external_name", $.simple_identifier)), - field("name", $.simple_identifier), - ":", - field("modifiers", optional($.parameter_modifiers)), - field("type", $._possibly_implicitly_unwrapped_type) - ) - ) - ) - ), - self_expression: ($) => "self", - super_expression: ($) => seq("super"), - _else_options: ($) => choice(field("else_branch", $.block), field("else_branch", $.if_statement)), - if_statement: ($) => - prec.right( - PRECS["if"], - seq( - "if", - sep1(field("condition", $.if_condition), ","), - field("body", $.block), - optional(seq(alias($["else"], "else"), $._else_options)) - ) - ), - if_condition: ($) => - field("kind", choice($.if_let_binding, $.expression, $.availability_condition)), - if_let_binding: ($) => - seq( - $._direct_or_indirect_binding, - optional(seq($._equal_sign, field("value", $.expression))), - field("where", optional($.where_clause)) - ), - guard_statement: ($) => - prec.right( - PRECS["if"], - seq( - "guard", - sep1(field("condition", $.if_condition), ","), - alias($["else"], "else"), - field("body", $.block) - ) - ), - switch_statement: ($) => - prec.right( - PRECS["switch"], - seq( - "switch", - field("expr", $.expression), - "{", - repeat(field("entry", $.switch_entry)), - "}" - ) - ), - switch_entry: ($) => - seq( - field("modifiers", optional($.modifiers)), - choice( - seq( - "case", - field("pattern", $.switch_pattern), - field("where", optional($.where_clause)), - repeat(seq(",", field("pattern", $.switch_pattern))) - ), - field("default", $.default_keyword) - ), - ":", - $._statements, - optional("fallthrough") - ), - switch_pattern: ($) => field("pattern", alias($._binding_pattern_with_expr, $.pattern)), - do_statement: ($) => - prec.right(PRECS["do"], seq("do", field("body", $.block), repeat(field("catch", $.catch_block)))), - catch_block: ($) => - seq( - field("keyword", $.catch_keyword), - field("error", optional(alias($._binding_pattern_no_expr, $.pattern))), - field("where", optional($.where_clause)), - field("body", $.block) - ), - where_clause: ($) => prec.left(seq(field("keyword", $.where_keyword), field("expr", $.expression))), - key_path_expression: ($) => - prec.right( - PRECS.keypath, - seq( - "\\", - field("type", optional( - choice($.simple_user_type, $.array_type, $.dictionary_type) - )), - repeat(seq(".", field("component", $.key_path_component))) - ) - ), - key_path_string_expression: ($) => - prec.left(seq($._hash_symbol, "keyPath", "(", field("expr", $.expression), ")")), - key_path_component: ($) => - prec.left( - choice( - seq(field("name", $.simple_identifier), repeat(field("postfix", $.key_path_postfix))), - repeat1(field("postfix", $.key_path_postfix)) - ) - ), - key_path_postfix: ($) => - choice( - "?", - field("force_unwrap", $.bang), - "self", - seq("[", optional(sep1(field("argument", $.value_argument), ",")), "]") - ), - try_operator: ($) => - prec.right( - seq("try", choice(optional($._try_operator_type), $._fake_try_bang)) - ), - _try_operator_type: ($) => - choice(token.immediate("!"), token.immediate("?")), - _assignment_and_operator: ($) => - choice("+=", "-=", "*=", "/=", "%=", $._equal_sign), - _equality_operator: ($) => choice("!=", "!==", $._eq_eq, "==="), - _comparison_operator: ($) => choice("<", ">", "<=", ">="), - _three_dot_operator: ($) => alias("...", "..."), // Weird alias to satisfy highlight queries - _open_ended_range_operator: ($) => alias("..<", "..<"), - _is_operator: ($) => "is", - _additive_operator: ($) => - choice( - alias($._plus_then_ws, "+"), - alias($._minus_then_ws, "-"), - "+", - "-" - ), - // The `/` operator conflicts with a regex literal (which itself appears to conflict with a - // comment, for some reason), so we must give it equivalent token precedence. - _multiplicative_operator: ($) => - choice("*", alias(token(prec(PRECS.regex, "/")), "/"), "%"), - as_operator: ($) => choice($._as, $._as_quest, $._as_bang), - _prefix_unary_operator: ($) => - prec.right( - choice( - "++", - "--", - "-", - "+", - $.bang, - "&", - "~", - $._dot, - $.custom_operator - ) - ), - _bitwise_binary_operator: ($) => choice("&", "|", "^", "<<", ">>"), - _postfix_unary_operator: ($) => choice("++", "--", $.bang), - directly_assignable_expression: ($) => field("expr", $.expression), - - //////////////////////////////// - // Statements - https://docs.swift.org/swift-book/ReferenceManual/Statements.html - //////////////////////////////// - _statements: ($) => - prec.left( - // Left precedence is required in switch statements - seq( - field("statement", $._local_statement), - repeat(seq($._semi, field("statement", $._local_statement))), - optional($._semi) - ) - ), - _local_statement: ($) => - choice( - $.expression, - $.local_declaration, - $._labeled_statement, - $.control_transfer_statement - ), - _top_level_statement: ($) => - choice( - $.expression, - $.global_declaration, - $._labeled_statement, - $._throw_statement - ), - block: ($) => prec(PRECS.block, seq("{", optional($._statements), "}")), - _labeled_statement: ($) => - seq( - optional($.statement_label), - choice( - $.for_statement, - $.while_statement, - $.repeat_while_statement, - $.do_statement, - $.if_statement, - $.guard_statement, - $.switch_statement - ) - ), - statement_label: ($) => token(/[a-zA-Z_][a-zA-Z_0-9]*:/), - for_statement: ($) => - prec( - PRECS.loop, - seq( - "for", - field("try", optional($.try_operator)), - optional($._await_operator), - field("item", alias($._binding_pattern_no_expr, $.pattern)), - field("type", optional($.type_annotation)), - "in", - field("collection", $._for_statement_collection), - field("where", optional($.where_clause)), - field("body", $.block) - ) - ), - _for_statement_collection: ($) => - // If this expression has "await", this triggers some special-cased logic to prefer function calls. We prefer - // the opposite, though, since function calls may contain trailing code blocks, which are undesirable here. - // - // To fix that, we simply undo the special casing by defining our own `await_expression`. - choice($.expression, alias($.for_statement_await, $.await_expression)), - for_statement_await: ($) => seq($._await_operator, field("expr", $.expression)), - - while_statement: ($) => - prec( - PRECS.loop, - seq( - "while", - sep1(field("condition", $.if_condition), ","), - field("body", $.block) - ) - ), - repeat_while_statement: ($) => - prec( - PRECS.loop, - seq( - "repeat", - field("body", $.block), - // Make sure we make it to the `while` before assuming this is a parameter pack. - repeat($._implicit_semi), - "while", - sep1(field("condition", $.if_condition), ",") - ) - ), - control_transfer_statement: ($) => - choice( - prec.right( - PRECS.control_transfer, - seq(field("kind", $.throw_keyword), field("result", $.expression)) - ), - prec.right( - PRECS.control_transfer, - seq( - field("kind", $._optionally_valueful_control_keyword), - field("result", optional($.expression)) - ) - ) - ), - _throw_statement: ($) => seq($.throw_keyword, $.expression), - throw_keyword: ($) => "throw", - _optionally_valueful_control_keyword: ($) => - choice("return", "continue", "break", "yield"), - assignment: ($) => - prec.left( - PRECS.assignment, - seq( - field("target", $.directly_assignable_expression), - field("operator", $._assignment_and_operator), - field("result", $.expression) - ) - ), - value_parameter_pack: ($) => - prec.left(PRECS.parameter_pack, seq("each", field("expr", $.expression))), - value_pack_expansion: ($) => - prec.left(PRECS.parameter_pack, seq("repeat", field("expr", $.expression))), - availability_condition: ($) => - seq( - $._hash_symbol, - choice("available", "unavailable"), - "(", - sep1Opt($._availability_argument, ","), - ")" - ), - _availability_argument: ($) => - choice(seq(field("platform", $.identifier), sep1(field("version", $.integer_literal), ".")), "*"), - //////////////////////////////// - // Declarations - https://docs.swift.org/swift-book/ReferenceManual/Declarations.html - //////////////////////////////// - global_declaration: ($) => - choice( - $.import_declaration, - $.property_declaration, - $.typealias_declaration, - $.function_declaration, - $.init_declaration, - $.class_declaration, - $.protocol_declaration, - $.operator_declaration, - $.precedence_group_declaration, - $.associatedtype_declaration, - $.macro_declaration - ), - type_level_declaration: ($) => - choice( - $.import_declaration, - $.property_declaration, - $.typealias_declaration, - $.function_declaration, - $.init_declaration, - $.class_declaration, - $.protocol_declaration, - $.deinit_declaration, - $.subscript_declaration, - $.operator_declaration, - $.precedence_group_declaration, - $.associatedtype_declaration - ), - local_declaration: ($) => - choice( - alias($._local_property_declaration, $.property_declaration), - alias($._local_typealias_declaration, $.typealias_declaration), - alias($._local_function_declaration, $.function_declaration), - alias($._local_class_declaration, $.class_declaration) - ), - _local_property_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_property_declaration - ), - _local_typealias_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_typealias_declaration - ), - _local_function_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_function_declaration - ), - _local_class_declaration: ($) => - seq( - field("modifiers", optional($._locally_permitted_modifiers)), - $._modifierless_class_declaration - ), - import_declaration: ($) => - seq( - field("modifiers", optional($.modifiers)), - "import", - optional(field("scoped_import_kind", $._import_kind)), - field("name", $.identifier) - ), - _import_kind: ($) => - choice( - "typealias", - "struct", - "class", - "enum", - "protocol", - "let", - "var", - "func" - ), - protocol_property_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - field("name", alias($._binding_kind_and_pattern, $.pattern)), - field("type", optional($.type_annotation)), - field("type_constraints", optional($.type_constraints)), - field("requirements", $.protocol_property_requirements) - ) - ), - protocol_property_requirements: ($) => - seq("{", repeat(field("accessor", choice($.getter_specifier, $.setter_specifier))), "}"), - property_declaration: ($) => - seq(field("modifiers", optional($.modifiers)), $._modifierless_property_declaration), - _modifierless_property_declaration: ($) => - prec.right( - seq( - $._possibly_async_binding_pattern_kind, - sep1(field("declarator", $.property_binding), ",") - ) - ), - property_binding: ($) => - prec.left( - seq( - field("name", alias($._no_expr_pattern_already_bound, $.pattern)), - field("type", optional($.type_annotation)), - field("type_constraints", optional($.type_constraints)), - optional( - choice( - $._expression_with_willset_didset, - $._expression_without_willset_didset, - field("observers", $.willset_didset_block), - field("computed_value", $.computed_property) - ) - ) - ) - ), - _expression_with_willset_didset: ($) => - prec.dynamic( - 1, - seq( - $._equal_sign, - field("value", $.expression), - field("observers", $.willset_didset_block) - ) - ), - _expression_without_willset_didset: ($) => - seq($._equal_sign, field("value", $.expression)), - willset_didset_block: ($) => - choice( - seq("{", field("willset", $.willset_clause), field("didset", optional($.didset_clause)), "}"), - seq("{", field("didset", $.didset_clause), field("willset", optional($.willset_clause)), "}") - ), - willset_clause: ($) => - seq( - field("modifiers", optional($.modifiers)), - "willSet", - optional(seq("(", field("parameter", $.simple_identifier), ")")), - field("body", $.block) - ), - didset_clause: ($) => - seq( - field("modifiers", optional($.modifiers)), - "didSet", - optional(seq("(", field("parameter", $.simple_identifier), ")")), - field("body", $.block) - ), - typealias_declaration: ($) => - seq(field("modifiers", optional($.modifiers)), $._modifierless_typealias_declaration), - _modifierless_typealias_declaration: ($) => - seq( - "typealias", - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - $._equal_sign, - field("value", $.type) - ), - function_declaration: ($) => - prec.right( - seq($._bodyless_function_declaration, field("body", $.block)) - ), - _modifierless_function_declaration: ($) => - prec.right( - seq( - $._modifierless_function_declaration_no_body, - field("body", $.block) - ) - ), - _bodyless_function_declaration: ($) => - seq( - field("modifiers", optional($.modifiers)), - optional("class"), // XXX: This should be possible in non-last position, but that creates parsing ambiguity - $._modifierless_function_declaration_no_body - ), - _modifierless_function_declaration_no_body: ($) => - prec.right( - seq( - $._non_constructor_function_decl, - field("type_parameters", optional($.type_parameters)), - $._function_value_parameters, - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - optional( - seq( - $._arrow_operator, - field("return_type", $._possibly_implicitly_unwrapped_type) - ) - ), - field("type_constraints", optional($.type_constraints)) - ) - ), - macro_declaration: ($) => - seq( - $._macro_head, - field("name", $.simple_identifier), - field("type_parameters", optional($.type_parameters)), - $._macro_signature, - optional(field("definition", $.macro_definition)), - field("type_constraints", optional($.type_constraints)) - ), - _macro_head: ($) => seq(field("modifiers", optional($.modifiers)), "macro"), - _macro_signature: ($) => - seq( - $._function_value_parameters, - optional(seq($._arrow_operator, field("return_type", $.unannotated_type))) - ), - macro_definition: ($) => - seq( - $._equal_sign, - field("body", choice($.expression, $.external_macro_definition)) - ), - - external_macro_definition: ($) => - seq($._hash_symbol, "externalMacro", field("arguments", $.value_arguments)), - - class_declaration: ($) => - seq(field("modifiers", optional($.modifiers)), $._modifierless_class_declaration), - _modifierless_class_declaration: ($) => - prec.right( - choice( - seq( - field("declaration_kind", choice("class", "struct", "actor")), - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.class_body) - ), - seq( - field("declaration_kind", "extension"), - field("name", $.unannotated_type), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.class_body) - ), - seq( - optional("indirect"), - field("declaration_kind", "enum"), - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.enum_class_body) - ) - ) - ), - class_body: ($) => seq("{", optional($._class_member_declarations), "}"), - _inheritance_specifiers: ($) => - prec.left(sep1($._annotated_inheritance_specifier, choice(",", "&"))), - _annotated_inheritance_specifier: ($) => - seq(repeat(field("attribute", $.attribute)), field("inherits", $.inheritance_specifier)), - inheritance_specifier: ($) => - prec.left( - field( - "inherits_from", - choice($.user_type, $.function_type, $.suppressed_constraint) - ) - ), - type_parameters: ($) => - seq( - "<", - sep1Opt(field("parameter", $.type_parameter), ","), - field("constraints", optional($.type_constraints)), - ">" - ), - type_parameter: ($) => - seq( - field("modifiers", optional($.type_parameter_modifiers)), - field("name", $._type_parameter_possibly_packed), - optional(seq(":", field("type", $.type))) - ), - _type_parameter_possibly_packed: ($) => - choice( - alias($.simple_identifier, $.type_identifier), - $.type_parameter_pack - ), - - type_constraints: ($) => - prec.right(seq(field("keyword", $.where_keyword), sep1Opt(field("constraint", $.type_constraint), ","))), - type_constraint: ($) => - field("constraint", choice($.inheritance_constraint, $.equality_constraint)), - inheritance_constraint: ($) => - seq( - repeat(field("attribute", $.attribute)), - field("constrained_type", $._constrained_type), - ":", - field("inherits_from", $._possibly_implicitly_unwrapped_type) - ), - equality_constraint: ($) => - seq( - repeat(field("attribute", $.attribute)), - field("constrained_type", $._constrained_type), - choice($._equal_sign, $._eq_eq), - field("must_equal", $.type) - ), - _constrained_type: ($) => choice($.identifier, $.nested_type_identifier), - nested_type_identifier: ($) => - seq( - field("base", $.unannotated_type), - optional(seq(".", sep1(field("member", $.simple_identifier), "."))) - ), - _class_member_separator: ($) => choice($._semi, $._multiline_comment), - _class_member_declarations: ($) => - seq( - sep1(field("member", $.type_level_declaration), $._class_member_separator), - optional($._class_member_separator) - ), - _function_value_parameters: ($) => - repeat1( - seq("(", optional(sep1Opt(field("parameter", $.function_parameter), ",")), ")") - ), - function_parameter: ($) => - seq( - field("attribute", optional($.attribute)), - field("parameter", $.parameter), - optional(seq($._equal_sign, field("default_value", $.expression))) - ), - parameter: ($) => - seq( - optional(field("external_name", $.simple_identifier)), - field("name", $.simple_identifier), - ":", - field("modifiers", optional($.parameter_modifiers)), - field("type", $._possibly_implicitly_unwrapped_type), - optional($._three_dot_operator) - ), - _non_constructor_function_decl: ($) => - seq( - "func", - field("name", choice($.simple_identifier, $.referenceable_operator)) - ), - referenceable_operator: ($) => - field("operator", choice( - $.custom_operator, - $._comparison_operator, - $._additive_operator, - $._multiplicative_operator, - $._equality_operator, - $._assignment_and_operator, - "++", - "--", - $.bang, - "~", - "|", - "^", - "<<", - ">>", - "&" - )), - // Hide the fact that certain symbols come from the custom scanner by aliasing them to their - // string variants. This keeps us from having to see them in the syntax tree (which would be - // noisy) but allows callers to refer to them as nodes by their text form like with any - // operator. - _equal_sign: ($) => alias($._eq_custom, "="), - _eq_eq: ($) => alias($._eq_eq_custom, "=="), - _dot: ($) => alias($._dot_custom, "."), - _arrow_operator: ($) => alias($._arrow_operator_custom, "->"), - _conjunction_operator: ($) => alias($._conjunction_operator_custom, "&&"), - _disjunction_operator: ($) => alias($._disjunction_operator_custom, "||"), - _nil_coalescing_operator: ($) => - alias($._nil_coalescing_operator_custom, "??"), - _as: ($) => alias($._as_custom, "as"), - _as_quest: ($) => alias($._as_quest_custom, "as?"), - _as_bang: ($) => alias($._as_bang_custom, "as!"), - _hash_symbol: ($) => alias($._hash_symbol_custom, "#"), - bang: ($) => choice($._bang_custom, "!"), - _async_keyword: ($) => alias($._async_keyword_custom, "async"), - _async_modifier: ($) => token("async"), - throws: ($) => choice($._throws_keyword, $._rethrows_keyword), - throws_clause: ($) => - seq($._throws_keyword, "(", field("type", $.unannotated_type), ")"), - enum_class_body: ($) => - seq("{", repeat(field("member", choice($.enum_entry, $.type_level_declaration))), "}"), - enum_entry: ($) => - seq( - field("modifiers", optional($.modifiers)), - optional("indirect"), - "case", - sep1(field("case", $.enum_case_entry), ","), - optional(";") - ), - enum_case_entry: ($) => - seq( - field("name", $.simple_identifier), - optional($._enum_entry_suffix) - ), - _enum_entry_suffix: ($) => - choice( - field("data_contents", $.enum_type_parameters), - seq($._equal_sign, field("raw_value", $.expression)) - ), - enum_type_parameters: ($) => - seq( - "(", - optional(sep1(field("parameter", $.enum_type_parameter), ",")), - ")" - ), - enum_type_parameter: ($) => - seq( - optional( - seq(optional(field("external_name", $.wildcard_pattern)), field("name", $.simple_identifier), ":") - ), - field("type", $.type), - optional(seq($._equal_sign, field("default_value", $.expression))) - ), - protocol_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - "protocol", - field("name", alias($.simple_identifier, $.type_identifier)), - field("type_parameters", optional($.type_parameters)), - optional(seq(":", $._inheritance_specifiers)), - field("type_constraints", optional($.type_constraints)), - field("body", $.protocol_body) - ) - ), - protocol_body: ($) => - seq("{", optional($._protocol_member_declarations), "}"), - _protocol_member_declarations: ($) => - seq(sep1(field("member", $.protocol_member_declaration), $._semi), optional($._semi)), - protocol_member_declaration: ($) => - choice( - $.protocol_function_declaration, - $.init_declaration, - $.deinit_declaration, - $.protocol_property_declaration, - $.typealias_declaration, - $.associatedtype_declaration, - $.subscript_declaration - ), - protocol_function_declaration: ($) => - seq( - $._bodyless_function_declaration, - optional(field("body", $.block)) - ), - init_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - optional("class"), - "init", - optional(choice($._quest, field("bang", $.bang))), - field("type_parameters", optional($.type_parameters)), - $._function_value_parameters, - field("async", optional($._async_keyword)), - field("throws", optional(choice($.throws_clause, $.throws))), - field("type_constraints", optional($.type_constraints)), - optional(field("body", $.block)) - ) - ), - deinit_declaration: ($) => - prec.right( - seq(field("modifiers", optional($.modifiers)), "deinit", field("body", $.block)) - ), - subscript_declaration: ($) => - prec.right( - seq( - field("modifiers", optional($.modifiers)), - "subscript", - field("type_parameters", optional($.type_parameters)), - $._function_value_parameters, - optional( - seq( - $._arrow_operator, - field("return_type", $._possibly_implicitly_unwrapped_type) - ) - ), - field("type_constraints", optional($.type_constraints)), - field("body", $.computed_property) - ) - ), - computed_property: ($) => - seq( - "{", - choice( - optional($._statements), - repeat( - field("accessor", choice($.computed_getter, $.computed_setter, $.computed_modify)) - ) - ), - "}" - ), - computed_getter: ($) => - seq(repeat(field("attribute", $.attribute)), field("specifier", $.getter_specifier), optional(field("body", $.block))), - computed_modify: ($) => - seq(repeat(field("attribute", $.attribute)), field("specifier", $.modify_specifier), optional(field("body", $.block))), - computed_setter: ($) => - seq( - repeat(field("attribute", $.attribute)), - field("specifier", $.setter_specifier), - optional(seq("(", field("parameter", $.simple_identifier), ")")), - optional(field("body", $.block)) - ), - getter_specifier: ($) => - seq(field("mutation", optional($.mutation_modifier)), "get", optional($._getter_effects)), - setter_specifier: ($) => seq(field("mutation", optional($.mutation_modifier)), "set"), - modify_specifier: ($) => seq(field("mutation", optional($.mutation_modifier)), "_modify"), - _getter_effects: ($) => - repeat1(field("effect", choice(alias($._async_keyword, $.async_keyword), $.throws_clause, $.throws))), - operator_declaration: ($) => - seq( - field("kind", choice("prefix", "infix", "postfix")), - "operator", - field("name", $.referenceable_operator), - optional(seq(":", field("precedence_group", $.simple_identifier))), - field("body", optional($.deprecated_operator_declaration_body)) - ), - // The Swift compiler no longer accepts these, but some very old code still uses it. - deprecated_operator_declaration_body: ($) => - seq("{", repeat(field("entry", choice($.simple_identifier, $._basic_literal))), "}"), - precedence_group_declaration: ($) => - seq( - "precedencegroup", - field("name", $.simple_identifier), - "{", - field("attributes", optional($.precedence_group_attributes)), - "}" - ), - precedence_group_attributes: ($) => repeat1(field("attribute", $.precedence_group_attribute)), - precedence_group_attribute: ($) => - seq( - field("name", $.simple_identifier), - ":", - field("value", choice($.simple_identifier, $.boolean_literal)) - ), - associatedtype_declaration: ($) => - seq( - field("modifiers", optional($.modifiers)), - "associatedtype", - field("name", alias($.simple_identifier, $.type_identifier)), - optional(seq(":", field("must_inherit", $.type))), - field("type_constraints", optional($.type_constraints)), - optional(seq($._equal_sign, field("default_value", $.type))) - ), - //////////////////////////////// - // Attributes - https://docs.swift.org/swift-book/ReferenceManual/Attributes.html - //////////////////////////////// - attribute: ($) => - seq( - "@", - field("name", $.user_type), - // attribute arguments are a mess of special cases, maybe this is good enough? - optional(seq("(", sep1Opt($._attribute_argument, ","), ")")) - ), - _attribute_argument: ($) => - choice( - // labeled function parameters, used in custom property wrappers - seq(field("argument_name", $.simple_identifier), ":", field("argument", $.expression)), - // Unlabeled function parameters, simple identifiers, or `*` - field("argument", $.expression), - // References to param names (used in `@objc(foo:bar:)`) - repeat1(seq(field("param_ref", $.simple_identifier), ":")), - // Version restrictions (iOS 3.4.5, Swift 5.0.0) - seq(repeat1(field("platform", $.simple_identifier)), sep1(field("version", $.integer_literal), ".")) - ), - //////////////////////////////// - // Patterns - https://docs.swift.org/swift-book/ReferenceManual/Patterns.html - //////////////////////////////// - _universally_allowed_pattern: ($) => - choice( - $.wildcard_pattern, - $.tuple_pattern, - $.type_casting_pattern, - $.case_pattern - ), - _bound_identifier: ($) => field("bound_identifier", $.simple_identifier), - - _binding_pattern_no_expr: ($) => - seq( - field("kind", choice( - $._universally_allowed_pattern, - $.binding_pattern, - $._bound_identifier - )), - optional($._quest) - ), - _no_expr_pattern_already_bound: ($) => - seq( - field("kind", choice($._universally_allowed_pattern, $._bound_identifier)), - optional($._quest) - ), - _binding_pattern_with_expr: ($) => - seq( - field("kind", choice( - $._universally_allowed_pattern, - $.binding_pattern, - $.expression - )), - optional($._quest) - ), - _non_binding_pattern_with_expr: ($) => - seq( - field("kind", choice($._universally_allowed_pattern, $.expression)), - optional($._quest) - ), - _direct_or_indirect_binding: ($) => - seq( - choice( - field("pattern", alias($._binding_kind_and_pattern, $.pattern)), - seq("case", field("pattern", alias($._binding_pattern_no_expr, $.pattern))) - ), - field("type", optional($.type_annotation)) - ), - value_binding_pattern: ($) => field("mutability", choice("var", "let")), - _possibly_async_binding_pattern_kind: ($) => - seq(optional($._async_modifier), field("binding", $.value_binding_pattern)), - _binding_kind_and_pattern: ($) => - seq( - $._possibly_async_binding_pattern_kind, - $._no_expr_pattern_already_bound - ), - wildcard_pattern: ($) => "_", - tuple_pattern_item: ($) => - choice( - seq( - field("name", $.simple_identifier), - ":", - field("pattern", alias($._binding_pattern_with_expr, $.pattern)) - ), - field("pattern", alias($._binding_pattern_with_expr, $.pattern)) - ), - tuple_pattern: ($) => seq("(", sep1Opt(field("item", $.tuple_pattern_item), ","), ")"), - case_pattern: ($) => - seq( - optional("case"), - optional(field("type", $.user_type)), // XXX this should just be _type but that creates ambiguity - field("dot", $._dot), - field("name", $.simple_identifier), - optional(field("arguments", $.tuple_pattern)) - ), - type_casting_pattern: ($) => - choice( - seq("is", field("type", $.type)), - seq(field("pattern", alias($._binding_pattern_no_expr, $.pattern)), $._as, field("type", $.type)) - ), - binding_pattern: ($) => - seq( - seq(optional("case"), field("binding", $.value_binding_pattern)), - field("pattern", alias($._no_expr_pattern_already_bound, $.pattern)) - ), - - // ========== - // Modifiers - // ========== - modifiers: ($) => - repeat1( - prec.left( - field("modifier", choice($._non_local_scope_modifier, $._locally_permitted_modifiers)) - ) - ), - _locally_permitted_modifiers: ($) => - repeat1(choice($.attribute, $._locally_permitted_modifier)), - parameter_modifiers: ($) => repeat1(field("modifier", $.parameter_modifier)), - _modifier: ($) => - choice($._non_local_scope_modifier, $._locally_permitted_modifier), - _non_local_scope_modifier: ($) => - choice( - $.member_modifier, - $.visibility_modifier, - $.function_modifier, - $.mutation_modifier, - $.property_modifier, - $.parameter_modifier - ), - _locally_permitted_modifier: ($) => - choice( - $.ownership_modifier, - $.inheritance_modifier, - $.property_behavior_modifier - ), - property_behavior_modifier: ($) => "lazy", - type_modifiers: ($) => repeat1(field("attribute", $.attribute)), - member_modifier: ($) => - choice("override", "convenience", "required", "nonisolated"), - visibility_modifier: ($) => - seq( - choice( - "public", - "private", - "internal", - "fileprivate", - "open", - "package" - ), - optional(seq("(", "set", ")")) - ), - type_parameter_modifiers: ($) => repeat1(field("attribute", $.attribute)), - function_modifier: ($) => choice("infix", "postfix", "prefix"), - mutation_modifier: ($) => choice("mutating", "nonmutating"), - property_modifier: ($) => - choice("static", "dynamic", "optional", "class", "distributed"), - inheritance_modifier: ($) => choice("final"), - parameter_modifier: ($) => - choice( - "inout", - "@escaping", - "@autoclosure", - $._parameter_ownership_modifier - ), - ownership_modifier: ($) => - choice("weak", "unowned", "unowned(safe)", "unowned(unsafe)"), - _parameter_ownership_modifier: ($) => choice("borrowing", "consuming"), - use_site_target: ($) => - seq( - choice( - "property", - "get", - "set", - "receiver", - "param", - "setparam", - "delegate" - ), - ":" - ), - directive: ($) => - prec.right( - PRECS.comment, - choice( - seq(alias($._directive_if, "#if"), field("condition", $.compilation_condition)), - seq(alias($._directive_elseif, "#elseif"), field("condition", $.compilation_condition)), - seq(alias($._directive_else, "#else")), - seq(alias($._directive_endif, "#endif")) - ) - ), - compilation_condition: ($) => - prec.right( - choice( - seq("os", "(", field("name", $.simple_identifier), ")"), - seq("arch", "(", field("name", $.simple_identifier), ")"), - seq( - "swift", - "(", - $._comparison_operator, - sep1(field("version", $.integer_literal), "."), - ")" - ), - seq( - "compiler", - "(", - $._comparison_operator, - sep1(field("version", $.integer_literal), "."), - ")" - ), - seq("canImport", "(", sep1(field("name", $.simple_identifier), "."), ")"), - seq("targetEnvironment", "(", field("name", $.simple_identifier), ")"), - field("value", $.boolean_literal), - field("name", $.simple_identifier), - seq("(", field("inner", $.compilation_condition), ")"), - seq("!", field("operand", $.compilation_condition)), - seq( - field("lhs", $.compilation_condition), - $._conjunction_operator, - field("rhs", $.compilation_condition) - ), - seq( - field("lhs", $.compilation_condition), - $._disjunction_operator, - field("rhs", $.compilation_condition) - ) - ) - ), - diagnostic: ($) => - prec( - PRECS.comment, - seq( - $._hash_symbol, - choice( - // Using regexes here, rather than actually validating the string literal, because complex string literals - // cannot be used inside `token()` and we need that to ensure we get the right precedence. - seq(/error([^\r\n]*)/), - seq(/warning([^\r\n]*)/), - seq(/sourceLocation([^\r\n]*)/) - ) - ) - ), - // Dumping ground for any nodes that used to exist in the grammar, but have since been removed for whatever - // reason. - // Neovim applies updates non-atomically to the parser and the queries. Meanwhile, `tree-sitter` rejects any query - // that contains any unrecognized nodes. Putting those two facts together, we see that we must never remove nodes - // that once existed. - unused_for_backward_compatibility: ($) => - choice(alias("unused1", "try?"), alias("unused2", "try!")), - }, -}); -function sep1(rule, separator) { - return seq(rule, repeat(seq(separator, rule))); -} -function sep1Opt(rule, separator) { - return seq(rule, repeat(seq(separator, rule)), optional(separator)); -} - -function tree_sitter_version_supports_emoji() { - try { - return ( - TREE_SITTER_CLI_VERSION_MAJOR > 0 || - TREE_SITTER_CLI_VERSION_MINOR > 20 || - TREE_SITTER_CLI_VERSION_PATCH >= 5 - ); - } catch (err) { - if (err instanceof ReferenceError) { - return false; - } else { - throw err; - } - } -} diff --git a/unified/extractor/tree-sitter-swift/node-types.yml b/unified/extractor/tree-sitter-swift/node-types.yml deleted file mode 100644 index 35dfb985b4a8..000000000000 --- a/unified/extractor/tree-sitter-swift/node-types.yml +++ /dev/null @@ -1,875 +0,0 @@ -supertypes: - expression: - - additive_expression - - array_literal - - as_expression - - assignment - - await_expression - - bin_literal - - bitwise_operation - - boolean_literal - - call_expression - - check_expression - - comparison_expression - - conjunction_expression - - constructor_expression - - diagnostic - - dictionary_literal - - directive - - disjunction_expression - - equality_expression - - fully_open_range - - hex_literal - - if_statement - - infix_expression - - integer_literal - - key_path_expression - - key_path_string_expression - - lambda_literal - - line_string_literal - - macro_invocation - - multi_line_string_literal - - multiplicative_expression - - navigation_expression - - "nil" - - nil_coalescing_expression - - oct_literal - - open_end_range_expression - - open_start_range_expression - - optional_chain_marker - - playground_literal - - postfix_expression - - prefix_expression - - range_expression - - raw_string_literal - - real_literal - - referenceable_operator - - regex_literal - - selector_expression - - self_expression - - simple_identifier - - special_literal - - super_expression - - switch_statement - - ternary_expression - - try_expression - - tuple_expression - - value_pack_expansion - - value_parameter_pack - global_declaration: - - associatedtype_declaration - - class_declaration - - function_declaration - - import_declaration - - init_declaration - - macro_declaration - - operator_declaration - - precedence_group_declaration - - property_declaration - - protocol_declaration - - typealias_declaration - local_declaration: - - class_declaration - - function_declaration - - property_declaration - - typealias_declaration - protocol_member_declaration: - - associatedtype_declaration - - deinit_declaration - - init_declaration - - protocol_function_declaration - - protocol_property_declaration - - subscript_declaration - - typealias_declaration - type_level_declaration: - - associatedtype_declaration - - class_declaration - - deinit_declaration - - function_declaration - - import_declaration - - init_declaration - - operator_declaration - - precedence_group_declaration - - property_declaration - - protocol_declaration - - subscript_declaration - - typealias_declaration - unannotated_type: - - array_type - - dictionary_type - - existential_type - - function_type - - metatype - - opaque_type - - optional_type - - protocol_composition_type - - suppressed_constraint - - tuple_type - - type_pack_expansion - - type_parameter_pack - - user_type - -named: - additive_expression: - lhs: expression - op: ["+", "-"] - rhs: expression - array_literal: - element*: expression - array_type: - element: type - as_expression: - expr: expression - operator: as_operator - type: type - as_operator: - assignment: - operator: ["%=", "*=", "+=", "-=", "/=", "="] - result: expression - target: directly_assignable_expression - associatedtype_declaration: - default_value?: type - modifiers?: modifiers - must_inherit?: type - name: type_identifier - type_constraints?: type_constraints - async_keyword: - attribute: - argument*: expression - argument_name*: simple_identifier - name: user_type - param_ref*: simple_identifier - platform*: simple_identifier - version*: integer_literal - availability_condition: - platform*: identifier - version*: integer_literal - await_expression: - expr: expression - bang: - bin_literal: - binding_pattern: - binding: value_binding_pattern - pattern: pattern - bitwise_operation: - lhs: expression - op: ["&", "<<", ">>", "^", "|"] - rhs: expression - block: - statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - boolean_literal: - call_expression: - function: expression - suffix: call_suffix - call_suffix: - arguments?: value_arguments - lambda*: lambda_literal - name*: simple_identifier - capture_list: - item+: capture_list_item - capture_list_item: - name: [self_expression, simple_identifier] - ownership?: ownership_modifier - value?: expression - case_pattern: - arguments?: tuple_pattern - dot: "." - name: simple_identifier - type?: user_type - catch_block: - body: block - error?: pattern - keyword: catch_keyword - where?: where_clause - catch_keyword: - check_expression: - op: "is" - target: expression - type: type - class_body: - member*: type_level_declaration - class_declaration: - attribute*: attribute - body: [class_body, enum_class_body] - declaration_kind: ["actor", "class", "enum", "extension", "struct"] - inherits*: inheritance_specifier - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - name: [type_identifier, unannotated_type] - type_constraints?: type_constraints - type_parameters?: type_parameters - comment: - comparison_expression: - lhs: expression - op: ["<", "<=", ">", ">="] - rhs: expression - compilation_condition: - inner?: compilation_condition - lhs?: compilation_condition - name*: simple_identifier - operand?: compilation_condition - rhs?: compilation_condition - value?: boolean_literal - version*: integer_literal - computed_getter: - attribute*: attribute - body?: block - specifier: getter_specifier - computed_modify: - attribute*: attribute - body?: block - specifier: modify_specifier - computed_property: - accessor*: [computed_getter, computed_modify, computed_setter] - statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - computed_setter: - attribute*: attribute - body?: block - parameter?: simple_identifier - specifier: setter_specifier - conjunction_expression: - lhs: expression - op: "&&" - rhs: expression - constructor_expression: - constructed_type: [array_type, dictionary_type, user_type] - suffix: constructor_suffix - constructor_suffix: - arguments?: value_arguments - lambda*: lambda_literal - name*: simple_identifier - control_transfer_statement: - kind: ["break", "continue", "return", throw_keyword, "yield"] - result?: expression - custom_operator: - default_keyword: - deinit_declaration: - body: block - modifiers?: modifiers - deprecated_operator_declaration_body: - entry*: [bin_literal, boolean_literal, hex_literal, integer_literal, line_string_literal, multi_line_string_literal, "nil", oct_literal, raw_string_literal, real_literal, regex_literal, simple_identifier] - diagnostic: - dictionary_literal: - element*: dictionary_literal_item - dictionary_literal_item: - key: expression - value: expression - dictionary_type: - key: type - value: type - didset_clause: - body: block - modifiers?: modifiers - parameter?: simple_identifier - directive: - condition?: compilation_condition - directly_assignable_expression: - expr: expression - disjunction_expression: - lhs: expression - op: "||" - rhs: expression - do_statement: - body: block - catch*: catch_block - enum_case_entry: - data_contents?: enum_type_parameters - name: simple_identifier - raw_value?: expression - enum_class_body: - member*: [enum_entry, type_level_declaration] - enum_entry: - case+: enum_case_entry - modifiers?: modifiers - enum_type_parameter: - default_value?: expression - external_name?: wildcard_pattern - name?: simple_identifier - type: type - enum_type_parameters: - parameter*: enum_type_parameter - equality_constraint: - attribute*: attribute - constrained_type: [identifier, nested_type_identifier] - must_equal: type - equality_expression: - lhs: expression - op: ["!=", "!==", "==", "==="] - rhs: expression - existential_type: - name: unannotated_type - external_macro_definition: - arguments: value_arguments - for_statement: - body: block - collection: expression - item: pattern - try?: try_operator - type?: type_annotation - where?: where_clause - fully_open_range: - function_declaration: - async?: "async" - body: block - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - name: [referenceable_operator, simple_identifier] - parameter*: function_parameter - return_type?: [implicitly_unwrapped_type, type] - throws?: [throws, throws_clause] - type_constraints?: type_constraints - type_parameters?: type_parameters - function_modifier: - function_parameter: - attribute?: attribute - default_value?: expression - parameter: parameter - function_type: - async?: "async" - params: unannotated_type - return_type: type - throws?: [throws, throws_clause] - getter_specifier: - effect*: [async_keyword, throws, throws_clause] - mutation?: mutation_modifier - guard_statement: - body: block - condition+: if_condition - hex_literal: - identifier: - part+: simple_identifier - if_condition: - kind: [availability_condition, expression, if_let_binding] - if_let_binding: - pattern: pattern - type?: type_annotation - value?: expression - where?: where_clause - if_statement: - body: block - condition+: if_condition - else_branch?: [block, if_statement] - implicitly_unwrapped_type: - name: type - import_declaration: - modifiers?: modifiers - name: identifier - scoped_import_kind?: ["class", "enum", "func", "let", "protocol", "struct", "typealias", "var"] - infix_expression: - lhs: expression - op: custom_operator - rhs: expression - inheritance_constraint: - attribute*: attribute - constrained_type: [identifier, nested_type_identifier] - inherits_from: [implicitly_unwrapped_type, type] - inheritance_modifier: - inheritance_specifier: - inherits_from: [function_type, suppressed_constraint, user_type] - init_declaration: - async?: "async" - bang?: bang - body?: block - modifiers?: modifiers - parameter*: function_parameter - throws?: [throws, throws_clause] - type_constraints?: type_constraints - type_parameters?: type_parameters - integer_literal: - interpolated_expression: - name?: value_argument_label - reference_specifier*: value_argument_label - type_modifiers?: type_modifiers - value?: expression - key_path_component: - name?: simple_identifier - postfix*: key_path_postfix - key_path_expression: - component*: key_path_component - type?: [array_type, dictionary_type, simple_user_type] - key_path_postfix: - argument*: value_argument - force_unwrap?: bang - key_path_string_expression: - expr: expression - lambda_function_type: - async?: "async" - params?: lambda_function_type_parameters - return_type?: [implicitly_unwrapped_type, type] - throws?: [throws, throws_clause] - lambda_function_type_parameters: - parameter+: lambda_parameter - lambda_literal: - attribute*: attribute - captures?: capture_list - statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - type?: lambda_function_type - lambda_parameter: - external_name?: simple_identifier - modifiers?: parameter_modifiers - name: [self_expression, simple_identifier] - type?: [implicitly_unwrapped_type, type] - line_str_text: - line_string_literal: - interpolation*: interpolated_expression - text*: [line_str_text, str_escaped_char] - macro_declaration: - definition?: macro_definition - modifiers?: modifiers - name: simple_identifier - parameter*: function_parameter - return_type?: unannotated_type - type_constraints?: type_constraints - type_parameters?: type_parameters - macro_definition: - body: [expression, external_macro_definition] - macro_invocation: - name: simple_identifier - suffix: call_suffix - type_parameters?: type_parameters - member_modifier: - metatype: - name: unannotated_type - modifiers: - modifier+: [attribute, function_modifier, inheritance_modifier, member_modifier, mutation_modifier, ownership_modifier, parameter_modifier, property_behavior_modifier, property_modifier, visibility_modifier] - modify_specifier: - mutation?: mutation_modifier - multi_line_str_text: - multi_line_string_literal: - interpolation*: interpolated_expression - text*: ["\"", multi_line_str_text, str_escaped_char] - multiline_comment: - multiplicative_expression: - lhs: expression - op: ["%", "*", "/"] - rhs: expression - mutation_modifier: - navigation_expression: - suffix: navigation_suffix - target: [array_type, dictionary_type, expression, parenthesized_type, user_type] - navigation_suffix: - suffix: [integer_literal, simple_identifier] - nested_type_identifier: - base: unannotated_type - member*: simple_identifier - nil_coalescing_expression: - if_nil: expression - value: expression - oct_literal: - opaque_type: - name: unannotated_type - open_end_range_expression: - start: expression - open_start_range_expression: - end: expression - operator_declaration: - body?: deprecated_operator_declaration_body - kind: ["infix", "postfix", "prefix"] - name: referenceable_operator - precedence_group?: simple_identifier - optional_chain_marker: - expr: expression - optional_type: - wrapped: [array_type, dictionary_type, tuple_type, user_type] - ownership_modifier: - parameter: - external_name?: simple_identifier - modifiers?: parameter_modifiers - name: simple_identifier - type: [implicitly_unwrapped_type, type] - parameter_modifier: - parameter_modifiers: - modifier+: parameter_modifier - parenthesized_type: - type: [dictionary_type, existential_type, opaque_type] - pattern: - binding?: value_binding_pattern - bound_identifier?: simple_identifier - kind: [binding_pattern, case_pattern, expression, tuple_pattern, type_casting_pattern, wildcard_pattern] - playground_literal: - argument+: playground_literal_argument - kind: ["colorLiteral", "fileLiteral", "imageLiteral"] - playground_literal_argument: - name: simple_identifier - value: expression - postfix_expression: - operation: ["++", "--", bang] - target: expression - precedence_group_attribute: - name: simple_identifier - value: [boolean_literal, simple_identifier] - precedence_group_attributes: - attribute+: precedence_group_attribute - precedence_group_declaration: - attributes?: precedence_group_attributes - name: simple_identifier - prefix_expression: - operation: ["&", "+", "++", "-", "--", ".", bang, custom_operator, "~"] - target: expression - property_behavior_modifier: - property_binding: - computed_value?: computed_property - name: pattern - observers?: willset_didset_block - type?: type_annotation - type_constraints?: type_constraints - value?: expression - property_declaration: - binding: value_binding_pattern - declarator+: property_binding - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - property_modifier: - protocol_body: - member*: protocol_member_declaration - protocol_composition_type: - type+: unannotated_type - protocol_declaration: - attribute*: attribute - body: protocol_body - inherits*: inheritance_specifier - modifiers?: modifiers - name: type_identifier - type_constraints?: type_constraints - type_parameters?: type_parameters - protocol_function_declaration: - async?: "async" - body?: block - modifiers?: modifiers - name: [referenceable_operator, simple_identifier] - parameter*: function_parameter - return_type?: [implicitly_unwrapped_type, type] - throws?: [throws, throws_clause] - type_constraints?: type_constraints - type_parameters?: type_parameters - protocol_property_declaration: - modifiers?: modifiers - name: pattern - requirements: protocol_property_requirements - type?: type_annotation - type_constraints?: type_constraints - protocol_property_requirements: - accessor*: [getter_specifier, setter_specifier] - range_expression: - end: expression - op: ["...", "..<"] - start: expression - raw_str_continuing_indicator: - raw_str_end_part: - raw_str_interpolation: - interpolation+: interpolated_expression - start: raw_str_interpolation_start - raw_str_interpolation_start: - raw_str_part: - raw_string_literal: - continuing*: raw_str_continuing_indicator - interpolation*: raw_str_interpolation - text+: [raw_str_end_part, raw_str_part] - real_literal: - referenceable_operator: - operator: ["!=", "!==", "%", "%=", "&", "*", "*=", "+", "++", "+=", "-", "--", "-=", "/", "/=", "<", "<<", "<=", "=", "==", "===", ">", ">=", ">>", "^", bang, custom_operator, "|", "~"] - regex_literal: - repeat_while_statement: - body: block - condition+: if_condition - selector_expression: - expr: expression - self_expression: - setter_specifier: - mutation?: mutation_modifier - shebang_line: - simple_identifier: - simple_user_type: - arguments?: type_arguments - name: type_identifier - source_file: - shebang?: shebang_line - statement*: [do_statement, expression, for_statement, global_declaration, guard_statement, repeat_while_statement, statement_label, throw_keyword, while_statement] - special_literal: - statement_label: - str_escaped_char: - subscript_declaration: - body: computed_property - modifiers?: modifiers - parameter*: function_parameter - return_type?: [implicitly_unwrapped_type, type] - type_constraints?: type_constraints - type_parameters?: type_parameters - super_expression: - suppressed_constraint: - suppressed: type_identifier - switch_entry: - default?: default_keyword - modifiers?: modifiers - pattern*: switch_pattern - statement+: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement] - where?: where_clause - switch_pattern: - pattern: pattern - switch_statement: - entry*: switch_entry - expr: expression - ternary_expression: - condition: expression - if_false: expression - if_true: expression - throw_keyword: - throws: - throws_clause: - type: unannotated_type - try_expression: - expr: expression - operator: try_operator - try_operator: - tuple_expression: - element+: tuple_expression_item - tuple_expression_item: - name?: simple_identifier - value: expression - tuple_pattern: - item+: tuple_pattern_item - tuple_pattern_item: - name?: simple_identifier - pattern: pattern - tuple_type: - element*: tuple_type_item - tuple_type_item: - external_name?: wildcard_pattern - modifiers?: parameter_modifiers - name?: simple_identifier - type: [dictionary_type, existential_type, opaque_type, type] - type: - modifiers?: type_modifiers - name: unannotated_type - type_annotation: - type: [implicitly_unwrapped_type, type] - type_arguments: - argument+: type - type_casting_pattern: - pattern?: pattern - type: type - type_constraint: - constraint: [equality_constraint, inheritance_constraint] - type_constraints: - constraint+: type_constraint - keyword: where_keyword - type_identifier: - type_modifiers: - attribute+: attribute - type_pack_expansion: - name: unannotated_type - type_parameter: - modifiers?: type_parameter_modifiers - name: [type_identifier, type_parameter_pack] - type?: type - type_parameter_modifiers: - attribute+: attribute - type_parameter_pack: - name: unannotated_type - type_parameters: - constraints?: type_constraints - parameter+: type_parameter - typealias_declaration: - modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier] - name: type_identifier - type_parameters?: type_parameters - value: type - user_type: - part+: simple_user_type - value_argument: - name?: value_argument_label - reference_specifier*: value_argument_label - type_modifiers?: type_modifiers - value?: expression - value_argument_label: - name: simple_identifier - value_arguments: - argument*: value_argument - value_binding_pattern: - mutability: ["let", "var"] - value_pack_expansion: - expr: expression - value_parameter_pack: - expr: expression - visibility_modifier: - where_clause: - expr: expression - keyword: where_keyword - where_keyword: - while_statement: - body: block - condition+: if_condition - wildcard_pattern: - willset_clause: - body: block - modifiers?: modifiers - parameter?: simple_identifier - willset_didset_block: - didset?: didset_clause - willset?: willset_clause - -unnamed: - - "?" - - "!" - - "!=" - - "!==" - - "\"" - - "\"\"\"" - - "#" - - "#else" - - "#elseif" - - "#endif" - - "#if" - - "%" - - "%=" - - "&" - - "&&" - - "(" - - ")" - - "*" - - "*=" - - "+" - - "++" - - "+=" - - "," - - "-" - - "--" - - "-=" - - "->" - - "." - - "..." - - "..<" - - "/" - - "/=" - - ":" - - ";" - - "<" - - "<<" - - "<=" - - "=" - - "==" - - "===" - - ">" - - ">=" - - ">>" - - "?" - - "??" - - "@" - - "@autoclosure" - - "@escaping" - - "Protocol" - - "Type" - - "[" - - "\\" - - "\\(" - - "]" - - "^" - - "^{" - - "_modify" - - "actor" - - "any" - - "arch" - - "as" - - "as!" - - "as?" - - "associatedtype" - - "async" - - "available" - - "await" - - "borrowing" - - "break" - - "canImport" - - "case" - - "class" - - "colorLiteral" - - "column" - - "compiler" - - "consuming" - - "continue" - - "convenience" - - "deinit" - - "didSet" - - "distributed" - - "do" - - "dsohandle" - - "dynamic" - - "each" - - "else" - - "enum" - - "extension" - - "externalMacro" - - "fallthrough" - - "false" - - "file" - - "fileID" - - "fileLiteral" - - "filePath" - - "fileprivate" - - "final" - - "for" - - "func" - - "function" - - "get" - - "getter:" - - "guard" - - "if" - - "imageLiteral" - - "import" - - "in" - - "indirect" - - "infix" - - "init" - - "inout" - - "internal" - - "is" - - "keyPath" - - "lazy" - - "let" - - "line" - - "macro" - - "mutating" - - "nil" - - "nonisolated" - - "nonmutating" - - "open" - - "operator" - - "optional" - - "os" - - "override" - - "package" - - "postfix" - - "precedencegroup" - - "prefix" - - "private" - - "protocol" - - "public" - - "repeat" - - "required" - - "return" - - "selector" - - "self" - - "set" - - "setter:" - - "some" - - "static" - - "struct" - - "subscript" - - "super" - - "swift" - - "switch" - - "targetEnvironment" - - "true" - - "try" - - "typealias" - - "u" - - "unavailable" - - "unowned" - - "unowned(safe)" - - "unowned(unsafe)" - - "var" - - "weak" - - "while" - - "willSet" - - "yield" - - "{" - - "|" - - "||" - - "}" - - "~" diff --git a/unified/extractor/tree-sitter-swift/package.json b/unified/extractor/tree-sitter-swift/package.json deleted file mode 100644 index 68dcf7cc42fc..000000000000 --- a/unified/extractor/tree-sitter-swift/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "tree-sitter-swift", - "version": "0.7.2", - "description": "A tree-sitter grammar for the Swift programming language.", - "main": "bindings/node/index.js", - "types": "bindings/node", - "scripts": { - "install": "node-gyp-build", - "prestart": "tree-sitter build --wasm", - "start": "tree-sitter playground", - "test": "node --test bindings/node/*_test.js" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/alex-pinkus/tree-sitter-swift.git" - }, - "tree-sitter": [ - { - "scope": "source.swift", - "file-types": [ - "swift" - ], - "injection-regex": "swift", - "highlights": "queries/highlights.scm", - "locals": "queries/locals.scm", - "injections": "queries/injections.scm" - } - ], - "keywords": [ - "parser", - "swift" - ], - "files": [ - "grammar.js", - "tree-sitter.json", - "binding.gyp", - "prebuilds/**", - "bindings/node/*", - "queries/*", - "scripts/*", - "src/**" - ], - "author": "Alex Pinkus ", - "license": "MIT", - "bugs": { - "url": "https://github.com/alex-pinkus/tree-sitter-swift/issues" - }, - "homepage": "https://github.com/alex-pinkus/tree-sitter-swift#readme", - "dependencies": { - "node-addon-api": "^8.0.0", - "node-gyp-build": "^4.8.0", - "tree-sitter-cli": "^0.23", - "which": "2.0.2" - }, - "peerDependencies": { - "tree-sitter": "^0.22.1" - }, - "peerDependenciesMeta": { - "tree_sitter": { - "optional": true - } - }, - "devDependencies": { - "node-gyp": "^10.0.1", - "prebuildify": "^6.0.0", - "prettier": "2.3.2" - } -} diff --git a/unified/extractor/tree-sitter-swift/queries/folds.scm b/unified/extractor/tree-sitter-swift/queries/folds.scm deleted file mode 100644 index ca7f72593aa8..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/folds.scm +++ /dev/null @@ -1,35 +0,0 @@ -; format-ignore -[ - (protocol_body) ; protocol Foo { ... } - (class_body) ; class Foo { ... } - (enum_class_body) ; enum Foo { ... } - (function_body) ; func Foo (...) {...} - (computed_property) ; { ... } - - (computed_getter) ; get { ... } - (computed_setter) ; set { ... } - - (do_statement) - (if_statement) - (for_statement) - (switch_statement) - (while_statement) - (guard_statement) - (switch_entry) - - (type_parameters) ; x - (tuple_type) ; (...) - (array_type) ; [String] - (dictionary_type) ; [Foo: Bar] - - (call_expression) ; callFunc(...) - (tuple_expression) ; ( foo + bar ) - (array_literal) ; [ foo, bar ] - (dictionary_literal) ; [ foo: bar, x: y ] - (lambda_literal) - (willset_didset_block) - (willset_clause) - (didset_clause) - - (import_declaration)+ -] @fold diff --git a/unified/extractor/tree-sitter-swift/queries/highlights.scm b/unified/extractor/tree-sitter-swift/queries/highlights.scm deleted file mode 100644 index 82ad68d4ed1c..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/highlights.scm +++ /dev/null @@ -1,336 +0,0 @@ -[ - "." - ";" - ":" - "," -] @punctuation.delimiter - -[ - "(" - ")" - "[" - "]" - "{" - "}" -] @punctuation.bracket - -; Identifiers -(type_identifier) @type - -[ - (self_expression) - (super_expression) -] @variable.builtin - -; Declarations -[ - "func" - "deinit" -] @keyword.function - -[ - (visibility_modifier) - (member_modifier) - (function_modifier) - (property_modifier) - (parameter_modifier) - (inheritance_modifier) - (mutation_modifier) -] @keyword.modifier - -(simple_identifier) @variable - -(function_declaration - (simple_identifier) @function.method) - -(protocol_function_declaration - name: (simple_identifier) @function.method) - -(init_declaration - "init" @constructor) - -(parameter - external_name: (simple_identifier) @variable.parameter) - -(parameter - name: (simple_identifier) @variable.parameter) - -(type_parameter - (type_identifier) @variable.parameter) - -(inheritance_constraint - (identifier - (simple_identifier) @variable.parameter)) - -(equality_constraint - (identifier - (simple_identifier) @variable.parameter)) - -[ - "protocol" - "extension" - "indirect" - "nonisolated" - "override" - "convenience" - "required" - "some" - "any" - "weak" - "unowned" - "didSet" - "willSet" - "subscript" - "let" - "var" - (throws) - (where_keyword) - (getter_specifier) - (setter_specifier) - (modify_specifier) - (else) - (as_operator) -] @keyword - -[ - "enum" - "struct" - "class" - "typealias" -] @keyword.type - -[ - "async" - "await" -] @keyword.coroutine - -(shebang_line) @keyword.directive - -(class_body - (property_declaration - (pattern - (simple_identifier) @variable.member))) - -(protocol_property_declaration - (pattern - (simple_identifier) @variable.member)) - -(navigation_expression - (navigation_suffix - (simple_identifier) @variable.member)) - -(value_argument - name: (value_argument_label - (simple_identifier) @variable.member)) - -(import_declaration - "import" @keyword.import) - -(enum_entry - "case" @keyword) - -(modifiers - (attribute - "@" @attribute - (user_type - (type_identifier) @attribute))) - -; Function calls -(call_expression - (simple_identifier) @function.call) ; foo() - -(call_expression - ; foo.bar.baz(): highlight the baz() - (navigation_expression - (navigation_suffix - (simple_identifier) @function.call))) - -(call_expression - (prefix_expression - (simple_identifier) @function.call)) ; .foo() - -((navigation_expression - (simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type - (#match? @type "^[A-Z]")) - -(directive) @keyword.directive - -; See https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Keywords-and-Punctuation -[ - (diagnostic) - (availability_condition) - (playground_literal) - (key_path_string_expression) - (selector_expression) - (external_macro_definition) -] @function.macro - -(special_literal) @constant.macro - -; Statements -(for_statement - "for" @keyword.repeat) - -(for_statement - "in" @keyword.repeat) - -[ - "while" - "repeat" - "continue" - "break" -] @keyword.repeat - -(guard_statement - "guard" @keyword.conditional) - -(if_statement - "if" @keyword.conditional) - -(switch_statement - "switch" @keyword.conditional) - -(switch_entry - "case" @keyword) - -(switch_entry - "fallthrough" @keyword) - -(switch_entry - (default_keyword) @keyword) - -"return" @keyword.return - -(ternary_expression - [ - "?" - ":" - ] @keyword.conditional.ternary) - -[ - (try_operator) - "do" - (throw_keyword) - (catch_keyword) -] @keyword.exception - -(statement_label) @label - -; Comments -[ - (comment) - (multiline_comment) -] @comment @spell - -((comment) @comment.documentation - (#match? @comment.documentation "^///[^/]")) - -((comment) @comment.documentation - (#match? @comment.documentation "^///$")) - -((multiline_comment) @comment.documentation - (#match? @comment.documentation "^/[*][*][^*].*[*]/$")) - -; String literals -(line_str_text) @string - -(str_escaped_char) @string.escape - -(multi_line_str_text) @string - -(raw_str_part) @string - -(raw_str_end_part) @string - -(line_string_literal - [ - "\\(" - ")" - ] @punctuation.special) - -(multi_line_string_literal - [ - "\\(" - ")" - ] @punctuation.special) - -(raw_str_interpolation - [ - (raw_str_interpolation_start) - ")" - ] @punctuation.special) - -[ - "\"" - "\"\"\"" -] @string - -; Lambda literals -(lambda_literal - "in" @keyword.operator) - -; Basic literals -[ - (integer_literal) - (hex_literal) - (oct_literal) - (bin_literal) -] @number - -(real_literal) @number.float - -(boolean_literal) @boolean - -"nil" @constant.builtin - -(wildcard_pattern) @character.special - -; Regex literals -(regex_literal) @string.regexp - -; Operators -(custom_operator) @operator - -[ - "+" - "-" - "*" - "/" - "%" - "=" - "+=" - "-=" - "*=" - "/=" - "<" - ">" - "<<" - ">>" - "<=" - ">=" - "++" - "--" - "^" - "&" - "&&" - "|" - "||" - "~" - "%=" - "!=" - "!==" - "==" - "===" - "?" - "??" - "->" - "..<" - "..." - (bang) -] @operator - -(type_arguments - [ - "<" - ">" - ] @punctuation.bracket) diff --git a/unified/extractor/tree-sitter-swift/queries/indents.scm b/unified/extractor/tree-sitter-swift/queries/indents.scm deleted file mode 100644 index ec8f8af95c6f..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/indents.scm +++ /dev/null @@ -1,123 +0,0 @@ -; format-ignore -[ - ; ... refers to the section that will get affected by this indent.begin capture - (protocol_body) ; protocol Foo { ... } - (class_body) ; class Foo { ... } - (enum_class_body) ; enum Foo { ... } - (function_declaration) ; func Foo (...) {...} - (init_declaration) ; init(...) {...} - (deinit_declaration) ; deinit {...} - (computed_property) ; { ... } - (subscript_declaration) ; subscript Foo(...) { ... } - - (computed_getter) ; get { ... } - (computed_setter) ; set { ... } - - (assignment) ; a = b - - (control_transfer_statement) ; return ... - (for_statement) - (while_statement) - (repeat_while_statement) - (do_statement) - (if_statement) - (switch_statement) - (guard_statement) - - (type_parameters) ; x - (tuple_type) ; (...) - (array_type) ; [String] - (dictionary_type) ; [Foo: Bar] - - (call_expression) ; callFunc(...) - (tuple_expression) ; ( foo + bar ) - (array_literal) ; [ foo, bar ] - (dictionary_literal) ; [ foo: bar, x: y ] - (lambda_literal) - (willset_didset_block) - (willset_clause) - (didset_clause) -] @indent.begin - -(init_declaration) @indent.begin - -(init_declaration - [ - "init" - "(" - ] @indent.branch) - -; indentation for init parameters -(init_declaration - ")" @indent.branch @indent.end) - -(init_declaration - (parameter) @indent.begin - (#set! indent.immediate)) - -; @something(...) -(modifiers - (attribute) @indent.begin) - -(function_declaration - (modifiers - . - (attribute) - (_)* @indent.branch) - . - _ @indent.branch - (#not-kind-eq? @indent.branch "type_parameters" "parameter")) - -(ERROR - [ - "<" - "{" - "(" - "[" - ]) @indent.begin - -; if-elseif -(if_statement - (if_statement) @indent.dedent) - -; case Foo: -; default Foo: -; @attribute default Foo: -(switch_entry - . - _ @indent.branch) - -(function_declaration - ")" @indent.branch) - -(type_parameters - ">" @indent.branch @indent.end .) - -(tuple_expression - ")" @indent.branch @indent.end) - -(value_arguments - ")" @indent.branch @indent.end) - -(tuple_type - ")" @indent.branch @indent.end) - -(modifiers - (attribute - ")" @indent.branch @indent.end)) - -[ - "}" - "]" -] @indent.branch @indent.end - -[ - ; (ERROR) - (comment) - (multiline_comment) - (raw_str_part) - (multi_line_string_literal) -] @indent.auto - -(directive) @indent.ignore - diff --git a/unified/extractor/tree-sitter-swift/queries/injections.scm b/unified/extractor/tree-sitter-swift/queries/injections.scm deleted file mode 100644 index 512cfa0d5223..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/injections.scm +++ /dev/null @@ -1,10 +0,0 @@ -; Parse regex syntax within regex literals - -((regex_literal) @injection.content - (#set! injection.language "regex")) - -([ - (comment) - (multiline_comment) -] @injection.content - (#set! injection.language "comment")) diff --git a/unified/extractor/tree-sitter-swift/queries/locals.scm b/unified/extractor/tree-sitter-swift/queries/locals.scm deleted file mode 100644 index 78032a81810b..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/locals.scm +++ /dev/null @@ -1,23 +0,0 @@ -(import_declaration - (identifier) @local.definition.import) - -(function_declaration - name: (simple_identifier) @local.definition.function) - -; Scopes -[ - (statements) - (for_statement) - (while_statement) - (repeat_while_statement) - (do_statement) - (if_statement) - (guard_statement) - (switch_statement) - (property_declaration) - (function_declaration) - (class_declaration) - (protocol_declaration) -] @local.scope - - diff --git a/unified/extractor/tree-sitter-swift/queries/outline.scm b/unified/extractor/tree-sitter-swift/queries/outline.scm deleted file mode 100644 index 31fe5d9d4a43..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/outline.scm +++ /dev/null @@ -1,66 +0,0 @@ -(protocol_declaration - declaration_kind: "protocol" @name - . - _ * @name - . - body: (protocol_body) -) @item - -(class_declaration - declaration_kind: ( - [ - "actor" - "class" - "extension" - "enum" - "struct" - ] - ) @name - . - _ * @name - . - body: (_) -) @item - -(init_declaration - name: "init" @name - . - _ * @name - . - body: (function_body) -) @item - -(deinit_declaration - "deinit" @name) @item - -(function_declaration - "func" @name - . - _ * @name - . - body: (function_body) -) @item - -(class_body - (property_declaration - (value_binding_pattern) @name - name: (pattern) @name - (type_annotation)? @name - ) @item -) - -(enum_class_body - (property_declaration - (value_binding_pattern) @name - name: (pattern) @name - (type_annotation)? @name - ) @item -) - -( - (protocol_function_declaration) @name -) @item - -( - (protocol_property_declaration) @name -) @item diff --git a/unified/extractor/tree-sitter-swift/queries/tags.scm b/unified/extractor/tree-sitter-swift/queries/tags.scm deleted file mode 100644 index 0038571e5d72..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/tags.scm +++ /dev/null @@ -1,51 +0,0 @@ -(class_declaration - name: (type_identifier) @name) @definition.class - -(protocol_declaration - name: (type_identifier) @name) @definition.interface - -(class_declaration - (class_body - [ - (function_declaration - name: (simple_identifier) @name - ) - (subscript_declaration - (parameter (simple_identifier) @name) - ) - (init_declaration "init" @name) - (deinit_declaration "deinit" @name) - ] - ) -) @definition.method - -(protocol_declaration - (protocol_body - [ - (protocol_function_declaration - name: (simple_identifier) @name - ) - (subscript_declaration - (parameter (simple_identifier) @name) - ) - (init_declaration "init" @name) - ] - ) -) @definition.method - -(class_declaration - (class_body - [ - (property_declaration - (pattern (simple_identifier) @name) - ) - ] - ) -) @definition.property - -(property_declaration - (pattern (simple_identifier) @name) -) @definition.property - -(function_declaration - name: (simple_identifier) @name) @definition.function \ No newline at end of file diff --git a/unified/extractor/tree-sitter-swift/queries/textobjects.scm b/unified/extractor/tree-sitter-swift/queries/textobjects.scm deleted file mode 100644 index da689a1b29f6..000000000000 --- a/unified/extractor/tree-sitter-swift/queries/textobjects.scm +++ /dev/null @@ -1,19 +0,0 @@ - - -; MARK: Structure - -(function_declaration - body: (_) @function.inside) @function.around - -; TODO: Classes/structs/enums - - -; MARK: Tests - -; Only matches prefix test. Other conventions -; might be nice to add! -(function_declaration - name: (simple_identifier) @_name - (#match? @_name "^test") -) - diff --git a/unified/extractor/tree-sitter-swift/src/scanner.c b/unified/extractor/tree-sitter-swift/src/scanner.c deleted file mode 100644 index bb2dcac58b28..000000000000 --- a/unified/extractor/tree-sitter-swift/src/scanner.c +++ /dev/null @@ -1,929 +0,0 @@ -#include "tree_sitter/parser.h" -#include -#include - -#define TOKEN_COUNT 33 - -enum TokenType { - BLOCK_COMMENT, - RAW_STR_PART, - RAW_STR_CONTINUING_INDICATOR, - RAW_STR_END_PART, - IMPLICIT_SEMI, - EXPLICIT_SEMI, - ARROW_OPERATOR, - DOT_OPERATOR, - CONJUNCTION_OPERATOR, - DISJUNCTION_OPERATOR, - NIL_COALESCING_OPERATOR, - EQUAL_SIGN, - EQ_EQ, - PLUS_THEN_WS, - MINUS_THEN_WS, - BANG, - THROWS_KEYWORD, - RETHROWS_KEYWORD, - DEFAULT_KEYWORD, - WHERE_KEYWORD, - ELSE_KEYWORD, - CATCH_KEYWORD, - AS_KEYWORD, - AS_QUEST, - AS_BANG, - ASYNC_KEYWORD, - CUSTOM_OPERATOR, - HASH_SYMBOL, - DIRECTIVE_IF, - DIRECTIVE_ELSEIF, - DIRECTIVE_ELSE, - DIRECTIVE_ENDIF, - FAKE_TRY_BANG -}; - -#define OPERATOR_COUNT 20 - -const char* OPERATORS[OPERATOR_COUNT] = { - "->", - ".", - "&&", - "||", - "??", - "=", - "==", - "+", - "-", - "!", - "throws", - "rethrows", - "default", - "where", - "else", - "catch", - "as", - "as?", - "as!", - "async" -}; - -enum IllegalTerminatorGroup { - ALPHANUMERIC, - OPERATOR_SYMBOLS, - OPERATOR_OR_DOT, - NON_WHITESPACE -}; - -const enum IllegalTerminatorGroup OP_ILLEGAL_TERMINATORS[OPERATOR_COUNT] = { - OPERATOR_SYMBOLS, // -> - OPERATOR_OR_DOT, // . - OPERATOR_SYMBOLS, // && - OPERATOR_SYMBOLS, // || - OPERATOR_SYMBOLS, // ?? - OPERATOR_SYMBOLS, // = - OPERATOR_SYMBOLS, // == - NON_WHITESPACE, // + - NON_WHITESPACE, // - - OPERATOR_SYMBOLS, // ! - ALPHANUMERIC, // throws - ALPHANUMERIC, // rethrows - ALPHANUMERIC, // default - ALPHANUMERIC, // where - ALPHANUMERIC, // else - ALPHANUMERIC, // catch - ALPHANUMERIC, // as - OPERATOR_SYMBOLS, // as? - OPERATOR_SYMBOLS, // as! - ALPHANUMERIC // async -}; - -const enum TokenType OP_SYMBOLS[OPERATOR_COUNT] = { - ARROW_OPERATOR, - DOT_OPERATOR, - CONJUNCTION_OPERATOR, - DISJUNCTION_OPERATOR, - NIL_COALESCING_OPERATOR, - EQUAL_SIGN, - EQ_EQ, - PLUS_THEN_WS, - MINUS_THEN_WS, - BANG, - THROWS_KEYWORD, - RETHROWS_KEYWORD, - DEFAULT_KEYWORD, - WHERE_KEYWORD, - ELSE_KEYWORD, - CATCH_KEYWORD, - AS_KEYWORD, - AS_QUEST, - AS_BANG, - ASYNC_KEYWORD -}; - -const uint64_t OP_SYMBOL_SUPPRESSOR[OPERATOR_COUNT] = { - 0, // ARROW_OPERATOR, - 0, // DOT_OPERATOR, - 0, // CONJUNCTION_OPERATOR, - 0, // DISJUNCTION_OPERATOR, - 0, // NIL_COALESCING_OPERATOR, - 0, // EQUAL_SIGN, - 0, // EQ_EQ, - 0, // PLUS_THEN_WS, - 0, // MINUS_THEN_WS, - 1UL << FAKE_TRY_BANG, // BANG, - 0, // THROWS_KEYWORD, - 0, // RETHROWS_KEYWORD, - 0, // DEFAULT_KEYWORD, - 0, // WHERE_KEYWORD, - 0, // ELSE_KEYWORD, - 0, // CATCH_KEYWORD, - 0, // AS_KEYWORD, - 0, // AS_QUEST, - 0, // AS_BANG, - 0, // ASYNC_KEYWORD -}; - -#define RESERVED_OP_COUNT 31 - -const char* RESERVED_OPS[RESERVED_OP_COUNT] = { - "/", - "=", - "-", - "+", - "!", - "*", - "%", - "<", - ">", - "&", - "|", - "^", - "?", - "~", - ".", - "..", - "->", - "/*", - "*/", - "+=", - "-=", - "*=", - "/=", - "%=", - ">>", - "<<", - "++", - "--", - "===", - "...", - "..<" -}; - -static bool is_cross_semi_token(enum TokenType op) { - switch(op) { - case ARROW_OPERATOR: - case DOT_OPERATOR: - case CONJUNCTION_OPERATOR: - case DISJUNCTION_OPERATOR: - case NIL_COALESCING_OPERATOR: - case EQUAL_SIGN: - case EQ_EQ: - case PLUS_THEN_WS: - case MINUS_THEN_WS: - case THROWS_KEYWORD: - case RETHROWS_KEYWORD: - case DEFAULT_KEYWORD: - case WHERE_KEYWORD: - case ELSE_KEYWORD: - case CATCH_KEYWORD: - case AS_KEYWORD: - case AS_QUEST: - case AS_BANG: - case ASYNC_KEYWORD: - case CUSTOM_OPERATOR: - return true; - case BANG: - default: - return false; - } -} - -#define NON_CONSUMING_CROSS_SEMI_CHAR_COUNT 3 -const uint32_t NON_CONSUMING_CROSS_SEMI_CHARS[NON_CONSUMING_CROSS_SEMI_CHAR_COUNT] = { '?', ':', '{' }; - -/** - * All possible results of having performed some sort of parsing. - * - * A parser can return a result along two dimensions: - * 1. Should the scanner continue trying to find another result? - * 2. Was some result produced by this parsing attempt? - * - * These are flattened into a single enum together. When the function returns one of the `TOKEN_FOUND` cases, it - * will always populate its `symbol_result` field. When it returns one of the `STOP_PARSING` cases, callers should - * immediately return (with the value, if there is one). - */ -enum ParseDirective { - CONTINUE_PARSING_NOTHING_FOUND, - CONTINUE_PARSING_TOKEN_FOUND, - CONTINUE_PARSING_SLASH_CONSUMED, - STOP_PARSING_NOTHING_FOUND, - STOP_PARSING_TOKEN_FOUND, - STOP_PARSING_END_OF_FILE -}; - -struct ScannerState { - uint32_t ongoing_raw_str_hash_count; -}; - -void *tree_sitter_swift_external_scanner_create() { - return calloc(1, sizeof(struct ScannerState)); -} - -void tree_sitter_swift_external_scanner_destroy(void *payload) { - free(payload); -} - -void tree_sitter_swift_external_scanner_reset(void *payload) { - struct ScannerState *state = (struct ScannerState *)payload; - state->ongoing_raw_str_hash_count = 0; -} - -unsigned tree_sitter_swift_external_scanner_serialize(void *payload, char *buffer) { - struct ScannerState *state = (struct ScannerState *)payload; - uint32_t hash_count = state->ongoing_raw_str_hash_count; - buffer[0] = (hash_count >> 24) & 0xff; - buffer[1] = (hash_count >> 16) & 0xff; - buffer[2] = (hash_count >> 8) & 0xff; - buffer[3] = (hash_count) & 0xff; - return 4; -} - -void tree_sitter_swift_external_scanner_deserialize( - void *payload, - const char *buffer, - unsigned length -) { - if (length < 4) { - return; - } - - uint32_t hash_count = ( - (((uint32_t) buffer[0]) << 24) | - (((uint32_t) buffer[1]) << 16) | - (((uint32_t) buffer[2]) << 8) | - (((uint32_t) buffer[3])) - ); - struct ScannerState *state = (struct ScannerState *)payload; - state->ongoing_raw_str_hash_count = hash_count; -} - -static void advance(TSLexer *lexer) { - lexer->advance(lexer, false); -} - -static bool should_treat_as_wspace(int32_t character) { - return iswspace(character) || (((int32_t) ';') == character); -} - -static int32_t encountered_op_count(bool *encountered_operator) { - int32_t encountered = 0; - for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) { - if (encountered_operator[op_idx]) { - encountered++; - } - } - - return encountered; -} - -static bool any_reserved_ops(uint8_t *encountered_reserved_ops) { - for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) { - if (encountered_reserved_ops[op_idx] == 2) { - return true; - } - } - - return false; -} - -static bool is_legal_custom_operator( - int32_t char_idx, - int32_t first_char, - int32_t cur_char -) { - bool is_first_char = !char_idx; - switch (cur_char) { - case '=': - case '-': - case '+': - case '!': - case '%': - case '<': - case '>': - case '&': - case '|': - case '^': - case '?': - case '~': - return true; - case '.': - // Grammar allows `.` for any operator that starts with `.` - return is_first_char || first_char == '.'; - case '*': - case '/': - // Not listed in the grammar, but `/*` and `//` can't be the start of an operator since they start comments - return char_idx != 1 || first_char != '/'; - default: - if ( - (cur_char >= 0x00A1 && cur_char <= 0x00A7) || - (cur_char == 0x00A9) || - (cur_char == 0x00AB) || - (cur_char == 0x00AC) || - (cur_char == 0x00AE) || - (cur_char >= 0x00B0 && cur_char <= 0x00B1) || - (cur_char == 0x00B6) || - (cur_char == 0x00BB) || - (cur_char == 0x00BF) || - (cur_char == 0x00D7) || - (cur_char == 0x00F7) || - (cur_char >= 0x2016 && cur_char <= 0x2017) || - (cur_char >= 0x2020 && cur_char <= 0x2027) || - (cur_char >= 0x2030 && cur_char <= 0x203E) || - (cur_char >= 0x2041 && cur_char <= 0x2053) || - (cur_char >= 0x2055 && cur_char <= 0x205E) || - (cur_char >= 0x2190 && cur_char <= 0x23FF) || - (cur_char >= 0x2500 && cur_char <= 0x2775) || - (cur_char >= 0x2794 && cur_char <= 0x2BFF) || - (cur_char >= 0x2E00 && cur_char <= 0x2E7F) || - (cur_char >= 0x3001 && cur_char <= 0x3003) || - (cur_char >= 0x3008 && cur_char <= 0x3020) || - (cur_char == 0x3030) - ) { - return true; - } else if ( - (cur_char >= 0x0300 && cur_char <= 0x036f) || - (cur_char >= 0x1DC0 && cur_char <= 0x1DFF) || - (cur_char >= 0x20D0 && cur_char <= 0x20FF) || - (cur_char >= 0xFE00 && cur_char <= 0xFE0F) || - (cur_char >= 0xFE20 && cur_char <= 0xFE2F) || - (cur_char >= 0xE0100 && cur_char <= 0xE01EF) - ) { - return !is_first_char; - } else { - return false; - } - } -} - -static bool eat_operators( - TSLexer *lexer, - const bool *valid_symbols, - bool mark_end, - const int32_t prior_char, - enum TokenType *symbol_result -) { - bool possible_operators[OPERATOR_COUNT]; - uint8_t reserved_operators[RESERVED_OP_COUNT]; - for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) { - possible_operators[op_idx] = valid_symbols[OP_SYMBOLS[op_idx]] && (!prior_char || OPERATORS[op_idx][0] == prior_char); - } - for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) { - reserved_operators[op_idx] = !prior_char || RESERVED_OPS[op_idx][0] == prior_char; - } - - bool possible_custom_operator = valid_symbols[CUSTOM_OPERATOR]; - int32_t first_char = prior_char ? prior_char : lexer->lookahead; - int32_t last_examined_char = first_char; - - int32_t str_idx = prior_char ? 1 : 0; - int32_t full_match = -1; - while(true) { - for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) { - if (!possible_operators[op_idx]) { - continue; - } - - if (OPERATORS[op_idx][str_idx] == '\0') { - // Make sure that the operator is allowed to have the next character as its lookahead. - enum IllegalTerminatorGroup illegal_terminators = OP_ILLEGAL_TERMINATORS[op_idx]; - switch (lexer->lookahead) { - // See "Operators": - // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418 - case '/': - case '=': - case '-': - case '+': - case '!': - case '*': - case '%': - case '<': - case '>': - case '&': - case '|': - case '^': - case '?': - case '~': - if (illegal_terminators == OPERATOR_SYMBOLS) { - break; - } // Otherwise, intentionally fall through to the OPERATOR_OR_DOT case - // fall through - case '.': - if (illegal_terminators == OPERATOR_OR_DOT) { - break; - } // Otherwise, fall through to DEFAULT which checks its groups directly - // fall through - default: - if (iswalnum(lexer->lookahead) && illegal_terminators == ALPHANUMERIC) { - break; - } - - if (!iswspace(lexer->lookahead) && illegal_terminators == NON_WHITESPACE) { - break; - } - - full_match = op_idx; - if (mark_end) { - lexer->mark_end(lexer); - } - } - - possible_operators[op_idx] = false; - continue; - } - - if (OPERATORS[op_idx][str_idx] != lexer->lookahead) { - possible_operators[op_idx] = false; - continue; - } - } - - for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) { - if (!reserved_operators[op_idx]) { - continue; - } - - if (RESERVED_OPS[op_idx][str_idx] == '\0') { - reserved_operators[op_idx] = 0; - continue; - } - - if (RESERVED_OPS[op_idx][str_idx] != lexer->lookahead) { - reserved_operators[op_idx] = 0; - continue; - } - - if (RESERVED_OPS[op_idx][str_idx + 1] == '\0') { - reserved_operators[op_idx] = 2; - continue; - } - } - - possible_custom_operator = possible_custom_operator && is_legal_custom_operator( - str_idx, - first_char, - lexer->lookahead - ); - - uint32_t encountered_ops = encountered_op_count(possible_operators); - if (encountered_ops == 0) { - if (!possible_custom_operator) { - break; - } else if (mark_end && full_match == -1) { - lexer->mark_end(lexer); - } - } - - last_examined_char = lexer->lookahead; - lexer->advance(lexer, false); - str_idx += 1; - - if (encountered_ops == 0 && !is_legal_custom_operator( - str_idx, - first_char, - lexer->lookahead - )) { - break; - } - } - - if (full_match != -1) { - // We have a match -- first see if that match has a symbol that suppresses it. For example, in `try!`, we do not - // want to emit the `!` as a symbol in our scanner, because we want the parser to have the chance to parse it as - // an immediate token. - uint64_t suppressing_symbols = OP_SYMBOL_SUPPRESSOR[full_match]; - if (suppressing_symbols) { - for (uint64_t suppressor = 0; suppressor < TOKEN_COUNT; suppressor++) { - if (!(suppressing_symbols & 1ULL << suppressor)) { - continue; - } - - // The suppressing symbol is valid in this position, so skip it. - if (valid_symbols[suppressor]) { - return false; - } - } - } - *symbol_result = OP_SYMBOLS[full_match]; - return true; - } - - if (possible_custom_operator && !any_reserved_ops(reserved_operators)) { - if ((last_examined_char != '<' || iswspace(lexer->lookahead)) && mark_end) { - lexer->mark_end(lexer); - } - *symbol_result = CUSTOM_OPERATOR; - return true; - } - - return false; -} - -static enum ParseDirective eat_comment( - TSLexer *lexer, - const bool *valid_symbols, - bool mark_end, - enum TokenType *symbol_result -) { - if (lexer->lookahead != '/') { - return CONTINUE_PARSING_NOTHING_FOUND; - } - - advance(lexer); - - if (lexer->lookahead != '*') { - return CONTINUE_PARSING_SLASH_CONSUMED; - } - - advance(lexer); - - bool after_star = false; - unsigned nesting_depth = 1; - for (;;) { - switch (lexer->lookahead) { - case '\0': - return STOP_PARSING_END_OF_FILE; - case '*': - advance(lexer); - after_star = true; - break; - case '/': - if (after_star) { - advance(lexer); - after_star = false; - nesting_depth--; - if (nesting_depth == 0) { - if (mark_end) { - lexer->mark_end(lexer); - } - *symbol_result = BLOCK_COMMENT; - return STOP_PARSING_TOKEN_FOUND; - } - } else { - advance(lexer); - after_star = false; - if (lexer->lookahead == '*') { - nesting_depth++; - advance(lexer); - } - } - break; - default: - advance(lexer); - after_star = false; - break; - } - } -} - -static enum ParseDirective eat_whitespace( - TSLexer *lexer, - const bool *valid_symbols, - enum TokenType *symbol_result -) { - enum ParseDirective ws_directive = CONTINUE_PARSING_NOTHING_FOUND; - bool semi_is_valid = valid_symbols[IMPLICIT_SEMI] && valid_symbols[EXPLICIT_SEMI]; - uint32_t lookahead; - while (should_treat_as_wspace(lookahead = lexer->lookahead)) { - if (lookahead == ';') { - if (semi_is_valid) { - ws_directive = STOP_PARSING_TOKEN_FOUND; - lexer->advance(lexer, false); - } - - break; - } - - lexer->advance(lexer, true); - - lexer->mark_end(lexer); - - if (ws_directive == CONTINUE_PARSING_NOTHING_FOUND && (lookahead == '\n' || lookahead == '\r')) { - ws_directive = CONTINUE_PARSING_TOKEN_FOUND; - } - } - - enum ParseDirective any_comment = CONTINUE_PARSING_NOTHING_FOUND; - if (ws_directive == CONTINUE_PARSING_TOKEN_FOUND && lookahead == '/') { - bool has_seen_single_comment = false; - while (lexer->lookahead == '/') { - // It's possible that this is a comment - start an exploratory mission to find out, and if it is, look for what - // comes after it. We care about what comes after it for the purpose of suppressing the newline. - - enum TokenType multiline_comment_result; - any_comment = eat_comment(lexer, valid_symbols, /* mark_end */ false, &multiline_comment_result); - if (any_comment == STOP_PARSING_TOKEN_FOUND) { - // This is a multiline comment. This scanner should be parsing those, so we might want to bail out and - // emit it instead. However, we only want to do that if we haven't advanced through a _single_ line - // comment on the way - otherwise that will get lumped into this. - if (!has_seen_single_comment) { - lexer->mark_end(lexer); - *symbol_result = multiline_comment_result; - return STOP_PARSING_TOKEN_FOUND; - } - } else if (any_comment == STOP_PARSING_END_OF_FILE) { - return STOP_PARSING_END_OF_FILE; - } else if (any_comment == CONTINUE_PARSING_SLASH_CONSUMED) { - // We accidentally ate a slash -- we should actually bail out, say we saw nothing, and let the next pass - // take it from after the newline. - return CONTINUE_PARSING_SLASH_CONSUMED; - } else if (lexer->lookahead == '/') { - // There wasn't a multiline comment, which we know means that the comment parser ate its `/` and then - // bailed out. If it had seen anything comment-like after that first `/` it would have continued going - // and eventually had a well-formed comment or an EOF. Thus, if we're currently looking at a `/`, it's - // the second one of those and it means we have a single-line comment. - has_seen_single_comment = true; - while (lexer->lookahead != '\n' && lexer->lookahead != '\0') { - lexer->advance(lexer, true); - } - } else if (iswspace(lexer->lookahead)) { - // We didn't see any type of comment - in fact, we saw an operator that we don't normally treat as an - // operator. Still, this is a reason to stop parsing. - return STOP_PARSING_NOTHING_FOUND; - } - - // If we skipped through some comment, we're at whitespace now, so advance. - while(iswspace(lexer->lookahead)) { - any_comment = CONTINUE_PARSING_NOTHING_FOUND; // We're advancing, so clear out the comment - lexer->advance(lexer, true); - } - } - - enum TokenType operator_result; - bool saw_operator = eat_operators( - lexer, - valid_symbols, - /* mark_end */ false, - '\0', - &operator_result - ); - if (saw_operator) { - // The operator we saw should suppress the newline, so bail out. - return STOP_PARSING_NOTHING_FOUND; - } else { - // Promote the implicit newline to an explicit one so we don't check for operators again. - *symbol_result = IMPLICIT_SEMI; - ws_directive = STOP_PARSING_TOKEN_FOUND; - } - } - - // Let's consume operators that can live after a "semicolon" style newline. Before we do that, though, we want to - // check for a set of characters that we do not consume, but that still suppress the semi. - if (ws_directive == CONTINUE_PARSING_TOKEN_FOUND) { - for (int i = 0; i < NON_CONSUMING_CROSS_SEMI_CHAR_COUNT; i++) { - if (NON_CONSUMING_CROSS_SEMI_CHARS[i] == lookahead) { - return CONTINUE_PARSING_NOTHING_FOUND; - } - } - } - - if (semi_is_valid && ws_directive != CONTINUE_PARSING_NOTHING_FOUND) { - *symbol_result = lookahead == ';' ? EXPLICIT_SEMI : IMPLICIT_SEMI; - return ws_directive; - } - - return CONTINUE_PARSING_NOTHING_FOUND; -} - -#define DIRECTIVE_COUNT 4 -const char* DIRECTIVES[OPERATOR_COUNT] = { - "if", - "elseif", - "else", - "endif" -}; - -const enum TokenType DIRECTIVE_SYMBOLS[DIRECTIVE_COUNT] = { - DIRECTIVE_IF, - DIRECTIVE_ELSEIF, - DIRECTIVE_ELSE, - DIRECTIVE_ENDIF -}; - -static enum TokenType find_possible_compiler_directive(TSLexer *lexer) { - bool possible_directives[DIRECTIVE_COUNT]; - for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx++) { - possible_directives[dir_idx] = true; - } - - int32_t str_idx = 0; - int32_t full_match = -1; - while(true) { - for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx++) { - if (!possible_directives[dir_idx]) { - continue; - } - - uint8_t expected_char = DIRECTIVES[dir_idx][str_idx]; - if (expected_char == '\0') { - full_match = dir_idx; - lexer->mark_end(lexer); - } - - if (expected_char != lexer->lookahead) { - possible_directives[dir_idx] = false; - continue; - } - } - - uint8_t match_count = 0; - for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx += 1) { - if (possible_directives[dir_idx]) { - match_count += 1; - } - } - - if (match_count == 0) { - break; - } - - lexer->advance(lexer, false); - str_idx += 1; - } - - if (full_match == -1) { - // No compiler directive found, so just match the starting symbol - return HASH_SYMBOL; - } - - return DIRECTIVE_SYMBOLS[full_match]; -} - -static bool eat_raw_str_part( - struct ScannerState *state, - TSLexer *lexer, - const bool *valid_symbols, - enum TokenType *symbol_result -) { - uint32_t hash_count = state->ongoing_raw_str_hash_count; - if (!valid_symbols[RAW_STR_PART]) { - return false; - } else if (hash_count == 0) { - // If this is a raw_str_part, it's the first one - look for hashes - while (lexer->lookahead == '#') { - hash_count += 1; - advance(lexer); - } - - if (hash_count == 0) { - return false; - } - - if (lexer->lookahead == '"') { - advance(lexer); - } else if (hash_count == 1) { - lexer->mark_end(lexer); - *symbol_result = find_possible_compiler_directive(lexer); - return true; - } else { - return false; - } - - } else if (valid_symbols[RAW_STR_CONTINUING_INDICATOR]) { - // This is the end of an interpolation - now it's another raw_str_part. This is a synthetic - // marker to tell us that the grammar just consumed a `(` symbol to close a raw - // interpolation (since we don't want to fire on every `(` in existence). We don't have - // anything to do except continue. - } else { - return false; - } - - // We're in a state where anything other than `hash_count` hash symbols in a row should be eaten - // and is part of a string. - // The last character _before_ the hashes will tell us what happens next. - // Matters are also complicated by the fact that we don't want to consume every character we - // visit; if we see a `\#(`, for instance, with the appropriate number of hash symbols, we want - // to end our parsing _before_ that sequence. This allows highlighting tools to treat that as a - // separate token. - while (lexer->lookahead != '\0') { - uint8_t last_char = '\0'; - lexer->mark_end(lexer); // We always want to parse thru the start of the string so far - // Advance through anything that isn't a hash symbol, because we want to count those. - while (lexer->lookahead != '#' && lexer->lookahead != '\0') { - last_char = lexer->lookahead; - advance(lexer); - if (last_char != '\\' || lexer->lookahead == '\\') { - // Mark a new end, but only if we didn't just advance past a `\` symbol, since we - // don't want to consume that. Exception: if this is a `\` that happens _right - // after_ another `\`, we for some reason _do_ want to consume that, because - // apparently that is parsed as a literal `\` followed by something escaped. - lexer->mark_end(lexer); - } - } - - // We hit at least one hash - count them and see if they match. - uint32_t current_hash_count = 0; - while (lexer->lookahead == '#' && current_hash_count < hash_count) { - current_hash_count += 1; - advance(lexer); - } - - // If we saw exactly the right number of hashes, one of three things is true: - // 1. We're trying to interpolate into this string. - // 2. The string just ended. - // 3. This was just some hash characters doing nothing important. - if (current_hash_count == hash_count) { - if (last_char == '\\' && lexer->lookahead == '(') { - // Interpolation case! Don't consume those chars; they get saved for grammar.js. - *symbol_result = RAW_STR_PART; - state->ongoing_raw_str_hash_count = hash_count; - return true; - } else if (last_char == '"') { - // The string is finished! Mark the end here, on the very last hash symbol. - lexer->mark_end(lexer); - *symbol_result = RAW_STR_END_PART; - state->ongoing_raw_str_hash_count = 0; - return true; - } - // Nothing special happened - let the string continue. - } - } - - return false; -} - -bool tree_sitter_swift_external_scanner_scan( - void *payload, - TSLexer *lexer, - const bool *valid_symbols -) { - // Figure out our scanner state - struct ScannerState *state = (struct ScannerState *)payload; - - // Consume any whitespace at the start. - enum TokenType ws_result; - enum ParseDirective ws_directive = eat_whitespace(lexer, valid_symbols, &ws_result); - if (ws_directive == STOP_PARSING_TOKEN_FOUND) { - lexer->result_symbol = ws_result; - return true; - } - - if (ws_directive == STOP_PARSING_NOTHING_FOUND || ws_directive == STOP_PARSING_END_OF_FILE) { - return false; - } - - bool has_ws_result = (ws_directive == CONTINUE_PARSING_TOKEN_FOUND); - - // Now consume comments (before custom operators so that those aren't treated as comments) - enum TokenType comment_result; - enum ParseDirective comment = ws_directive == CONTINUE_PARSING_SLASH_CONSUMED ? ws_directive : eat_comment(lexer, valid_symbols, /* mark_end */ true, &comment_result); - if (comment == STOP_PARSING_TOKEN_FOUND) { - lexer->mark_end(lexer); - lexer->result_symbol = comment_result; - return true; - } - - if (comment == STOP_PARSING_END_OF_FILE) { - return false; - } - // Now consume any operators that might cause our whitespace to be suppressed. - enum TokenType operator_result; - bool saw_operator = eat_operators( - lexer, - valid_symbols, - /* mark_end */ !has_ws_result, - comment == CONTINUE_PARSING_SLASH_CONSUMED ? '/' : '\0', - &operator_result - ); - - if (saw_operator && (!has_ws_result || is_cross_semi_token(operator_result))) { - lexer->result_symbol = operator_result; - if (has_ws_result) lexer->mark_end(lexer); - return true; - } - - if (has_ws_result) { - // Don't `mark_end`, since we may have advanced through some operators. - lexer->result_symbol = ws_result; - return true; - } - - // NOTE: this will consume any `#` characters it sees, even if it does not find a result. Keep - // it at the end so that it doesn't interfere with special literals or selectors! - enum TokenType raw_str_result; - bool saw_raw_str_part = eat_raw_str_part(state, lexer, valid_symbols, &raw_str_result); - if (saw_raw_str_part) { - lexer->result_symbol = raw_str_result; - return true; - } - - return false; -} - diff --git a/unified/extractor/tree-sitter-swift/tree-sitter.json b/unified/extractor/tree-sitter-swift/tree-sitter.json deleted file mode 100644 index 3cd49a28a38f..000000000000 --- a/unified/extractor/tree-sitter-swift/tree-sitter.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "grammars": [ - { - "name": "swift", - "camelcase": "Swift", - "scope": "source.swift", - "path": ".", - "file-types": [ - "swift" - ], - "highlights": "queries/highlights.scm", - "injections": "queries/injections.scm", - "locals": "queries/locals.scm", - "injection-regex": "swift" - } - ], - "metadata": { - "version": "0.7.2", - "license": "MIT", - "description": "A tree-sitter grammar for the Swift programming language.", - "authors": [ - { - "name": "Alex Pinkus", - "email": "alex.pinkus@gmail.com" - } - ], - "links": { - "repository": "git+https://github.com/alex-pinkus/tree-sitter-swift.git" - } - }, - "bindings": { - "c": true, - "go": true, - "node": true, - "python": true, - "rust": true, - "swift": true - } -} diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/internal/Ast.qll similarity index 60% rename from unified/ql/lib/codeql/unified/Ast.qll rename to unified/ql/lib/codeql/unified/internal/Ast.qll index 8adb4c2e44a0..20ff74e6eaf7 100644 --- a/unified/ql/lib/codeql/unified/Ast.qll +++ b/unified/ql/lib/codeql/unified/internal/Ast.qll @@ -25,8 +25,10 @@ private predicate discardLocation(@location_default loc) { overlay[local] module Unified { + private import FacadeAst::Unified as F + /** The base class for all AST nodes */ - private class AstNodeImpl extends @unified_ast_node { + class AstNode extends @unified_ast_node { /** Gets a string representation of this element. */ string toString() { result = this.getAPrimaryQlClass() } @@ -34,13 +36,13 @@ module Unified { final L::Location getLocation() { unified_ast_node_location(this, result) } /** Gets the parent of this element. */ - final AstNode getParent() { unified_ast_node_parent(this, result, _) } + final F::AstNode getParent() { unified_ast_node_parent(this, result, _) } /** Gets the index of this node among the children of its parent. */ final int getParentIndex() { unified_ast_node_parent(this, _, result) } /** Gets a field or child node of this node. */ - AstNode getAFieldOrChild() { none() } + F::AstNode getAFieldOrChild() { none() } /** Gets the name of the primary QL class for this element. */ string getAPrimaryQlClass() { result = "???" } @@ -49,10 +51,8 @@ module Unified { string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } } - final class AstNode = AstNodeImpl; - /** A token. */ - private class TokenImpl extends @unified_token, AstNodeImpl { + class Token extends @unified_token, F::AstNode { /** Gets the value of this token. */ final string getValue() { unified_tokeninfo(this, _, result) } @@ -63,10 +63,8 @@ module Unified { override string getAPrimaryQlClass() { result = "Token" } } - final class Token = TokenImpl; - /** A trivia token, such as a comment, preserved from the original parse tree. */ - final class TriviaToken extends @unified_trivia_token, AstNodeImpl { + class TriviaToken extends @unified_trivia_token, F::AstNode { /** Gets the source text of this trivia token. */ final string getValue() { unified_trivia_tokeninfo(this, _, result) } @@ -98,30 +96,38 @@ module Unified { } /** A class representing `accessor_declaration` nodes. */ - final class AccessorDeclaration extends @unified_accessor_declaration, AstNodeImpl { + class AccessorDeclaration extends @unified_accessor_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorDeclaration" } /** Gets the node corresponding to the field `accessor_kind`. */ - final AccessorKind getAccessorKind() { unified_accessor_declaration_def(this, result, _) } + final F::AccessorKind getAccessorKind() { unified_accessor_declaration_def(this, result, _) } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_accessor_declaration_body(this, result) } + final F::Block getBody() { unified_accessor_declaration_body(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_accessor_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_accessor_declaration_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_accessor_declaration_def(this, _, result) } + final F::Identifier getName() { unified_accessor_declaration_def(this, _, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getParameter(int i) { + unified_accessor_declaration_parameter(this, i, result) + } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_accessor_declaration_parameter(this, i, result) } + final F::Parameter getAParameter() { result = this.getParameter(_) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_accessor_declaration_type(this, result) } + final F::TypeExpr getType() { unified_accessor_declaration_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_accessor_declaration_def(this, result, _) or unified_accessor_declaration_body(this, result) or unified_accessor_declaration_modifier(this, _, result) or @@ -132,27 +138,30 @@ module Unified { } /** A class representing `accessor_kind` tokens. */ - final class AccessorKind extends @unified_token_accessor_kind, TokenImpl { + class AccessorKind extends @unified_token_accessor_kind, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AccessorKind" } } /** A class representing `argument` nodes. */ - final class Argument extends @unified_argument, AstNodeImpl { + class Argument extends @unified_argument, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Argument" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_argument_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_argument_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_argument_name(this, result) } + final F::Identifier getName() { unified_argument_name(this, result) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_argument_def(this, result) } + final F::Expr getValue() { unified_argument_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_argument_modifier(this, _, result) or unified_argument_name(this, result) or unified_argument_def(this, result) @@ -160,52 +169,58 @@ module Unified { } /** A class representing `array_literal` nodes. */ - final class ArrayLiteral extends @unified_array_literal, AstNodeImpl { + class ArrayLiteral extends @unified_array_literal, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ArrayLiteral" } /** Gets the node corresponding to the field `element`. */ - final Expr getElement(int i) { unified_array_literal_element(this, i, result) } + final F::Expr getElement(int i) { unified_array_literal_element(this, i, result) } + + /** Gets the node corresponding to the field `element`. */ + final F::Expr getAnElement() { result = this.getElement(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_array_literal_element(this, _, result) } } /** A class representing `assign_expr` nodes. */ - final class AssignExpr extends @unified_assign_expr, AstNodeImpl { + class AssignExpr extends @unified_assign_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssignExpr" } /** Gets the node corresponding to the field `target`. */ - final ExprOrPattern getTarget() { unified_assign_expr_def(this, result, _) } + final F::ExprOrPattern getTarget() { unified_assign_expr_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_assign_expr_def(this, _, result) } + final F::Expr getValue() { unified_assign_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_assign_expr_def(this, result, _) or unified_assign_expr_def(this, _, result) } } /** A class representing `associated_type_declaration` nodes. */ - final class AssociatedTypeDeclaration extends @unified_associated_type_declaration, AstNodeImpl { + class AssociatedTypeDeclaration extends @unified_associated_type_declaration, F::Member { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "AssociatedTypeDeclaration" } /** Gets the node corresponding to the field `bound`. */ - final TypeExpr getBound() { unified_associated_type_declaration_bound(this, result) } + final F::TypeExpr getBound() { unified_associated_type_declaration_bound(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { + final F::Modifier getModifier(int i) { unified_associated_type_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_associated_type_declaration_def(this, result) } + final F::Identifier getName() { unified_associated_type_declaration_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_associated_type_declaration_bound(this, result) or unified_associated_type_declaration_modifier(this, _, result) or unified_associated_type_declaration_def(this, result) @@ -213,38 +228,41 @@ module Unified { } /** A class representing `base_type` nodes. */ - final class BaseType extends @unified_base_type, AstNodeImpl { + class BaseType extends @unified_base_type, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BaseType" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_base_type_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_base_type_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_base_type_def(this, result) } + final F::TypeExpr getType() { unified_base_type_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_base_type_modifier(this, _, result) or unified_base_type_def(this, result) } } /** A class representing `binary_expr` nodes. */ - final class BinaryExpr extends @unified_binary_expr, AstNodeImpl { + class BinaryExpr extends @unified_binary_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BinaryExpr" } /** Gets the node corresponding to the field `left`. */ - final Expr getLeft() { unified_binary_expr_def(this, result, _, _) } + final F::Expr getLeft() { unified_binary_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_binary_expr_def(this, _, result, _) } + final F::InfixOperator getOperator() { unified_binary_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `right`. */ - final Expr getRight() { unified_binary_expr_def(this, _, _, result) } + final F::Expr getRight() { unified_binary_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_binary_expr_def(this, result, _, _) or unified_binary_expr_def(this, _, result, _) or unified_binary_expr_def(this, _, _, result) @@ -252,89 +270,103 @@ module Unified { } /** A class representing `block` nodes. */ - final class Block extends @unified_block, AstNodeImpl { + class Block extends @unified_block, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Block" } /** Gets the node corresponding to the field `stmt`. */ - final Stmt getStmt(int i) { unified_block_stmt(this, i, result) } + final F::Stmt getStmt(int i) { unified_block_stmt(this, i, result) } + + /** Gets the node corresponding to the field `stmt`. */ + final F::Stmt getAStmt() { result = this.getStmt(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_block_stmt(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_block_stmt(this, _, result) } } /** A class representing `boolean_literal` tokens. */ - final class BooleanLiteral extends @unified_token_boolean_literal, TokenImpl { + class BooleanLiteral extends @unified_token_boolean_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BooleanLiteral" } } /** A class representing `bound_type_constraint` nodes. */ - final class BoundTypeConstraint extends @unified_bound_type_constraint, AstNodeImpl { + class BoundTypeConstraint extends @unified_bound_type_constraint, F::TypeConstraint { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BoundTypeConstraint" } /** Gets the node corresponding to the field `bound`. */ - final TypeExpr getBound() { unified_bound_type_constraint_def(this, result, _) } + final F::TypeExpr getBound() { unified_bound_type_constraint_def(this, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_bound_type_constraint_def(this, _, result) } + final F::TypeExpr getType() { unified_bound_type_constraint_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_bound_type_constraint_def(this, result, _) or unified_bound_type_constraint_def(this, _, result) } } /** A class representing `break_expr` nodes. */ - final class BreakExpr extends @unified_break_expr, AstNodeImpl { + class BreakExpr extends @unified_break_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BreakExpr" } /** Gets the node corresponding to the field `label`. */ - final Identifier getLabel() { unified_break_expr_label(this, result) } + final F::Identifier getLabel() { unified_break_expr_label(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_break_expr_label(this, result) } + final override F::AstNode getAFieldOrChild() { unified_break_expr_label(this, result) } } /** A class representing `builtin_expr` tokens. */ - final class BuiltinExpr extends @unified_token_builtin_expr, TokenImpl { + class BuiltinExpr extends @unified_token_builtin_expr, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BuiltinExpr" } } /** A class representing `bulk_importing_pattern` nodes. */ - final class BulkImportingPattern extends @unified_bulk_importing_pattern, AstNodeImpl { + class BulkImportingPattern extends @unified_bulk_importing_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "BulkImportingPattern" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_bulk_importing_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_bulk_importing_pattern_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_bulk_importing_pattern_modifier(this, _, result) } } /** A class representing `call_expr` nodes. */ - final class CallExpr extends @unified_call_expr, AstNodeImpl { + class CallExpr extends @unified_call_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CallExpr" } /** Gets the node corresponding to the field `argument`. */ - final Argument getArgument(int i) { unified_call_expr_argument(this, i, result) } + final F::Argument getArgument(int i) { unified_call_expr_argument(this, i, result) } + + /** Gets the node corresponding to the field `argument`. */ + final F::Argument getAnArgument() { result = this.getArgument(_) } /** Gets the node corresponding to the field `callee`. */ - final ExprOrType getCallee() { unified_call_expr_def(this, result) } + final F::ExprOrType getCallee() { unified_call_expr_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_call_expr_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_call_expr_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_call_expr_argument(this, _, result) or unified_call_expr_def(this, result) or unified_call_expr_modifier(this, _, result) @@ -342,60 +374,78 @@ module Unified { } /** A class representing `catch_clause` nodes. */ - final class CatchClause extends @unified_catch_clause, AstNodeImpl { + class CatchClause extends @unified_catch_clause, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CatchClause" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_catch_clause_def(this, result) } + final F::Block getBody() { unified_catch_clause_def(this, result) } - /** Gets the node corresponding to the field `guard`. */ - final Expr getGuard() { unified_catch_clause_guard(this, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_catch_clause_pattern(this, result) } + final F::Pattern getPattern() { unified_catch_clause_pattern(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_catch_clause_def(this, result) or - unified_catch_clause_guard(this, result) or unified_catch_clause_modifier(this, _, result) or unified_catch_clause_pattern(this, result) } } /** A class representing `class_like_declaration` nodes. */ - final class ClassLikeDeclaration extends @unified_class_like_declaration, AstNodeImpl { + class ClassLikeDeclaration extends @unified_class_like_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ClassLikeDeclaration" } /** Gets the node corresponding to the field `base_type`. */ - final BaseType getBaseType(int i) { unified_class_like_declaration_base_type(this, i, result) } + final F::BaseType getBaseType(int i) { + unified_class_like_declaration_base_type(this, i, result) + } + + /** Gets the node corresponding to the field `base_type`. */ + final F::BaseType getABaseType() { result = this.getBaseType(_) } + + /** Gets the node corresponding to the field `member`. */ + final F::Member getMember(int i) { unified_class_like_declaration_member(this, i, result) } /** Gets the node corresponding to the field `member`. */ - final Member getMember(int i) { unified_class_like_declaration_member(this, i, result) } + final F::Member getAMember() { result = this.getMember(_) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_class_like_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_class_like_declaration_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_class_like_declaration_name(this, result) } + final F::Identifier getName() { unified_class_like_declaration_name(this, result) } /** Gets the node corresponding to the field `type_constraint`. */ - final TypeConstraint getTypeConstraint(int i) { + final F::TypeConstraint getTypeConstraint(int i) { unified_class_like_declaration_type_constraint(this, i, result) } + /** Gets the node corresponding to the field `type_constraint`. */ + final F::TypeConstraint getATypeConstraint() { result = this.getTypeConstraint(_) } + /** Gets the node corresponding to the field `type_parameter`. */ - final TypeParameter getTypeParameter(int i) { + final F::TypeParameter getTypeParameter(int i) { unified_class_like_declaration_type_parameter(this, i, result) } + /** Gets the node corresponding to the field `type_parameter`. */ + final F::TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } + /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_class_like_declaration_base_type(this, _, result) or unified_class_like_declaration_member(this, _, result) or unified_class_like_declaration_modifier(this, _, result) or @@ -406,48 +456,81 @@ module Unified { } /** A class representing `compound_assign_expr` nodes. */ - final class CompoundAssignExpr extends @unified_compound_assign_expr, AstNodeImpl { + class CompoundAssignExpr extends @unified_compound_assign_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "CompoundAssignExpr" } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_compound_assign_expr_def(this, result, _, _) } + final F::InfixOperator getOperator() { unified_compound_assign_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `target`. */ - final Expr getTarget() { unified_compound_assign_expr_def(this, _, result, _) } + final F::Expr getTarget() { unified_compound_assign_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_compound_assign_expr_def(this, _, _, result) } + final F::Expr getValue() { unified_compound_assign_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_compound_assign_expr_def(this, result, _, _) or unified_compound_assign_expr_def(this, _, result, _) or unified_compound_assign_expr_def(this, _, _, result) } } + /** A class representing `conditional_pattern` nodes. */ + class ConditionalPattern extends @unified_conditional_pattern, F::Pattern { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConditionalPattern" } + + /** Gets the node corresponding to the field `condition`. */ + final F::Expr getCondition() { unified_conditional_pattern_def(this, result, _) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_conditional_pattern_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + + /** Gets the node corresponding to the field `pattern`. */ + final F::Pattern getPattern() { unified_conditional_pattern_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override F::AstNode getAFieldOrChild() { + unified_conditional_pattern_def(this, result, _) or + unified_conditional_pattern_modifier(this, _, result) or + unified_conditional_pattern_def(this, _, result) + } + } + /** A class representing `constructor_declaration` nodes. */ - final class ConstructorDeclaration extends @unified_constructor_declaration, AstNodeImpl { + class ConstructorDeclaration extends @unified_constructor_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_constructor_declaration_def(this, result) } + final F::Block getBody() { unified_constructor_declaration_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { + unified_constructor_declaration_modifier(this, i, result) + } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_constructor_declaration_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_constructor_declaration_name(this, result) } + final F::Identifier getName() { unified_constructor_declaration_name(this, result) } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { + final F::Parameter getParameter(int i) { unified_constructor_declaration_parameter(this, i, result) } + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } + /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_constructor_declaration_def(this, result) or unified_constructor_declaration_modifier(this, _, result) or unified_constructor_declaration_name(this, result) or @@ -456,21 +539,29 @@ module Unified { } /** A class representing `constructor_pattern` nodes. */ - final class ConstructorPattern extends @unified_constructor_pattern, AstNodeImpl { + class ConstructorPattern extends @unified_constructor_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ConstructorPattern" } /** Gets the node corresponding to the field `constructor`. */ - final ExprOrType getConstructor() { unified_constructor_pattern_def(this, result) } + final F::ExprOrType getConstructor() { unified_constructor_pattern_def(this, result) } + + /** Gets the node corresponding to the field `element`. */ + final F::PatternElement getElement(int i) { + unified_constructor_pattern_element(this, i, result) + } /** Gets the node corresponding to the field `element`. */ - final PatternElement getElement(int i) { unified_constructor_pattern_element(this, i, result) } + final F::PatternElement getAnElement() { result = this.getElement(_) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_constructor_pattern_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_constructor_pattern_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_constructor_pattern_def(this, result) or unified_constructor_pattern_element(this, _, result) or unified_constructor_pattern_modifier(this, _, result) @@ -478,51 +569,59 @@ module Unified { } /** A class representing `continue_expr` nodes. */ - final class ContinueExpr extends @unified_continue_expr, AstNodeImpl { + class ContinueExpr extends @unified_continue_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ContinueExpr" } /** Gets the node corresponding to the field `label`. */ - final Identifier getLabel() { unified_continue_expr_label(this, result) } + final F::Identifier getLabel() { unified_continue_expr_label(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_continue_expr_label(this, result) } + final override F::AstNode getAFieldOrChild() { unified_continue_expr_label(this, result) } } /** A class representing `destructor_declaration` nodes. */ - final class DestructorDeclaration extends @unified_destructor_declaration, AstNodeImpl { + class DestructorDeclaration extends @unified_destructor_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DestructorDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_destructor_declaration_def(this, result) } + final F::Block getBody() { unified_destructor_declaration_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_destructor_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_destructor_declaration_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_destructor_declaration_def(this, result) or unified_destructor_declaration_modifier(this, _, result) } } /** A class representing `do_while_stmt` nodes. */ - final class DoWhileStmt extends @unified_do_while_stmt, AstNodeImpl { + class DoWhileStmt extends @unified_do_while_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "DoWhileStmt" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_do_while_stmt_body(this, result) } + final F::Block getBody() { unified_do_while_stmt_body(this, result) } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_do_while_stmt_def(this, result) } + final F::Expr getCondition() { unified_do_while_stmt_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_do_while_stmt_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_do_while_stmt_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_do_while_stmt_body(this, result) or unified_do_while_stmt_def(this, result) or unified_do_while_stmt_modifier(this, _, result) @@ -530,81 +629,86 @@ module Unified { } /** A class representing `empty_expr` tokens. */ - final class EmptyExpr extends @unified_token_empty_expr, TokenImpl { + class EmptyExpr extends @unified_token_empty_expr, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EmptyExpr" } } /** A class representing `equality_type_constraint` nodes. */ - final class EqualityTypeConstraint extends @unified_equality_type_constraint, AstNodeImpl { + class EqualityTypeConstraint extends @unified_equality_type_constraint, F::TypeConstraint { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "EqualityTypeConstraint" } /** Gets the node corresponding to the field `left`. */ - final TypeExpr getLeft() { unified_equality_type_constraint_def(this, result, _) } + final F::TypeExpr getLeft() { unified_equality_type_constraint_def(this, result, _) } /** Gets the node corresponding to the field `right`. */ - final TypeExpr getRight() { unified_equality_type_constraint_def(this, _, result) } + final F::TypeExpr getRight() { unified_equality_type_constraint_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_equality_type_constraint_def(this, result, _) or unified_equality_type_constraint_def(this, _, result) } } - final class Expr extends @unified_expr, AstNodeImpl { } + class Expr extends @unified_expr, F::ExprOrOperator, F::ExprOrPattern, F::ExprOrType, F::Stmt { } /** A class representing `expr_equality_pattern` nodes. */ - final class ExprEqualityPattern extends @unified_expr_equality_pattern, AstNodeImpl { + class ExprEqualityPattern extends @unified_expr_equality_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ExprEqualityPattern" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_expr_equality_pattern_def(this, result) } + final F::Expr getExpr() { unified_expr_equality_pattern_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } + final override F::AstNode getAFieldOrChild() { unified_expr_equality_pattern_def(this, result) } } - final class ExprOrPattern extends @unified_expr_or_pattern, AstNodeImpl { } + class ExprOrOperator extends @unified_expr_or_operator, F::AstNode { } - final class ExprOrType extends @unified_expr_or_type, AstNodeImpl { } + class ExprOrPattern extends @unified_expr_or_pattern, F::AstNode { } + + class ExprOrType extends @unified_expr_or_type, F::AstNode { } /** A class representing `fixity` tokens. */ - final class Fixity extends @unified_token_fixity, TokenImpl { + class Fixity extends @unified_token_fixity, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Fixity" } } /** A class representing `float_literal` tokens. */ - final class FloatLiteral extends @unified_token_float_literal, TokenImpl { + class FloatLiteral extends @unified_token_float_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FloatLiteral" } } /** A class representing `for_each_stmt` nodes. */ - final class ForEachStmt extends @unified_for_each_stmt, AstNodeImpl { + class ForEachStmt extends @unified_for_each_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ForEachStmt" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_for_each_stmt_body(this, result) } + final F::Block getBody() { unified_for_each_stmt_body(this, result) } /** Gets the node corresponding to the field `guard`. */ - final Expr getGuard() { unified_for_each_stmt_guard(this, result) } + final F::Expr getGuard() { unified_for_each_stmt_guard(this, result) } /** Gets the node corresponding to the field `iterable`. */ - final Expr getIterable() { unified_for_each_stmt_def(this, result, _) } + final F::Expr getIterable() { unified_for_each_stmt_def(this, result, _) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_for_each_stmt_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_for_each_stmt_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_for_each_stmt_def(this, _, result) } + final F::Pattern getPattern() { unified_for_each_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_for_each_stmt_body(this, result) or unified_for_each_stmt_guard(this, result) or unified_for_each_stmt_def(this, result, _) or @@ -614,37 +718,51 @@ module Unified { } /** A class representing `function_declaration` nodes. */ - final class FunctionDeclaration extends @unified_function_declaration, AstNodeImpl { + class FunctionDeclaration extends @unified_function_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_function_declaration_body(this, result) } + final F::Block getBody() { unified_function_declaration_body(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_function_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_function_declaration_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_function_declaration_def(this, result) } + final F::Identifier getName() { unified_function_declaration_def(this, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getParameter(int i) { + unified_function_declaration_parameter(this, i, result) + } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_function_declaration_parameter(this, i, result) } + final F::Parameter getAParameter() { result = this.getParameter(_) } /** Gets the node corresponding to the field `return_type`. */ - final TypeExpr getReturnType() { unified_function_declaration_return_type(this, result) } + final F::TypeExpr getReturnType() { unified_function_declaration_return_type(this, result) } /** Gets the node corresponding to the field `type_constraint`. */ - final TypeConstraint getTypeConstraint(int i) { + final F::TypeConstraint getTypeConstraint(int i) { unified_function_declaration_type_constraint(this, i, result) } + /** Gets the node corresponding to the field `type_constraint`. */ + final F::TypeConstraint getATypeConstraint() { result = this.getTypeConstraint(_) } + /** Gets the node corresponding to the field `type_parameter`. */ - final TypeParameter getTypeParameter(int i) { + final F::TypeParameter getTypeParameter(int i) { unified_function_declaration_type_parameter(this, i, result) } + /** Gets the node corresponding to the field `type_parameter`. */ + final F::TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } + /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_function_declaration_body(this, result) or unified_function_declaration_modifier(this, _, result) or unified_function_declaration_def(this, result) or @@ -656,29 +774,38 @@ module Unified { } /** A class representing `function_expr` nodes. */ - final class FunctionExpr extends @unified_function_expr, AstNodeImpl { + class FunctionExpr extends @unified_function_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionExpr" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_function_expr_def(this, result) } + final F::Block getBody() { unified_function_expr_def(this, result) } /** Gets the node corresponding to the field `capture_declaration`. */ - final VariableDeclaration getCaptureDeclaration(int i) { + final F::VariableDeclaration getCaptureDeclaration(int i) { unified_function_expr_capture_declaration(this, i, result) } + /** Gets the node corresponding to the field `capture_declaration`. */ + final F::VariableDeclaration getACaptureDeclaration() { result = this.getCaptureDeclaration(_) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_function_expr_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_function_expr_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_function_expr_parameter(this, i, result) } + final F::Parameter getParameter(int i) { unified_function_expr_parameter(this, i, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } /** Gets the node corresponding to the field `return_type`. */ - final TypeExpr getReturnType() { unified_function_expr_return_type(this, result) } + final F::TypeExpr getReturnType() { unified_function_expr_return_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_function_expr_def(this, result) or unified_function_expr_capture_declaration(this, _, result) or unified_function_expr_modifier(this, _, result) or @@ -688,82 +815,88 @@ module Unified { } /** A class representing `function_type_expr` nodes. */ - final class FunctionTypeExpr extends @unified_function_type_expr, AstNodeImpl { + class FunctionTypeExpr extends @unified_function_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "FunctionTypeExpr" } /** Gets the node corresponding to the field `parameter`. */ - final Parameter getParameter(int i) { unified_function_type_expr_parameter(this, i, result) } + final F::Parameter getParameter(int i) { unified_function_type_expr_parameter(this, i, result) } + + /** Gets the node corresponding to the field `parameter`. */ + final F::Parameter getAParameter() { result = this.getParameter(_) } /** Gets the node corresponding to the field `return_type`. */ - final TypeExpr getReturnType() { unified_function_type_expr_def(this, result) } + final F::TypeExpr getReturnType() { unified_function_type_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_function_type_expr_parameter(this, _, result) or unified_function_type_expr_def(this, result) } } /** A class representing `generic_type_expr` nodes. */ - final class GenericTypeExpr extends @unified_generic_type_expr, AstNodeImpl { + class GenericTypeExpr extends @unified_generic_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GenericTypeExpr" } /** Gets the node corresponding to the field `base`. */ - final TypeExpr getBase() { unified_generic_type_expr_def(this, result) } + final F::TypeExpr getBase() { unified_generic_type_expr_def(this, result) } /** Gets the node corresponding to the field `type_argument`. */ - final TypeExpr getTypeArgument(int i) { + final F::TypeExpr getTypeArgument(int i) { unified_generic_type_expr_type_argument(this, i, result) } + /** Gets the node corresponding to the field `type_argument`. */ + final F::TypeExpr getATypeArgument() { result = this.getTypeArgument(_) } + /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_generic_type_expr_def(this, result) or unified_generic_type_expr_type_argument(this, _, result) } } /** A class representing `guard_if_stmt` nodes. */ - final class GuardIfStmt extends @unified_guard_if_stmt, AstNodeImpl { + class GuardIfStmt extends @unified_guard_if_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "GuardIfStmt" } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_guard_if_stmt_def(this, result, _) } + final F::Expr getCondition() { unified_guard_if_stmt_def(this, result, _) } /** Gets the node corresponding to the field `else`. */ - final Block getElse() { unified_guard_if_stmt_def(this, _, result) } + final F::Block getElse() { unified_guard_if_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_guard_if_stmt_def(this, result, _) or unified_guard_if_stmt_def(this, _, result) } } /** A class representing `identifier` tokens. */ - final class Identifier extends @unified_token_identifier, TokenImpl { + class Identifier extends @unified_token_identifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Identifier" } } /** A class representing `if_expr` nodes. */ - final class IfExpr extends @unified_if_expr, AstNodeImpl { + class IfExpr extends @unified_if_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IfExpr" } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_if_expr_def(this, result) } + final F::Expr getCondition() { unified_if_expr_def(this, result) } /** Gets the node corresponding to the field `else`. */ - final Expr getElse() { unified_if_expr_else(this, result) } + final F::Expr getElse() { unified_if_expr_else(this, result) } /** Gets the node corresponding to the field `then`. */ - final Expr getThen() { unified_if_expr_then(this, result) } + final F::Expr getThen() { unified_if_expr_then(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_if_expr_def(this, result) or unified_if_expr_else(this, result) or unified_if_expr_then(this, result) @@ -771,27 +904,30 @@ module Unified { } /** A class representing `ignore_pattern` tokens. */ - final class IgnorePattern extends @unified_token_ignore_pattern, TokenImpl { + class IgnorePattern extends @unified_token_ignore_pattern, F::Pattern, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IgnorePattern" } } /** A class representing `import_declaration` nodes. */ - final class ImportDeclaration extends @unified_import_declaration, AstNodeImpl { + class ImportDeclaration extends @unified_import_declaration, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ImportDeclaration" } /** Gets the node corresponding to the field `imported_expr`. */ - final Expr getImportedExpr() { unified_import_declaration_def(this, result) } + final F::Expr getImportedExpr() { unified_import_declaration_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_import_declaration_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_import_declaration_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_import_declaration_pattern(this, result) } + final F::Pattern getPattern() { unified_import_declaration_pattern(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_import_declaration_def(this, result) or unified_import_declaration_modifier(this, _, result) or unified_import_declaration_pattern(this, result) @@ -799,182 +935,198 @@ module Unified { } /** A class representing `inferred_type_expr` tokens. */ - final class InferredTypeExpr extends @unified_token_inferred_type_expr, TokenImpl { + class InferredTypeExpr extends @unified_token_inferred_type_expr, F::Token, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InferredTypeExpr" } } /** A class representing `infix_operator` tokens. */ - final class InfixOperator extends @unified_token_infix_operator, TokenImpl { + class InfixOperator extends @unified_token_infix_operator, F::ExprOrOperator, F::Operator, + F::Token + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InfixOperator" } } /** A class representing `initializer_declaration` nodes. */ - final class InitializerDeclaration extends @unified_initializer_declaration, AstNodeImpl { + class InitializerDeclaration extends @unified_initializer_declaration, F::Member { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "InitializerDeclaration" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_initializer_declaration_def(this, result) } + final F::Block getBody() { unified_initializer_declaration_def(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_initializer_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_initializer_declaration_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_initializer_declaration_def(this, result) or unified_initializer_declaration_modifier(this, _, result) } } /** A class representing `int_literal` tokens. */ - final class IntLiteral extends @unified_token_int_literal, TokenImpl { + class IntLiteral extends @unified_token_int_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "IntLiteral" } } /** A class representing `key_value_pair` nodes. */ - final class KeyValuePair extends @unified_key_value_pair, AstNodeImpl { + class KeyValuePair extends @unified_key_value_pair, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "KeyValuePair" } /** Gets the node corresponding to the field `key`. */ - final Expr getKey() { unified_key_value_pair_def(this, result, _) } + final F::Expr getKey() { unified_key_value_pair_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_key_value_pair_def(this, _, result) } + final F::Expr getValue() { unified_key_value_pair_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_key_value_pair_def(this, result, _) or unified_key_value_pair_def(this, _, result) } } /** A class representing `labeled_stmt` nodes. */ - final class LabeledStmt extends @unified_labeled_stmt, AstNodeImpl { + class LabeledStmt extends @unified_labeled_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "LabeledStmt" } /** Gets the node corresponding to the field `label`. */ - final Identifier getLabel() { unified_labeled_stmt_def(this, result, _) } + final F::Identifier getLabel() { unified_labeled_stmt_def(this, result, _) } /** Gets the node corresponding to the field `stmt`. */ - final Stmt getStmt() { unified_labeled_stmt_def(this, _, result) } + final F::Stmt getStmt() { unified_labeled_stmt_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_labeled_stmt_def(this, result, _) or unified_labeled_stmt_def(this, _, result) } } /** A class representing `map_literal` nodes. */ - final class MapLiteral extends @unified_map_literal, AstNodeImpl { + class MapLiteral extends @unified_map_literal, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MapLiteral" } /** Gets the node corresponding to the field `element`. */ - final Expr getElement(int i) { unified_map_literal_element(this, i, result) } + final F::Expr getElement(int i) { unified_map_literal_element(this, i, result) } + + /** Gets the node corresponding to the field `element`. */ + final F::Expr getAnElement() { result = this.getElement(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_map_literal_element(this, _, result) } } - final class Member extends @unified_member, AstNodeImpl { } + class Member extends @unified_member, F::AstNode { } /** A class representing `member_access_expr` nodes. */ - final class MemberAccessExpr extends @unified_member_access_expr, AstNodeImpl { + class MemberAccessExpr extends @unified_member_access_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "MemberAccessExpr" } /** Gets the node corresponding to the field `base`. */ - final ExprOrType getBase() { unified_member_access_expr_def(this, result, _) } + final F::ExprOrType getBase() { unified_member_access_expr_def(this, result, _) } /** Gets the node corresponding to the field `member`. */ - final Identifier getMember() { unified_member_access_expr_def(this, _, result) } + final F::Identifier getMember() { unified_member_access_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_member_access_expr_def(this, result, _) or unified_member_access_expr_def(this, _, result) } } /** A class representing `modifier` tokens. */ - final class Modifier extends @unified_token_modifier, TokenImpl { + class Modifier extends @unified_token_modifier, F::AstNode, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Modifier" } } /** A class representing `name_expr` nodes. */ - final class NameExpr extends @unified_name_expr, AstNodeImpl { + class NameExpr extends @unified_name_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NameExpr" } /** Gets the node corresponding to the field `identifier`. */ - final Identifier getIdentifier() { unified_name_expr_def(this, result) } + final F::Identifier getIdentifier() { unified_name_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_name_expr_def(this, result) } + final override F::AstNode getAFieldOrChild() { unified_name_expr_def(this, result) } } /** A class representing `name_pattern` nodes. */ - final class NamePattern extends @unified_name_pattern, AstNodeImpl { + class NamePattern extends @unified_name_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamePattern" } /** Gets the node corresponding to the field `identifier`. */ - final Identifier getIdentifier() { unified_name_pattern_def(this, result) } + final F::Identifier getIdentifier() { unified_name_pattern_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_name_pattern_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_name_pattern_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_name_pattern_def(this, result) or unified_name_pattern_modifier(this, _, result) } } /** A class representing `named_type_expr` nodes. */ - final class NamedTypeExpr extends @unified_named_type_expr, AstNodeImpl { + class NamedTypeExpr extends @unified_named_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "NamedTypeExpr" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_named_type_expr_def(this, result) } + final F::Identifier getName() { unified_named_type_expr_def(this, result) } /** Gets the node corresponding to the field `qualifier`. */ - final TypeExpr getQualifier() { unified_named_type_expr_qualifier(this, result) } + final F::TypeExpr getQualifier() { unified_named_type_expr_qualifier(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_named_type_expr_def(this, result) or unified_named_type_expr_qualifier(this, result) } } - final class Operator extends @unified_operator, AstNodeImpl { } + class Operator extends @unified_operator, F::AstNode { } /** A class representing `operator_syntax_declaration` nodes. */ - final class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, AstNodeImpl { + class OperatorSyntaxDeclaration extends @unified_operator_syntax_declaration, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OperatorSyntaxDeclaration" } /** Gets the node corresponding to the field `fixity`. */ - final Fixity getFixity() { unified_operator_syntax_declaration_fixity(this, result) } + final F::Fixity getFixity() { unified_operator_syntax_declaration_fixity(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { + final F::Modifier getModifier(int i) { unified_operator_syntax_declaration_modifier(this, i, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_operator_syntax_declaration_def(this, result) } + final F::Identifier getName() { unified_operator_syntax_declaration_def(this, result) } /** Gets the node corresponding to the field `precedence`. */ - final Expr getPrecedence() { unified_operator_syntax_declaration_precedence(this, result) } + final F::Expr getPrecedence() { unified_operator_syntax_declaration_precedence(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_operator_syntax_declaration_fixity(this, result) or unified_operator_syntax_declaration_modifier(this, _, result) or unified_operator_syntax_declaration_def(this, result) or @@ -983,44 +1135,53 @@ module Unified { } /** A class representing `or_pattern` nodes. */ - final class OrPattern extends @unified_or_pattern, AstNodeImpl { + class OrPattern extends @unified_or_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "OrPattern" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_or_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_or_pattern_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } + + /** Gets the node corresponding to the field `pattern`. */ + final F::Pattern getPattern(int i) { unified_or_pattern_pattern(this, i, result) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern(int i) { unified_or_pattern_pattern(this, i, result) } + final F::Pattern getAPattern() { result = this.getPattern(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_or_pattern_modifier(this, _, result) or unified_or_pattern_pattern(this, _, result) } } /** A class representing `parameter` nodes. */ - final class Parameter extends @unified_parameter, AstNodeImpl { + class Parameter extends @unified_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "Parameter" } /** Gets the node corresponding to the field `default`. */ - final Expr getDefault() { unified_parameter_default(this, result) } + final F::Expr getDefault() { unified_parameter_default(this, result) } /** Gets the node corresponding to the field `external_name`. */ - final Identifier getExternalName() { unified_parameter_external_name(this, result) } + final F::Identifier getExternalName() { unified_parameter_external_name(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_parameter_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_parameter_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_parameter_pattern(this, result) } + final F::Pattern getPattern() { unified_parameter_pattern(this, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_parameter_type(this, result) } + final F::TypeExpr getType() { unified_parameter_type(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_parameter_default(this, result) or unified_parameter_external_name(this, result) or unified_parameter_modifier(this, _, result) or @@ -1029,24 +1190,27 @@ module Unified { } } - final class Pattern extends @unified_pattern, AstNodeImpl { } + class Pattern extends @unified_pattern, F::ExprOrPattern { } /** A class representing `pattern_element` nodes. */ - final class PatternElement extends @unified_pattern_element, AstNodeImpl { + class PatternElement extends @unified_pattern_element, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternElement" } /** Gets the node corresponding to the field `key`. */ - final Identifier getKey() { unified_pattern_element_key(this, result) } + final F::Identifier getKey() { unified_pattern_element_key(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_pattern_element_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_pattern_element_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_pattern_element_def(this, result) } + final F::Pattern getPattern() { unified_pattern_element_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_pattern_element_key(this, result) or unified_pattern_element_modifier(this, _, result) or unified_pattern_element_def(this, result) @@ -1054,109 +1218,114 @@ module Unified { } /** A class representing `pattern_guard_expr` nodes. */ - final class PatternGuardExpr extends @unified_pattern_guard_expr, AstNodeImpl { + class PatternGuardExpr extends @unified_pattern_guard_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PatternGuardExpr" } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_pattern_guard_expr_def(this, result, _) } + final F::Pattern getPattern() { unified_pattern_guard_expr_def(this, result, _) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_pattern_guard_expr_def(this, _, result) } + final F::Expr getValue() { unified_pattern_guard_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_pattern_guard_expr_def(this, result, _) or unified_pattern_guard_expr_def(this, _, result) } } /** A class representing `postfix_operator` tokens. */ - final class PostfixOperator extends @unified_token_postfix_operator, TokenImpl { + class PostfixOperator extends @unified_token_postfix_operator, F::Operator, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PostfixOperator" } } /** A class representing `prefix_operator` tokens. */ - final class PrefixOperator extends @unified_token_prefix_operator, TokenImpl { + class PrefixOperator extends @unified_token_prefix_operator, F::Operator, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "PrefixOperator" } } /** A class representing `regex_literal` tokens. */ - final class RegexLiteral extends @unified_token_regex_literal, TokenImpl { + class RegexLiteral extends @unified_token_regex_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "RegexLiteral" } } /** A class representing `return_expr` nodes. */ - final class ReturnExpr extends @unified_return_expr, AstNodeImpl { + class ReturnExpr extends @unified_return_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ReturnExpr" } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_return_expr_value(this, result) } + final F::Expr getValue() { unified_return_expr_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } + final override F::AstNode getAFieldOrChild() { unified_return_expr_value(this, result) } } - final class Stmt extends @unified_stmt, AstNodeImpl { } + class Stmt extends @unified_stmt, F::AstNode { } /** A class representing `string_literal` tokens. */ - final class StringLiteral extends @unified_token_string_literal, TokenImpl { + class StringLiteral extends @unified_token_string_literal, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringLiteral" } } /** A class representing `super_expr` tokens. */ - final class SuperExpr extends @unified_token_super_expr, TokenImpl { + class SuperExpr extends @unified_token_super_expr, F::Expr, F::Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SuperExpr" } } /** A class representing `switch_case` nodes. */ - final class SwitchCase extends @unified_switch_case, AstNodeImpl { + class SwitchCase extends @unified_switch_case, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchCase" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_switch_case_def(this, result) } + final F::Block getBody() { unified_switch_case_def(this, result) } - /** Gets the node corresponding to the field `guard`. */ - final Expr getGuard() { unified_switch_case_guard(this, result) } + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_switch_case_pattern(this, result) } + final F::Pattern getPattern() { unified_switch_case_pattern(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_switch_case_def(this, result) or - unified_switch_case_guard(this, result) or unified_switch_case_modifier(this, _, result) or unified_switch_case_pattern(this, result) } } /** A class representing `switch_expr` nodes. */ - final class SwitchExpr extends @unified_switch_expr, AstNodeImpl { + class SwitchExpr extends @unified_switch_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "SwitchExpr" } /** Gets the node corresponding to the field `case`. */ - final SwitchCase getCase(int i) { unified_switch_expr_case(this, i, result) } + final F::SwitchCase getCase(int i) { unified_switch_expr_case(this, i, result) } + + /** Gets the node corresponding to the field `case`. */ + final F::SwitchCase getACase() { result = this.getCase(_) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_switch_expr_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_switch_expr_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_switch_expr_def(this, result) } + final F::Expr getValue() { unified_switch_expr_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_switch_expr_case(this, _, result) or unified_switch_expr_modifier(this, _, result) or unified_switch_expr_def(this, result) @@ -1164,45 +1333,51 @@ module Unified { } /** A class representing `throw_expr` nodes. */ - final class ThrowExpr extends @unified_throw_expr, AstNodeImpl { + class ThrowExpr extends @unified_throw_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "ThrowExpr" } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_throw_expr_value(this, result) } + final F::Expr getValue() { unified_throw_expr_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_throw_expr_value(this, result) } + final override F::AstNode getAFieldOrChild() { unified_throw_expr_value(this, result) } } /** A class representing `top_level` nodes. */ - final class TopLevel extends @unified_top_level, AstNodeImpl { + class TopLevel extends @unified_top_level, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TopLevel" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_top_level_def(this, result) } + final F::Block getBody() { unified_top_level_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_top_level_def(this, result) } + final override F::AstNode getAFieldOrChild() { unified_top_level_def(this, result) } } /** A class representing `try_expr` nodes. */ - final class TryExpr extends @unified_try_expr, AstNodeImpl { + class TryExpr extends @unified_try_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TryExpr" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_try_expr_def(this, result) } + final F::Block getBody() { unified_try_expr_def(this, result) } + + /** Gets the node corresponding to the field `catch_clause`. */ + final F::CatchClause getCatchClause(int i) { unified_try_expr_catch_clause(this, i, result) } /** Gets the node corresponding to the field `catch_clause`. */ - final CatchClause getCatchClause(int i) { unified_try_expr_catch_clause(this, i, result) } + final F::CatchClause getACatchClause() { result = this.getCatchClause(_) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_try_expr_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_try_expr_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_try_expr_def(this, result) or unified_try_expr_catch_clause(this, _, result) or unified_try_expr_modifier(this, _, result) @@ -1210,90 +1385,115 @@ module Unified { } /** A class representing `tuple_expr` nodes. */ - final class TupleExpr extends @unified_tuple_expr, AstNodeImpl { + class TupleExpr extends @unified_tuple_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleExpr" } /** Gets the node corresponding to the field `element`. */ - final Expr getElement(int i) { unified_tuple_expr_element(this, i, result) } + final F::Expr getElement(int i) { unified_tuple_expr_element(this, i, result) } + + /** Gets the node corresponding to the field `element`. */ + final F::Expr getAnElement() { result = this.getElement(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_tuple_expr_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { unified_tuple_expr_element(this, _, result) } } /** A class representing `tuple_pattern` nodes. */ - final class TuplePattern extends @unified_tuple_pattern, AstNodeImpl { + class TuplePattern extends @unified_tuple_pattern, F::Pattern { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TuplePattern" } /** Gets the node corresponding to the field `element`. */ - final PatternElement getElement(int i) { unified_tuple_pattern_element(this, i, result) } + final F::PatternElement getElement(int i) { unified_tuple_pattern_element(this, i, result) } + + /** Gets the node corresponding to the field `element`. */ + final F::PatternElement getAnElement() { result = this.getElement(_) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_tuple_pattern_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_tuple_pattern_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_tuple_pattern_element(this, _, result) or unified_tuple_pattern_modifier(this, _, result) } } /** A class representing `tuple_type_element` nodes. */ - final class TupleTypeElement extends @unified_tuple_type_element, AstNodeImpl { + class TupleTypeElement extends @unified_tuple_type_element, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeElement" } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_tuple_type_element_name(this, result) } + final F::Identifier getName() { unified_tuple_type_element_name(this, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_tuple_type_element_def(this, result) } + final F::TypeExpr getType() { unified_tuple_type_element_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_tuple_type_element_name(this, result) or unified_tuple_type_element_def(this, result) } } /** A class representing `tuple_type_expr` nodes. */ - final class TupleTypeExpr extends @unified_tuple_type_expr, AstNodeImpl { + class TupleTypeExpr extends @unified_tuple_type_expr, F::TypeExpr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TupleTypeExpr" } /** Gets the node corresponding to the field `element`. */ - final TupleTypeElement getElement(int i) { unified_tuple_type_expr_element(this, i, result) } + final F::TupleTypeElement getElement(int i) { unified_tuple_type_expr_element(this, i, result) } + + /** Gets the node corresponding to the field `element`. */ + final F::TupleTypeElement getAnElement() { result = this.getElement(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { unified_tuple_type_expr_element(this, _, result) } + final override F::AstNode getAFieldOrChild() { + unified_tuple_type_expr_element(this, _, result) + } } /** A class representing `type_alias_declaration` nodes. */ - final class TypeAliasDeclaration extends @unified_type_alias_declaration, AstNodeImpl { + class TypeAliasDeclaration extends @unified_type_alias_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_type_alias_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { + unified_type_alias_declaration_modifier(this, i, result) + } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_type_alias_declaration_def(this, result, _) } + final F::Identifier getName() { unified_type_alias_declaration_def(this, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_alias_declaration_def(this, _, result) } + final F::TypeExpr getType() { unified_type_alias_declaration_def(this, _, result) } /** Gets the node corresponding to the field `type_constraint`. */ - final TypeConstraint getTypeConstraint(int i) { + final F::TypeConstraint getTypeConstraint(int i) { unified_type_alias_declaration_type_constraint(this, i, result) } + /** Gets the node corresponding to the field `type_constraint`. */ + final F::TypeConstraint getATypeConstraint() { result = this.getTypeConstraint(_) } + /** Gets the node corresponding to the field `type_parameter`. */ - final TypeParameter getTypeParameter(int i) { + final F::TypeParameter getTypeParameter(int i) { unified_type_alias_declaration_type_parameter(this, i, result) } + /** Gets the node corresponding to the field `type_parameter`. */ + final F::TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } + /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_alias_declaration_modifier(this, _, result) or unified_type_alias_declaration_def(this, result, _) or unified_type_alias_declaration_def(this, _, result) or @@ -1303,47 +1503,50 @@ module Unified { } /** A class representing `type_cast_expr` nodes. */ - final class TypeCastExpr extends @unified_type_cast_expr, AstNodeImpl { + class TypeCastExpr extends @unified_type_cast_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeCastExpr" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_type_cast_expr_def(this, result, _, _) } + final F::Expr getExpr() { unified_type_cast_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_type_cast_expr_def(this, _, result, _) } + final F::InfixOperator getOperator() { unified_type_cast_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_cast_expr_def(this, _, _, result) } + final F::TypeExpr getType() { unified_type_cast_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_cast_expr_def(this, result, _, _) or unified_type_cast_expr_def(this, _, result, _) or unified_type_cast_expr_def(this, _, _, result) } } - final class TypeConstraint extends @unified_type_constraint, AstNodeImpl { } + class TypeConstraint extends @unified_type_constraint, F::AstNode { } - final class TypeExpr extends @unified_type_expr, AstNodeImpl { } + class TypeExpr extends @unified_type_expr, F::ExprOrType { } /** A class representing `type_parameter` nodes. */ - final class TypeParameter extends @unified_type_parameter, AstNodeImpl { + class TypeParameter extends @unified_type_parameter, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeParameter" } /** Gets the node corresponding to the field `bound`. */ - final TypeExpr getBound() { unified_type_parameter_bound(this, result) } + final F::TypeExpr getBound() { unified_type_parameter_bound(this, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_type_parameter_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_type_parameter_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `name`. */ - final Identifier getName() { unified_type_parameter_def(this, result) } + final F::Identifier getName() { unified_type_parameter_def(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_parameter_bound(this, result) or unified_type_parameter_modifier(this, _, result) or unified_type_parameter_def(this, result) @@ -1351,21 +1554,21 @@ module Unified { } /** A class representing `type_test_expr` nodes. */ - final class TypeTestExpr extends @unified_type_test_expr, AstNodeImpl { + class TypeTestExpr extends @unified_type_test_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestExpr" } /** Gets the node corresponding to the field `expr`. */ - final Expr getExpr() { unified_type_test_expr_def(this, result, _, _) } + final F::Expr getExpr() { unified_type_test_expr_def(this, result, _, _) } /** Gets the node corresponding to the field `operator`. */ - final InfixOperator getOperator() { unified_type_test_expr_def(this, _, result, _) } + final F::InfixOperator getOperator() { unified_type_test_expr_def(this, _, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_test_expr_def(this, _, _, result) } + final F::TypeExpr getType() { unified_type_test_expr_def(this, _, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_test_expr_def(this, result, _, _) or unified_type_test_expr_def(this, _, result, _) or unified_type_test_expr_def(this, _, _, result) @@ -1373,65 +1576,89 @@ module Unified { } /** A class representing `type_test_pattern` nodes. */ - final class TypeTestPattern extends @unified_type_test_pattern, AstNodeImpl { + class TypeTestPattern extends @unified_type_test_pattern, F::AstNode { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "TypeTestPattern" } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_type_test_pattern_def(this, result, _) } + final F::Pattern getPattern() { unified_type_test_pattern_def(this, result, _) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_type_test_pattern_def(this, _, result) } + final F::TypeExpr getType() { unified_type_test_pattern_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_type_test_pattern_def(this, result, _) or unified_type_test_pattern_def(this, _, result) } } /** A class representing `unary_expr` nodes. */ - final class UnaryExpr extends @unified_unary_expr, AstNodeImpl { + class UnaryExpr extends @unified_unary_expr, F::Expr { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnaryExpr" } /** Gets the node corresponding to the field `operand`. */ - final Expr getOperand() { unified_unary_expr_def(this, result, _) } + final F::Expr getOperand() { unified_unary_expr_def(this, result, _) } /** Gets the node corresponding to the field `operator`. */ - final Operator getOperator() { unified_unary_expr_def(this, _, result) } + final F::Operator getOperator() { unified_unary_expr_def(this, _, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_unary_expr_def(this, result, _) or unified_unary_expr_def(this, _, result) } } + /** A class representing `unresolved_operator_sequence` nodes. */ + class UnresolvedOperatorSequence extends @unified_unresolved_operator_sequence, F::Expr { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UnresolvedOperatorSequence" } + + /** Gets the node corresponding to the field `element`. */ + final F::ExprOrOperator getElement(int i) { + unified_unresolved_operator_sequence_element(this, i, result) + } + + /** Gets the node corresponding to the field `element`. */ + final F::ExprOrOperator getAnElement() { result = this.getElement(_) } + + /** Gets a field or child node of this node. */ + final override F::AstNode getAFieldOrChild() { + unified_unresolved_operator_sequence_element(this, _, result) + } + } + /** A class representing `unsupported_node` tokens. */ - final class UnsupportedNode extends @unified_token_unsupported_node, TokenImpl { + class UnsupportedNode extends @unified_token_unsupported_node, F::Expr, F::Member, F::Pattern, + F::Token, F::TypeExpr + { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "UnsupportedNode" } } /** A class representing `variable_declaration` nodes. */ - final class VariableDeclaration extends @unified_variable_declaration, AstNodeImpl { + class VariableDeclaration extends @unified_variable_declaration, F::Member, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "VariableDeclaration" } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_variable_declaration_modifier(this, i, result) } + final F::Modifier getModifier(int i) { unified_variable_declaration_modifier(this, i, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets the node corresponding to the field `pattern`. */ - final Pattern getPattern() { unified_variable_declaration_def(this, result) } + final F::Pattern getPattern() { unified_variable_declaration_def(this, result) } /** Gets the node corresponding to the field `type`. */ - final TypeExpr getType() { unified_variable_declaration_type(this, result) } + final F::TypeExpr getType() { unified_variable_declaration_type(this, result) } /** Gets the node corresponding to the field `value`. */ - final Expr getValue() { unified_variable_declaration_value(this, result) } + final F::Expr getValue() { unified_variable_declaration_value(this, result) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_variable_declaration_modifier(this, _, result) or unified_variable_declaration_def(this, result) or unified_variable_declaration_type(this, result) or @@ -1440,21 +1667,24 @@ module Unified { } /** A class representing `while_stmt` nodes. */ - final class WhileStmt extends @unified_while_stmt, AstNodeImpl { + class WhileStmt extends @unified_while_stmt, F::Stmt { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "WhileStmt" } /** Gets the node corresponding to the field `body`. */ - final Block getBody() { unified_while_stmt_body(this, result) } + final F::Block getBody() { unified_while_stmt_body(this, result) } /** Gets the node corresponding to the field `condition`. */ - final Expr getCondition() { unified_while_stmt_def(this, result) } + final F::Expr getCondition() { unified_while_stmt_def(this, result) } + + /** Gets the node corresponding to the field `modifier`. */ + final F::Modifier getModifier(int i) { unified_while_stmt_modifier(this, i, result) } /** Gets the node corresponding to the field `modifier`. */ - final Modifier getModifier(int i) { unified_while_stmt_modifier(this, i, result) } + final F::Modifier getAModifier() { result = this.getModifier(_) } /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { + final override F::AstNode getAFieldOrChild() { unified_while_stmt_body(this, result) or unified_while_stmt_def(this, result) or unified_while_stmt_modifier(this, _, result) @@ -1464,7 +1694,7 @@ module Unified { /** Provides predicates for mapping AST nodes to their named children. */ module PrintAst { /** Gets a child of `node` returned by the member predicate with the given `name`. If the predicate takes an index argument, `i` is bound to that index, otherwise `i` is `-1` (which is never a valid index). */ - AstNode getChild(AstNode node, string name, int i) { + F::AstNode getChild(F::AstNode node, string name, int i) { result = node.(AccessorDeclaration).getAccessorKind() and i = -1 and name = "getAccessorKind" or result = node.(AccessorDeclaration).getBody() and i = -1 and name = "getBody" @@ -1523,8 +1753,6 @@ module Unified { or result = node.(CatchClause).getBody() and i = -1 and name = "getBody" or - result = node.(CatchClause).getGuard() and i = -1 and name = "getGuard" - or result = node.(CatchClause).getModifier(i) and name = "getModifier" or result = node.(CatchClause).getPattern() and i = -1 and name = "getPattern" @@ -1547,6 +1775,12 @@ module Unified { or result = node.(CompoundAssignExpr).getValue() and i = -1 and name = "getValue" or + result = node.(ConditionalPattern).getCondition() and i = -1 and name = "getCondition" + or + result = node.(ConditionalPattern).getModifier(i) and name = "getModifier" + or + result = node.(ConditionalPattern).getPattern() and i = -1 and name = "getPattern" + or result = node.(ConstructorDeclaration).getBody() and i = -1 and name = "getBody" or result = node.(ConstructorDeclaration).getModifier(i) and name = "getModifier" @@ -1703,8 +1937,6 @@ module Unified { or result = node.(SwitchCase).getBody() and i = -1 and name = "getBody" or - result = node.(SwitchCase).getGuard() and i = -1 and name = "getGuard" - or result = node.(SwitchCase).getModifier(i) and name = "getModifier" or result = node.(SwitchCase).getPattern() and i = -1 and name = "getPattern" @@ -1773,6 +2005,8 @@ module Unified { or result = node.(UnaryExpr).getOperator() and i = -1 and name = "getOperator" or + result = node.(UnresolvedOperatorSequence).getElement(i) and name = "getElement" + or result = node.(VariableDeclaration).getModifier(i) and name = "getModifier" or result = node.(VariableDeclaration).getPattern() and i = -1 and name = "getPattern" @@ -1789,3 +2023,196 @@ module Unified { } } } + +module UnifiedFinal { + private import FacadeAst::Unified as F + import F + + final class AstNode = F::AstNode; + + final class Token = F::Token; + + final class TriviaToken = F::TriviaToken; + + final class AccessorDeclaration = F::AccessorDeclaration; + + final class AccessorKind = F::AccessorKind; + + final class Argument = F::Argument; + + final class ArrayLiteral = F::ArrayLiteral; + + final class AssignExpr = F::AssignExpr; + + final class AssociatedTypeDeclaration = F::AssociatedTypeDeclaration; + + final class BaseType = F::BaseType; + + final class BinaryExpr = F::BinaryExpr; + + final class Block = F::Block; + + final class BooleanLiteral = F::BooleanLiteral; + + final class BoundTypeConstraint = F::BoundTypeConstraint; + + final class BreakExpr = F::BreakExpr; + + final class BuiltinExpr = F::BuiltinExpr; + + final class BulkImportingPattern = F::BulkImportingPattern; + + final class CallExpr = F::CallExpr; + + final class CatchClause = F::CatchClause; + + final class ClassLikeDeclaration = F::ClassLikeDeclaration; + + final class CompoundAssignExpr = F::CompoundAssignExpr; + + final class ConditionalPattern = F::ConditionalPattern; + + final class ConstructorDeclaration = F::ConstructorDeclaration; + + final class ConstructorPattern = F::ConstructorPattern; + + final class ContinueExpr = F::ContinueExpr; + + final class DestructorDeclaration = F::DestructorDeclaration; + + final class DoWhileStmt = F::DoWhileStmt; + + final class EmptyExpr = F::EmptyExpr; + + final class EqualityTypeConstraint = F::EqualityTypeConstraint; + + final class Expr = F::Expr; + + final class ExprEqualityPattern = F::ExprEqualityPattern; + + final class ExprOrOperator = F::ExprOrOperator; + + final class ExprOrPattern = F::ExprOrPattern; + + final class ExprOrType = F::ExprOrType; + + final class Fixity = F::Fixity; + + final class FloatLiteral = F::FloatLiteral; + + final class ForEachStmt = F::ForEachStmt; + + final class FunctionDeclaration = F::FunctionDeclaration; + + final class FunctionExpr = F::FunctionExpr; + + final class FunctionTypeExpr = F::FunctionTypeExpr; + + final class GenericTypeExpr = F::GenericTypeExpr; + + final class GuardIfStmt = F::GuardIfStmt; + + final class Identifier = F::Identifier; + + final class IfExpr = F::IfExpr; + + final class IgnorePattern = F::IgnorePattern; + + final class ImportDeclaration = F::ImportDeclaration; + + final class InferredTypeExpr = F::InferredTypeExpr; + + final class InfixOperator = F::InfixOperator; + + final class InitializerDeclaration = F::InitializerDeclaration; + + final class IntLiteral = F::IntLiteral; + + final class KeyValuePair = F::KeyValuePair; + + final class LabeledStmt = F::LabeledStmt; + + final class MapLiteral = F::MapLiteral; + + final class Member = F::Member; + + final class MemberAccessExpr = F::MemberAccessExpr; + + final class Modifier = F::Modifier; + + final class NameExpr = F::NameExpr; + + final class NamePattern = F::NamePattern; + + final class NamedTypeExpr = F::NamedTypeExpr; + + final class Operator = F::Operator; + + final class OperatorSyntaxDeclaration = F::OperatorSyntaxDeclaration; + + final class OrPattern = F::OrPattern; + + final class Parameter = F::Parameter; + + final class Pattern = F::Pattern; + + final class PatternElement = F::PatternElement; + + final class PatternGuardExpr = F::PatternGuardExpr; + + final class PostfixOperator = F::PostfixOperator; + + final class PrefixOperator = F::PrefixOperator; + + final class RegexLiteral = F::RegexLiteral; + + final class ReturnExpr = F::ReturnExpr; + + final class Stmt = F::Stmt; + + final class StringLiteral = F::StringLiteral; + + final class SuperExpr = F::SuperExpr; + + final class SwitchCase = F::SwitchCase; + + final class SwitchExpr = F::SwitchExpr; + + final class ThrowExpr = F::ThrowExpr; + + final class TopLevel = F::TopLevel; + + final class TryExpr = F::TryExpr; + + final class TupleExpr = F::TupleExpr; + + final class TuplePattern = F::TuplePattern; + + final class TupleTypeElement = F::TupleTypeElement; + + final class TupleTypeExpr = F::TupleTypeExpr; + + final class TypeAliasDeclaration = F::TypeAliasDeclaration; + + final class TypeCastExpr = F::TypeCastExpr; + + final class TypeConstraint = F::TypeConstraint; + + final class TypeExpr = F::TypeExpr; + + final class TypeParameter = F::TypeParameter; + + final class TypeTestExpr = F::TypeTestExpr; + + final class TypeTestPattern = F::TypeTestPattern; + + final class UnaryExpr = F::UnaryExpr; + + final class UnresolvedOperatorSequence = F::UnresolvedOperatorSequence; + + final class UnsupportedNode = F::UnsupportedNode; + + final class VariableDeclaration = F::VariableDeclaration; + + final class WhileStmt = F::WhileStmt; +} diff --git a/unified/ql/lib/codeql/unified/internal/FacadeAst.qll b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll new file mode 100644 index 000000000000..a25fb3447c1e --- /dev/null +++ b/unified/ql/lib/codeql/unified/internal/FacadeAst.qll @@ -0,0 +1,31 @@ +/** + * Provides facade AST classes, with additional hand-written members on top of the generated ones. + */ +overlay[local?] +module; + +module Unified { + private import Ast::Unified as G + import G + + /** The base class for all AST nodes. */ + class AstNode extends G::AstNode { + /** Holds if this AST node has a modifier with the given text. */ + predicate hasModifier(string text) { + exists(Modifier mod | + mod.getParent() = this and + mod.getValue() = text + ) + } + } + + /** The base class for all patterns. */ + class Pattern extends G::Pattern { + /** Gets the immediately-enclosing pattern in which this is a nested pattern. */ + Pattern getEnclosingPattern() { + result = this.getParent() + or + result = this.getParent().(PatternElement).getParent() + } + } +} diff --git a/unified/ql/lib/codeql/unified/internal/Variables.qll b/unified/ql/lib/codeql/unified/internal/Variables.qll index 97629f2c57ff..49cad56d05db 100644 --- a/unified/ql/lib/codeql/unified/internal/Variables.qll +++ b/unified/ql/lib/codeql/unified/internal/Variables.qll @@ -178,12 +178,12 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig; diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme index e957e303c22f..8306c3fcf0c7 100644 --- a/unified/ql/lib/unified.dbscheme +++ b/unified/ql/lib/unified.dbscheme @@ -292,11 +292,6 @@ unified_call_expr_def( int callee: @unified_expr_or_type ref ); -unified_catch_clause_guard( - unique int unified_catch_clause: @unified_catch_clause ref, - unique int guard: @unified_expr ref -); - #keyset[unified_catch_clause, index] unified_catch_clause_modifier( int unified_catch_clause: @unified_catch_clause ref, @@ -365,6 +360,19 @@ unified_compound_assign_expr_def( int value: @unified_expr ref ); +#keyset[unified_conditional_pattern, index] +unified_conditional_pattern_modifier( + int unified_conditional_pattern: @unified_conditional_pattern ref, + int index: int ref, + unique int modifier: @unified_token_modifier ref +); + +unified_conditional_pattern_def( + unique int id: @unified_conditional_pattern, + int condition: @unified_expr ref, + int pattern: @unified_pattern ref +); + #keyset[unified_constructor_declaration, index] unified_constructor_declaration_modifier( int unified_constructor_declaration: @unified_constructor_declaration ref, @@ -452,13 +460,15 @@ unified_equality_type_constraint_def( int right: @unified_type_expr ref ); -@unified_expr = @unified_array_literal | @unified_assign_expr | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_call_expr | @unified_compound_assign_expr | @unified_continue_expr | @unified_function_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr +@unified_expr = @unified_array_literal | @unified_assign_expr | @unified_binary_expr | @unified_block | @unified_break_expr | @unified_call_expr | @unified_compound_assign_expr | @unified_continue_expr | @unified_function_expr | @unified_if_expr | @unified_key_value_pair | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_expr | @unified_throw_expr | @unified_token_boolean_literal | @unified_token_builtin_expr | @unified_token_empty_expr | @unified_token_float_literal | @unified_token_int_literal | @unified_token_regex_literal | @unified_token_string_literal | @unified_token_super_expr | @unified_token_unsupported_node | @unified_try_expr | @unified_tuple_expr | @unified_type_cast_expr | @unified_type_test_expr | @unified_unary_expr | @unified_unresolved_operator_sequence unified_expr_equality_pattern_def( unique int id: @unified_expr_equality_pattern, int expr: @unified_expr ref ); +@unified_expr_or_operator = @unified_expr | @unified_token_infix_operator + @unified_expr_or_pattern = @unified_expr | @unified_pattern @unified_expr_or_type = @unified_expr | @unified_type_expr @@ -765,7 +775,7 @@ unified_parameter_def( unique int id: @unified_parameter ); -@unified_pattern = @unified_bulk_importing_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern +@unified_pattern = @unified_bulk_importing_pattern | @unified_conditional_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern unified_pattern_element_key( unique int unified_pattern_element: @unified_pattern_element ref, @@ -801,11 +811,6 @@ unified_return_expr_def( @unified_stmt = @unified_accessor_declaration | @unified_class_like_declaration | @unified_constructor_declaration | @unified_destructor_declaration | @unified_do_while_stmt | @unified_expr | @unified_for_each_stmt | @unified_function_declaration | @unified_guard_if_stmt | @unified_import_declaration | @unified_labeled_stmt | @unified_operator_syntax_declaration | @unified_type_alias_declaration | @unified_variable_declaration | @unified_while_stmt -unified_switch_case_guard( - unique int unified_switch_case: @unified_switch_case ref, - unique int guard: @unified_expr ref -); - #keyset[unified_switch_case, index] unified_switch_case_modifier( int unified_switch_case: @unified_switch_case ref, @@ -999,6 +1004,17 @@ unified_unary_expr_def( int operator: @unified_operator ref ); +#keyset[unified_unresolved_operator_sequence, index] +unified_unresolved_operator_sequence_element( + int unified_unresolved_operator_sequence: @unified_unresolved_operator_sequence ref, + int index: int ref, + unique int element: @unified_expr_or_operator ref +); + +unified_unresolved_operator_sequence_def( + unique int id: @unified_unresolved_operator_sequence +); + #keyset[unified_variable_declaration, index] unified_variable_declaration_modifier( int unified_variable_declaration: @unified_variable_declaration ref, @@ -1072,7 +1088,7 @@ unified_trivia_tokeninfo( string value: string ref ); -@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_variable_declaration | @unified_while_stmt +@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_conditional_pattern | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt unified_ast_node_location( unique int node: @unified_ast_node ref, diff --git a/unified/ql/lib/unified.qll b/unified/ql/lib/unified.qll index 477ac22f3661..fad4b3ef9e67 100644 --- a/unified/ql/lib/unified.qll +++ b/unified/ql/lib/unified.qll @@ -4,6 +4,6 @@ import codeql.Locations import codeql.files.FileSystem -import codeql.unified.Ast::Unified +import codeql.unified.internal.Ast::UnifiedFinal import codeql.unified.internal.AstExtra::Public import codeql.unified.internal.Variables::Public diff --git a/unified/ql/test/library-tests/BasicTest/test.ql b/unified/ql/test/library-tests/BasicTest/test.ql index ca422d039781..5e70f9303687 100644 --- a/unified/ql/test/library-tests/BasicTest/test.ql +++ b/unified/ql/test/library-tests/BasicTest/test.ql @@ -1,4 +1,4 @@ -import codeql.unified.Ast::Unified +import unified query predicate nameExpr(NameExpr node, string value) { value = node.getIdentifier().getValue() } diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift index 0e6c23782b0d..e4280dc5b408 100644 --- a/unified/ql/test/library-tests/variables/test.swift +++ b/unified/ql/test/library-tests/variables/test.swift @@ -80,7 +80,7 @@ func t10(value: Int) { // name=value1 // Switch with multiple cases func t11(value: Int) { // name=value1 switch value { // $ access=value1 - case let x where x > 0: // name=x1 + case let x where x > 0: // $ access=x1 // name=x1 print(x) // $ access=x1 case let x: // name=x2 print(x) // $ access=x2 @@ -187,6 +187,8 @@ func t22() { } inner() // $ access=inner1 print(x) // $ access=x1 + let inner = 2 // name=inner2 + print(inner) // $ access=inner2 } // Three levels of shadowing @@ -214,7 +216,7 @@ func t24(optional: Int?) { // name=optional1 } } -// Switch with same variable name in different cases +// Switch with variable shadowed within body of case func t25(value: Int) { // name=value1 switch value { // $ access=value1 case let x: // name=x1 @@ -341,11 +343,14 @@ enum E38 { } // Switch with a multi-pattern case that binds 'x' in each pattern -// Note: the testing framework does not make it possible to name the 'x' variable in this case. func t38(value: E38) { switch value { // $ access=value - case .a(let x), // $ access=x - .b(let x): // $ access=x - print(x) // $ access=x + case .a(let x), // $ access=x1 // name=x1 + .b(let x): // $ access=x1 + print(x) // $ access=x1 + + case .a(let y) where y < 1, // $ access=y1 // name=y1 + .b(let y): // $ access=y1 + print(y) // $ access=y1 } } diff --git a/unified/ql/test/library-tests/variables/variables.expected b/unified/ql/test/library-tests/variables/variables.expected index e69de29bb2d1..3bbfe8e89ddf 100644 --- a/unified/ql/test/library-tests/variables/variables.expected +++ b/unified/ql/test/library-tests/variables/variables.expected @@ -0,0 +1,2 @@ +testFailures +ambiguousVariable diff --git a/unified/ql/test/library-tests/variables/variables.ql b/unified/ql/test/library-tests/variables/variables.ql index 146da296ae74..cf653afebd9d 100644 --- a/unified/ql/test/library-tests/variables/variables.ql +++ b/unified/ql/test/library-tests/variables/variables.ql @@ -23,8 +23,8 @@ predicate keyValueCommentAt(string filepath, int line, string key, string value) module VariableAccessTest implements TestSig { string getARelevantTag() { result = "access" } - private predicate declAt(Variable v, string filepath, int line) { - v.getLocation().hasLocationInfo(filepath, _, _, line, _) + additional predicate declAt(Variable v, string filepath, int line) { + v.getLocation().hasLocationInfo(filepath, line, _, _, _) } private predicate decl(Variable v, string alias) { @@ -49,3 +49,13 @@ module VariableAccessTest implements TestSig { } import MakeTest + +private Variable getVariableAt(string name, string filepath, int line) { + VariableAccessTest::declAt(result, filepath, line) and + result.getName() = name +} + +query predicate ambiguousVariable(Variable v, string name, string filepath, int line) { + v = getVariableAt(name, filepath, line) and + strictcount(getVariableAt(name, filepath, line)) >= 2 +} diff --git a/unified/scripts/create-extractor-pack.sh b/unified/scripts/create-extractor-pack.sh index 7a41092e4a74..3c22b0e6cbfd 100755 --- a/unified/scripts/create-extractor-pack.sh +++ b/unified/scripts/create-extractor-pack.sh @@ -14,9 +14,9 @@ cd "$(dirname "$0")/.." # we are in a cargo workspace rooted at the git checkout BIN_DIR=../target/release -"$BIN_DIR/codeql-extractor-unified" generate --dbscheme ql/lib/unified.dbscheme --library ql/lib/codeql/unified/Ast.qll +"$BIN_DIR/codeql-extractor-unified" generate --dbscheme ql/lib/unified.dbscheme --library ql/lib/codeql/unified/internal/Ast.qll -codeql query format -i ql/lib/codeql/unified/Ast.qll +codeql query format -i ql/lib/codeql/unified/internal/Ast.qll rm -rf extractor-pack mkdir -p extractor-pack diff --git a/unified/scripts/regenerate-grammar.sh b/unified/scripts/regenerate-grammar.sh deleted file mode 100755 index b7a5ce263fb8..000000000000 --- a/unified/scripts/regenerate-grammar.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# Regenerate the vendored tree-sitter-swift parser tables from grammar.js, -# then refresh the human-readable node-types.yml companion file. -# -# Run this after editing -# unified/extractor/tree-sitter-swift/grammar.js so that: -# * src/parser.c, src/grammar.json, src/node-types.json (and the -# src/tree_sitter/*.h headers) reflect the current grammar; and -# * node-types.yml shows the same information in a form that's -# pleasant to review in PR diffs. -# -# Requirements: tree-sitter CLI on PATH, and a working cargo toolchain. -set -euo pipefail - -cd "$(dirname "$0")/.." -SWIFT_DIR="extractor/tree-sitter-swift" - -( - cd "$SWIFT_DIR" - tree-sitter generate -) - -# Build yeast's node_types_yaml binary and use it to convert the freshly -# generated src/node-types.json into the human-readable node-types.yml. -cargo run --release --quiet -p yeast --bin node_types_yaml -- \ - --from-json "$SWIFT_DIR/src/node-types.json" > "$SWIFT_DIR/node-types.yml" - -echo "Regenerated $SWIFT_DIR/{src/parser.c,src/grammar.json,src/node-types.json,node-types.yml}" diff --git a/unified/swift-syntax-rs/BUILD.bazel b/unified/swift-syntax-rs/BUILD.bazel index 5c2360d4deba..db451e5b7b9a 100644 --- a/unified/swift-syntax-rs/BUILD.bazel +++ b/unified/swift-syntax-rs/BUILD.bazel @@ -1,4 +1,6 @@ load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("//misc/bazel:pkg.bzl", "codeql_pkg_runfiles") load(":swift_runtime.bzl", "swift_runtime_libs") load(":xcode_transition.bzl", "xcode_transition_swift_library") @@ -27,6 +29,7 @@ xcode_transition_swift_library( module_name = "SwiftSyntaxFFI", target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, deps = [ + "@swift-syntax//:SwiftOperators", "@swift-syntax//:SwiftParser", "@swift-syntax//:SwiftSyntax", ], @@ -47,13 +50,19 @@ rust_library( ], ) +# The Swift front-end parser. We ship it like `//swift/extractor`: a small shell +# wrapper (`swift-syntax-parse`) sets `LD_LIBRARY_PATH`/`DYLD_LIBRARY_PATH` to its +# own directory and execs the real binary (`swift-syntax-parse.real`); the Swift +# runtime shared libraries are packaged alongside them. `parse.rs` resolves the +# wrapper as a sibling of the extractor executable. rust_binary( - name = "swift-syntax-parse", + name = "swift-syntax-parse.real", srcs = ["src/main.rs"], - # `rust_binary` doesn't copy the Swift runtime into runfiles the way - # `swift_binary` does. On Linux, ship the standalone toolchain's runtime; - # on macOS the OS provides it at `/usr/lib/swift` (rpath'd by - # `xcode_swift_toolchain`). + # Target name carries `.real` (invalid in a crate name), so set it explicitly. + crate_name = "swift_syntax_parse", + # On Linux, carry the toolchain's runtime shared libraries as runfiles so + # they get packaged next to the binary. On macOS the OS provides the Swift + # runtime, so nothing extra is bundled. data = select({ "@platforms//os:macos": [], "@platforms//os:linux": [":swift_runtime_libs"], @@ -63,6 +72,28 @@ rust_binary( deps = [":swift_syntax_rs"], ) +# `swift-syntax-parse` wrapper (see `swift-syntax-parse.sh`). Its runfiles carry +# the real binary and the runtime libraries; packaging flattens them into one +# directory. +sh_binary( + name = "swift-syntax-parse", + srcs = ["swift-syntax-parse.sh"], + data = [":swift-syntax-parse.real"], + target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, +) + +# Packaged form for the extractor pack: the wrapper (as `swift-syntax-parse`), +# the real binary, and the runtime libraries, flattened into one directory. +codeql_pkg_runfiles( + name = "swift-syntax-parse-pkg", + # The `.sh` source is shipped as `swift-syntax-parse` (the wrapper); drop the + # original filename. + excludes = ["swift-syntax-parse.sh"], + exes = [":swift-syntax-parse"], + target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS, + visibility = ["//unified:__pkg__"], +) + rust_test( name = "swift_syntax_rs_test", size = "small", diff --git a/unified/swift-syntax-rs/README.md b/unified/swift-syntax-rs/README.md index d43969199f91..7d15c6f2c23e 100644 --- a/unified/swift-syntax-rs/README.md +++ b/unified/swift-syntax-rs/README.md @@ -91,6 +91,37 @@ arrays (their collection nodes are elided), layout children such as comment rides along as `trailingTrivia` on the token it follows. Tokens without trivia (most of them) simply omit the `leadingTrivia`/`trailingTrivia` keys. +### Operator folding + +Swift's grammar does not encode operator precedence, so the parser represents an +expression like `a + b * c` as a flat `sequenceExpr` (an alternating list of +operands and operators). Before serializing, we fold these sequences into +precedence-correct `infixOperatorExpr` (and `ternaryExpr`) trees — so `1 + 2 * 3` +becomes `1 + (2 * 3)`. + +Folding needs to know each operator's precedence group, which comes from +declarations rather than the grammar. We resolve operators from two sources: + +- the **Swift standard library** operators (a built-in approximation), and +- operator / precedence-group declarations **in the file being parsed**. + +Operators defined anywhere else (for example, imported from another module) are +unknown, so their precedence cannot be determined. Rather than guess — which +would silently produce a wrongly-structured tree — each top-level sequence is +folded independently, and any sequence that uses an unknown operator is left as +a flat `sequenceExpr`. So `a <+> b` (with an undeclared `<+>`) stays flat, while +a neighbouring `1 + 2` in the same file still folds. Supporting operators from +other modules is future work. + +Folding is bottom-up, so a *grouped* subexpression still folds even when the +sequence enclosing it uses an unknown operator: in `a *** (b + c)` (with an +unknown `***`) the parenthesised `b + c` is its own sequence and folds, while +the outer `a *** …` stays flat. This only applies when the subexpression is +syntactically isolated (parentheses, call arguments, collection elements, …); +an unparenthesised `a *** b + c` is a single flat sequence whose structure +cannot be determined without knowing `***`'s precedence, so it is left flat in +its entirety. + ## Prerequisites The build does not depend on any particular version manager. You need: diff --git a/unified/swift-syntax-rs/build.rs b/unified/swift-syntax-rs/build.rs index c599cdf4e70b..6a58ddb4d8da 100644 --- a/unified/swift-syntax-rs/build.rs +++ b/unified/swift-syntax-rs/build.rs @@ -24,20 +24,34 @@ fn main() { println!("cargo:rerun-if-env-changed=SWIFTC"); // Build the Swift FFI package as a release dynamic library. + // + // Degrade gracefully when there is no runnable Swift toolchain. This crate + // is a workspace member, so a plain `cargo check`/`fmt`/`clippy` at the repo + // root runs this build script; if `swift build` cannot even be spawned we + // emit a warning and skip the link directives rather than panicking, so + // those Swift-free workflows keep working. Only `cargo build`/`cargo test` + // then fail — at link time, which is fair: they genuinely need Swift (and CI + // builds go through Bazel anyway). A Swift toolchain that *is* present but + // whose build fails is still surfaced as a hard error below. let mut command = Command::new(swift_bin()); command .args(["build", "-c", "release"]) .current_dir(&swift_dir); apply_bare_repository_workaround(&mut command); - let status = command.status().unwrap_or_else(|e| { - panic!( - "failed to run `{swift} build`: {e}\n\ - Install a Swift toolchain (see https://www.swift.org/install/, e.g. via \ - swiftly) and ensure `swift` is on PATH, or set the `SWIFT` environment \ - variable to the `swift` executable. The pinned version is in `.swift-version`.", - swift = swift_bin(), - ) - }); + let status = match command.status() { + Ok(status) => status, + Err(e) => { + println!( + "cargo:warning=skipping the Swift FFI build: failed to run `{swift} build`: {e}. \ + Install a Swift toolchain (see https://www.swift.org/install/, e.g. via swiftly) \ + and ensure `swift` is on PATH, or set the `SWIFT` environment variable, to build \ + or test this crate. `cargo check`/`fmt`/`clippy` work without it. The pinned \ + version is in `.swift-version`.", + swift = swift_bin(), + ); + return; + } + }; assert!(status.success(), "`swift build` failed"); // Link against the freshly built dynamic library. diff --git a/unified/swift-syntax-rs/src/lib.rs b/unified/swift-syntax-rs/src/lib.rs index 2a8fe0411af8..5f558d942fc8 100644 --- a/unified/swift-syntax-rs/src/lib.rs +++ b/unified/swift-syntax-rs/src/lib.rs @@ -132,4 +132,87 @@ mod tests { "comment trivia not captured: {json}" ); } + + #[test] + fn folds_standard_library_operators() { + // Standard-library operators are folded into a precedence-correct tree: + // the flat `sequenceExpr` becomes nested `infixOperatorExpr` nodes. + let json = parse_to_json("let x = 1 + 2 * 3").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "operators were not folded: {json}" + ); + assert!( + !json.contains("\"kind\":\"sequenceExpr\""), + "a foldable sequence was left flat: {json}" + ); + } + + #[test] + fn folds_file_defined_operators() { + // An operator declared in the same file (with a known precedence group) + // is folded, just like a standard-library one. + let json = parse_to_json("infix operator |>: AdditionPrecedence\nlet y = a |> b |> c") + .expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "file-defined operator was not folded: {json}" + ); + assert!( + !json.contains("\"kind\":\"sequenceExpr\""), + "a foldable sequence was left flat: {json}" + ); + } + + #[test] + fn leaves_unknown_operators_unfolded() { + // An operator that is neither in the standard library nor declared in + // this file (e.g. imported from another module) has unknown precedence, + // so its sequence is left flat rather than folded incorrectly. + let json = parse_to_json("let z = a <+> b").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"sequenceExpr\""), + "unknown-operator sequence should stay flat: {json}" + ); + assert!( + !json.contains("\"kind\":\"infixOperatorExpr\""), + "unknown operator should not be folded: {json}" + ); + } + + #[test] + fn folds_each_sequence_independently() { + // Folding is isolated per sequence: a statement using a known operator + // folds even when another statement uses an unknown one. One unfoldable + // expression does not suppress folding elsewhere. + let json = parse_to_json("let x = 1 + 2\nlet y = a <+> b").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "the known-operator statement should fold: {json}" + ); + assert!( + json.contains("\"kind\":\"sequenceExpr\""), + "the unknown-operator statement should stay flat: {json}" + ); + } + + #[test] + fn folds_grouped_subexpressions_under_unknown_operators() { + // A parenthesized (or otherwise bracketed) subexpression is its own + // sequence, so it folds independently even when the enclosing sequence + // uses an unknown operator. Here `***` is unknown (outer stays flat) but + // the grouped `b + c` still folds. Note this only works because the + // parentheses isolate `b + c`: in an unparenthesized `a *** b + c` the + // whole thing is one flat sequence whose structure can't be determined + // without `***`'s precedence, so it is left flat entirely. + let json = parse_to_json("let r = a *** (b + c)").expect("parsing should succeed"); + assert!( + json.contains("\"kind\":\"infixOperatorExpr\""), + "the grouped known-operator subexpression should fold: {json}" + ); + assert!( + json.contains("\"kind\":\"sequenceExpr\""), + "the enclosing unknown-operator sequence should stay flat: {json}" + ); + } } diff --git a/unified/swift-syntax-rs/swift-syntax-parse.sh b/unified/swift-syntax-rs/swift-syntax-parse.sh new file mode 100755 index 000000000000..811697c820c6 --- /dev/null +++ b/unified/swift-syntax-rs/swift-syntax-parse.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Wrapper that lets the shipped `swift-syntax-parse` find its Swift runtime +# libraries, which are packaged in the same directory as this script (and the +# real binary). Mirrors `swift/extractor/extractor.sh`. +if [[ "$(uname)" == Darwin ]]; then + export DYLD_LIBRARY_PATH=$(dirname "$0") +else + export LD_LIBRARY_PATH=$(dirname "$0") +fi + +exec -a "$0" "$0.real" "$@" diff --git a/unified/swift-syntax-rs/swift/Package.swift b/unified/swift-syntax-rs/swift/Package.swift index a58b7c1a479b..37fa5a1eed7b 100644 --- a/unified/swift-syntax-rs/swift/Package.swift +++ b/unified/swift-syntax-rs/swift/Package.swift @@ -29,6 +29,7 @@ let package = Package( dependencies: [ .product(name: "SwiftSyntax", package: "swift-syntax"), .product(name: "SwiftParser", package: "swift-syntax"), + .product(name: "SwiftOperators", package: "swift-syntax"), ] ) ] diff --git a/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift b/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift index 6305b1610d06..9471c2ea143d 100644 --- a/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift +++ b/unified/swift-syntax-rs/swift/Sources/SwiftSyntaxFFI/SwiftSyntaxFFI.swift @@ -1,4 +1,5 @@ import Foundation +import SwiftOperators import SwiftParser // `@_spi(RawSyntax)` exposes the `childName(_:)` helper that maps a child's @@ -151,6 +152,68 @@ private func serialize( return result } +/// Fold the flat operator sequences in `tree` into structured binary/ternary +/// expressions, using operator precedence. +/// +/// Swift's grammar does not encode operator precedence: an expression like +/// `a + b * c` is parsed as a flat `SequenceExpr` (a list of operands and +/// operators). Resolving it into a precedence-correct tree requires knowing the +/// operators' precedence groups, which live in declarations rather than the +/// grammar. We fold using two sources of operator definitions: +/// +/// * `OperatorTable.standardOperators` — the Swift standard library's +/// operators (a built-in approximation), and +/// * the operator / precedence-group declarations in *this* file +/// (via `addSourceFile`). +/// +/// Operators from anywhere else (e.g. imported from another module) are +/// unknown to us. Rather than guess their precedence — which would silently +/// produce an incorrectly-structured tree — we fold each top-level sequence +/// *independently* and leave any sequence containing an unknown operator as a +/// flat `SequenceExpr`. Downstream can treat such a sequence as unsupported. +/// This keeps folding correct for the operators we do know while isolating the +/// rest per sequence, so one exotic operator doesn't block folding elsewhere. +private func foldOperators(in tree: SourceFileSyntax) -> Syntax { + var operators = OperatorTable.standardOperators + // Register operators and precedence groups declared in this file. Swallow + // errors (e.g. a redeclaration of a standard operator): keep whatever we + // can and carry on. + operators.addSourceFile(tree, errorHandler: { _ in }) + return PerSequenceFolder(operators: operators).rewrite(tree) +} + +/// A `SyntaxRewriter` that folds each `SequenceExpr` on its own, leaving +/// sequences it cannot fold (because they use an operator we don't know) flat. +/// +/// This is deliberately more conservative than `OperatorTable.foldAll`, which +/// is all-or-nothing: with a throwing error handler a single unknown operator +/// aborts folding for the *entire* tree, while with a non-throwing handler +/// unknown operators are folded *arbitrarily* (left-associatively), silently +/// producing a wrong tree. Folding each sequence with a throwing handler and +/// catching the error gives us per-sequence isolation instead. +private final class PerSequenceFolder: SyntaxRewriter { + private let operators: OperatorTable + + init(operators: OperatorTable) { + self.operators = operators + super.init() + } + + override func visit(_ node: SequenceExprSyntax) -> ExprSyntax { + // Fold any nested sequences first (bottom-up), so that an unfoldable + // outer sequence still keeps its foldable inner sequences folded. + let inner = super.visit(node).as(SequenceExprSyntax.self)! + do { + // The default error handler throws on the first unknown operator or + // incomparable-precedence pair. + return try operators.foldSingle(inner) + } catch { + // Leave this sequence flat; it uses an operator we don't know. + return ExprSyntax(inner) + } + } +} + /// Parse the given NUL-terminated Swift source string and return a /// heap-allocated, NUL-terminated JSON representation of the syntax tree. /// @@ -161,8 +224,12 @@ public func ssr_parse_json(_ source: UnsafePointer?) -> UnsafeMutablePoin guard let source = source else { return nil } let code = String(cString: source) let tree = Parser.parse(source: code) + // Fold operator sequences before serializing. Source positions are + // preserved by folding (the same tokens, in the same places), so a + // converter built from the original tree maps the folded tree correctly. + let folded = foldOperators(in: tree) let converter = SourceLocationConverter(fileName: "", tree: tree) - let json = serialize(Syntax(tree), converter) + let json = serialize(folded, converter) guard let data = try? JSONSerialization.data(