From 06750dc733979dc5cfc2c58b1486c2996ec80a8d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:05:25 +0100 Subject: [PATCH] Add PHP extractor and initial queries --- .github/labeler.yml | 4 + .github/workflows/php.yml | 77 + .gitignore | 3 + Cargo.lock | 27 + Cargo.toml | 2 + MODULE.bazel | 1 + .../tree_sitter_extractors_deps/BUILD.bazel | 12 + .../BUILD.tree-sitter-php-0.23.11.bazel | 165 ++ .../tree_sitter_extractors_deps/defs.bzl | 49 + php/.gitignore | 13 + php/BUILD.bazel | 59 + php/codeql-extractor.yml | 32 + php/demo/index.php | 10 + php/downgrades/BUILD.bazel | 13 + php/extractor/BUILD.bazel | 19 + php/extractor/Cargo.toml | 21 + php/extractor/src/autobuilder.rs | 21 + php/extractor/src/extractor.rs | 154 ++ php/extractor/src/generator.rs | 26 + php/extractor/src/main.rs | 23 + php/ql/lib/BUILD.bazel | 13 + php/ql/lib/change-notes/2025-12-17-php-mvp.md | 4 + php/ql/lib/codeql-pack.lock.yml | 4 + php/ql/lib/codeql/Locations.qll | 37 + php/ql/lib/codeql/php/ast/Calls.qll | 84 + .../codeql/php/ast/internal/TreeSitter.qll | 2456 +++++++++++++++++ php/ql/lib/codeql/php/security/Sinks.qll | 12 + php/ql/lib/codeql/php/security/Sources.qll | 35 + php/ql/lib/codeql/php/security/Taint.qll | 43 + php/ql/lib/php.dbscheme | 1809 ++++++++++++ php/ql/lib/php.dbscheme.stats | 4 + php/ql/lib/qlpack.yml | 10 + .../src/Security/AssertWithStringArgument.ql | 20 + php/ql/src/Security/DangerousBuiltinCall.ql | 15 + .../Security/TaintedDangerousBuiltinCall.ql | 17 + php/ql/src/change-notes/2025-12-17-php-mvp.md | 4 + php/ql/src/codeql-pack.lock.yml | 4 + .../src/codeql-suites/php-code-scanning.qls | 4 + php/ql/src/qlpack.yml | 12 + php/ql/test/qlpack.yml | 8 + .../AssertWithStringArgument.expected | 2 + .../AssertWithStringArgument.php | 7 + .../AssertWithStringArgument.qlref | 1 + .../DangerousBuiltinCall.expected | 4 + .../DangerousBuiltinCall.php | 20 + .../DangerousBuiltinCall.qlref | 1 + .../TaintedDangerousBuiltinCall.expected | 7 + .../TaintedDangerousBuiltinCall.php | 29 + .../TaintedDangerousBuiltinCall.qlref | 1 + php/scripts/create-extractor-pack.sh | 43 + php/tools/BUILD.bazel | 11 + php/tools/autobuild.cmd | 5 + php/tools/autobuild.sh | 3 + php/tools/index-files.cmd | 9 + php/tools/index-files.sh | 9 + php/tools/qltest.cmd | 12 + php/tools/qltest.sh | 12 + 57 files changed, 5502 insertions(+) create mode 100644 .github/workflows/php.yml create mode 100644 misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-php-0.23.11.bazel create mode 100644 php/.gitignore create mode 100644 php/BUILD.bazel create mode 100644 php/codeql-extractor.yml create mode 100644 php/demo/index.php create mode 100644 php/downgrades/BUILD.bazel create mode 100644 php/extractor/BUILD.bazel create mode 100644 php/extractor/Cargo.toml create mode 100644 php/extractor/src/autobuilder.rs create mode 100644 php/extractor/src/extractor.rs create mode 100644 php/extractor/src/generator.rs create mode 100644 php/extractor/src/main.rs create mode 100644 php/ql/lib/BUILD.bazel create mode 100644 php/ql/lib/change-notes/2025-12-17-php-mvp.md create mode 100644 php/ql/lib/codeql-pack.lock.yml create mode 100644 php/ql/lib/codeql/Locations.qll create mode 100644 php/ql/lib/codeql/php/ast/Calls.qll create mode 100644 php/ql/lib/codeql/php/ast/internal/TreeSitter.qll create mode 100644 php/ql/lib/codeql/php/security/Sinks.qll create mode 100644 php/ql/lib/codeql/php/security/Sources.qll create mode 100644 php/ql/lib/codeql/php/security/Taint.qll create mode 100644 php/ql/lib/php.dbscheme create mode 100644 php/ql/lib/php.dbscheme.stats create mode 100644 php/ql/lib/qlpack.yml create mode 100644 php/ql/src/Security/AssertWithStringArgument.ql create mode 100644 php/ql/src/Security/DangerousBuiltinCall.ql create mode 100644 php/ql/src/Security/TaintedDangerousBuiltinCall.ql create mode 100644 php/ql/src/change-notes/2025-12-17-php-mvp.md create mode 100644 php/ql/src/codeql-pack.lock.yml create mode 100644 php/ql/src/codeql-suites/php-code-scanning.qls create mode 100644 php/ql/src/qlpack.yml create mode 100644 php/ql/test/qlpack.yml create mode 100644 php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.expected create mode 100644 php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.php create mode 100644 php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.qlref create mode 100644 php/ql/test/query-tests/Security/DangerousBuiltinCall/DangerousBuiltinCall.expected create mode 100644 php/ql/test/query-tests/Security/DangerousBuiltinCall/DangerousBuiltinCall.php create mode 100644 php/ql/test/query-tests/Security/DangerousBuiltinCall/DangerousBuiltinCall.qlref create mode 100644 php/ql/test/query-tests/Security/TaintedDangerousBuiltinCall/TaintedDangerousBuiltinCall.expected create mode 100644 php/ql/test/query-tests/Security/TaintedDangerousBuiltinCall/TaintedDangerousBuiltinCall.php create mode 100644 php/ql/test/query-tests/Security/TaintedDangerousBuiltinCall/TaintedDangerousBuiltinCall.qlref create mode 100755 php/scripts/create-extractor-pack.sh create mode 100644 php/tools/BUILD.bazel create mode 100644 php/tools/autobuild.cmd create mode 100755 php/tools/autobuild.sh create mode 100644 php/tools/index-files.cmd create mode 100755 php/tools/index-files.sh create mode 100644 php/tools/qltest.cmd create mode 100755 php/tools/qltest.sh diff --git a/.github/labeler.yml b/.github/labeler.yml index 65f820799716..948648136e58 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -26,6 +26,10 @@ Python: - python/**/* - change-notes/**/*python* +PHP: + - php/**/* + - change-notes/**/*php* + Ruby: - ruby/**/* - change-notes/**/*ruby* diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 000000000000..aadb326badcf --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,77 @@ +name: "PHP" + +on: + pull_request: + paths: + - "php/**" + - "misc/bazel/**" + - "misc/codegen/**" + - "shared/**" + - "*.bazel*" + - "MODULE.bazel" + - .github/workflows/php.yml + - .github/actions/** + - codeql-workspace.yml + - "!**/*.md" + - "!**/*.qhelp" + branches: + - main + - rc/* + - codeql-cli-* + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + +defaults: + run: + shell: bash + +jobs: + extractor: + runs-on: ubuntu-latest + defaults: + run: + working-directory: php/extractor + steps: + - uses: actions/checkout@v5 + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.88" + components: clippy,rustfmt + - name: Format + run: cargo fmt --check + - name: Compilation + run: cargo check + - name: Clippy + run: cargo clippy --no-deps -- -D warnings + + qltest: + if: github.repository_owner == 'github' + runs-on: ubuntu-latest + defaults: + run: + working-directory: php + steps: + - uses: actions/checkout@v5 + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.88" + components: clippy,rustfmt + - uses: ./.github/actions/fetch-codeql + - name: Build extractor pack + run: scripts/create-extractor-pack.sh + - name: Cache compilation cache + id: query-cache + uses: ./.github/actions/cache-query-compilation + with: + key: php-qltest + - name: Run QL tests + run: | + codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 4dbe45b8d28a..860cece01588 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,9 @@ # Avoid committing cached package components .codeql +# Local CodeQL CLI distributions (VS Code / local dev) +.codeql-cli/ + # Compiled class file *.class diff --git a/Cargo.lock b/Cargo.lock index b6456c841063..f29a6ee0600a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,6 +419,23 @@ dependencies = [ "zstd", ] +[[package]] +name = "codeql-extractor-php" +version = "0.1.0" +dependencies = [ + "clap", + "codeql-extractor", + "encoding", + "lazy_static", + "rayon", + "regex", + "serde_json", + "tracing", + "tracing-subscriber", + "tree-sitter", + "tree-sitter-php", +] + [[package]] name = "codeql-extractor-ruby" version = "0.1.0" @@ -2891,6 +2908,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" +[[package]] +name = "tree-sitter-php" +version = "0.23.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f066e94e9272cfe4f1dcb07a1c50c66097eca648f2d7233d299c8ae9ed8c130c" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "tree-sitter-ql" version = "0.23.1" diff --git a/Cargo.toml b/Cargo.toml index 58a755340b9c..8f516e31f940 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,11 @@ resolver = "2" members = [ "shared/tree-sitter-extractor", + "php/extractor", "ruby/extractor", "rust/extractor", "rust/extractor/macros", "rust/ast-generator", "rust/autobuild", ] + diff --git a/MODULE.bazel b/MODULE.bazel index 8ba6c2fcd8c8..89a044512fa2 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -147,6 +147,7 @@ use_repo( "vendor_ts__tree-sitter-0.25.9", "vendor_ts__tree-sitter-embedded-template-0.25.0", "vendor_ts__tree-sitter-json-0.24.8", + "vendor_ts__tree-sitter-php-0.23.11", "vendor_ts__tree-sitter-ql-0.23.1", "vendor_ts__tree-sitter-ruby-0.23.1", "vendor_ts__triomphe-0.1.14", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel index a5cfeccdcea8..01c3b78ada9c 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.bazel @@ -625,6 +625,18 @@ alias( tags = ["manual"], ) +alias( + name = "tree-sitter-php-0.23.11", + actual = "@vendor_ts__tree-sitter-php-0.23.11//:tree_sitter_php", + tags = ["manual"], +) + +alias( + name = "tree-sitter-php", + actual = "@vendor_ts__tree-sitter-php-0.23.11//:tree_sitter_php", + tags = ["manual"], +) + alias( name = "tree-sitter-ql-0.23.1", actual = "@vendor_ts__tree-sitter-ql-0.23.1//:tree_sitter_ql", diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-php-0.23.11.bazel b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-php-0.23.11.bazel new file mode 100644 index 000000000000..55bb836c7655 --- /dev/null +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/BUILD.tree-sitter-php-0.23.11.bazel @@ -0,0 +1,165 @@ +############################################################################### +# @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 = "tree_sitter_php", + 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 = "bindings/rust/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=tree-sitter-php", + "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: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.23.11", + deps = [ + "@vendor_ts__tree-sitter-language-0.1.5//:tree_sitter_language", + "@vendor_ts__tree-sitter-php-0.23.11//:build_script_build", + ], +) + +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_name = "build_script_build", + crate_root = "bindings/rust/build.rs", + data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + edition = "2021", + pkg_name = "tree-sitter-php", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=tree-sitter-php", + "manual", + "noclippy", + "norustfmt", + ], + version = "0.23.11", + visibility = ["//visibility:private"], + deps = [ + "@vendor_ts__cc-1.2.37//:cc", + ], +) + +alias( + name = "build_script_build", + actual = ":_bs", + tags = ["manual"], +) diff --git a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl index a56d266ab746..fddcf9ce90e4 100644 --- a/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl +++ b/misc/bazel/3rdparty/tree_sitter_extractors_deps/defs.bzl @@ -293,6 +293,20 @@ def aliases( ############################################################################### _NORMAL_DEPENDENCIES = { + "php/extractor": { + _COMMON_CONDITION: { + "clap": Label("@vendor_ts__clap-4.5.48//:clap"), + "encoding": Label("@vendor_ts__encoding-0.2.33//:encoding"), + "lazy_static": Label("@vendor_ts__lazy_static-1.5.0//:lazy_static"), + "rayon": Label("@vendor_ts__rayon-1.11.0//:rayon"), + "regex": Label("@vendor_ts__regex-1.11.3//:regex"), + "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.25.9//:tree_sitter"), + "tree-sitter-php": Label("@vendor_ts__tree-sitter-php-0.23.11//:tree_sitter_php"), + }, + }, "ruby/extractor": { _COMMON_CONDITION: { "clap": Label("@vendor_ts__clap-4.5.48//:clap"), @@ -388,6 +402,10 @@ _NORMAL_DEPENDENCIES = { } _NORMAL_ALIASES = { + "php/extractor": { + _COMMON_CONDITION: { + }, + }, "ruby/extractor": { _COMMON_CONDITION: { }, @@ -414,6 +432,8 @@ _NORMAL_ALIASES = { } _NORMAL_DEV_DEPENDENCIES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -434,6 +454,8 @@ _NORMAL_DEV_DEPENDENCIES = { } _NORMAL_DEV_ALIASES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -451,6 +473,8 @@ _NORMAL_DEV_ALIASES = { } _PROC_MACRO_DEPENDENCIES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -466,6 +490,8 @@ _PROC_MACRO_DEPENDENCIES = { } _PROC_MACRO_ALIASES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -481,6 +507,8 @@ _PROC_MACRO_ALIASES = { } _PROC_MACRO_DEV_DEPENDENCIES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -496,6 +524,8 @@ _PROC_MACRO_DEV_DEPENDENCIES = { } _PROC_MACRO_DEV_ALIASES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -513,6 +543,8 @@ _PROC_MACRO_DEV_ALIASES = { } _BUILD_DEPENDENCIES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -528,6 +560,8 @@ _BUILD_DEPENDENCIES = { } _BUILD_ALIASES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -543,6 +577,8 @@ _BUILD_ALIASES = { } _BUILD_PROC_MACRO_DEPENDENCIES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -558,6 +594,8 @@ _BUILD_PROC_MACRO_DEPENDENCIES = { } _BUILD_PROC_MACRO_ALIASES = { + "php/extractor": { + }, "ruby/extractor": { }, "rust/ast-generator": { @@ -3400,6 +3438,16 @@ def crate_repositories(): build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.tree-sitter-language-0.1.5.bazel"), ) + maybe( + http_archive, + name = "vendor_ts__tree-sitter-php-0.23.11", + sha256 = "f066e94e9272cfe4f1dcb07a1c50c66097eca648f2d7233d299c8ae9ed8c130c", + type = "tar.gz", + urls = ["https://static.crates.io/crates/tree-sitter-php/0.23.11/download"], + strip_prefix = "tree-sitter-php-0.23.11", + build_file = Label("//misc/bazel/3rdparty/tree_sitter_extractors_deps:BUILD.tree-sitter-php-0.23.11.bazel"), + ) + maybe( http_archive, name = "vendor_ts__tree-sitter-ql-0.23.1", @@ -4158,6 +4206,7 @@ def crate_repositories(): struct(repo = "vendor_ts__tracing-subscriber-0.3.20", is_dev_dep = False), struct(repo = "vendor_ts__tree-sitter-0.25.9", 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-php-0.23.11", 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), struct(repo = "vendor_ts__ungrammar-1.16.1", is_dev_dep = False), diff --git a/php/.gitignore b/php/.gitignore new file mode 100644 index 000000000000..67ce5f8629b6 --- /dev/null +++ b/php/.gitignore @@ -0,0 +1,13 @@ +extractor/target +.vscode/launch.json +.cache +ql/test/**/*.testproj +ql/test/**/*.actual +.codeql +demo-db/ + +# Local-only extractor binaries (used for ad-hoc validation). +tools/**/extractor + +# Generated extractor pack output. +extractor-pack/ diff --git a/php/BUILD.bazel b/php/BUILD.bazel new file mode 100644 index 000000000000..74c59cedf2a5 --- /dev/null +++ b/php/BUILD.bazel @@ -0,0 +1,59 @@ +load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup") +load("//misc/bazel:pkg.bzl", "codeql_pack", "codeql_pkg_files") + +package(default_visibility = ["//visibility:public"]) + +alias( + name = "dbscheme", + actual = "//php/ql/lib:dbscheme", +) + +alias( + name = "dbscheme-stats", + actual = "//php/ql/lib:dbscheme-stats", +) + +codeql_pkg_files( + name = "dbscheme-group", + srcs = [ + ":dbscheme", + ":dbscheme-stats", + ], + strip_prefix = None, +) + +pkg_filegroup( + name = "db-files", + srcs = [ + ":dbscheme-group", + "//php/downgrades", + ], +) + +codeql_pkg_files( + name = "codeql-extractor-yml", + srcs = [ + "codeql-extractor.yml", + "//:LICENSE", + ], + strip_prefix = None, +) + +codeql_pkg_files( + name = "extractor-arch", + exes = [ + "//php/extractor", + ], + prefix = "tools/{CODEQL_PLATFORM}", +) + +codeql_pack( + name = "php", + srcs = [ + ":codeql-extractor-yml", + ":dbscheme-group", + ":extractor-arch", + "//php/downgrades", + "//php/tools", + ], +) diff --git a/php/codeql-extractor.yml b/php/codeql-extractor.yml new file mode 100644 index 000000000000..2d8d63b556ee --- /dev/null +++ b/php/codeql-extractor.yml @@ -0,0 +1,32 @@ +name: "php" +display_name: "PHP" +version: 0.1.0 +column_kind: "utf8" +legacy_qltest_extraction: true +overlay_support_version: 20250626 +build_modes: + - none +default_queries: + - codeql/php-queries +github_api_languages: + - PHP +scc_languages: + - PHP +file_types: + - name: php + display_name: PHP files + extensions: + - .php +options: + trap: + title: Options pertaining to TRAP. + type: object + properties: + compression: + title: Controls compression for the TRAP files written by the extractor. + description: > + This option is only intended for use in debugging the extractor. Accepted + values are 'gzip' (the default, to write gzip-compressed TRAP) 'zstd' (to + write Zstandard-compressed TRAP) and 'none' (to write uncompressed TRAP). + type: string + pattern: "^(none|gzip|zstd)$" diff --git a/php/demo/index.php b/php/demo/index.php new file mode 100644 index 000000000000..bbd870ec61dd --- /dev/null +++ b/php/demo/index.php @@ -0,0 +1,10 @@ += 0.23.0" +tree-sitter-php = "0.23.1" +clap = { version = "4.5", features = ["derive"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } +rayon = "1.11.0" +regex = "1.11.3" +encoding = "0.2" +lazy_static = "1.5.0" +serde_json = "1.0.145" + +codeql-extractor = { path = "../../shared/tree-sitter-extractor" } diff --git a/php/extractor/src/autobuilder.rs b/php/extractor/src/autobuilder.rs new file mode 100644 index 000000000000..e523b259d619 --- /dev/null +++ b/php/extractor/src/autobuilder.rs @@ -0,0 +1,21 @@ +use std::env; +use std::path::PathBuf; + +use clap::Args; + +use codeql_extractor::autobuilder; + +#[derive(Args)] +// The autobuilder takes no command-line options, but this may change in the future. +pub struct Options {} + +pub fn run(_: Options) -> std::io::Result<()> { + let database = env::var("CODEQL_EXTRACTOR_PHP_WIP_DATABASE") + .expect("CODEQL_EXTRACTOR_PHP_WIP_DATABASE not set"); + + autobuilder::Autobuilder::new("php", PathBuf::from(database)) + .include_extensions(&[".php"]) + .exclude_globs(&["**/.git"]) + .size_limit("5m") + .run() +} diff --git a/php/extractor/src/extractor.rs b/php/extractor/src/extractor.rs new file mode 100644 index 000000000000..b1d1bb338b2c --- /dev/null +++ b/php/extractor/src/extractor.rs @@ -0,0 +1,154 @@ +use clap::Args; +use codeql_extractor::file_paths::PathTransformer; +use rayon::prelude::*; +use std::collections::HashSet; +use std::fs; +use std::io::BufRead; +use std::path::{Path, PathBuf}; +use tree_sitter::Language; + +use codeql_extractor::{diagnostics, extractor, file_paths, node_types, trap}; + +#[derive(Args)] +pub struct Options { + /// Sets a custom source achive folder + #[arg(long)] + source_archive_dir: String, + + /// Sets a custom trap folder + #[arg(long)] + output_dir: String, + + /// A text file containing the paths of the files to extract + #[arg(long)] + file_list: String, +} + +pub fn run(options: Options) -> std::io::Result<()> { + extractor::set_tracing_level("php"); + tracing::info!("Extraction started"); + + let diagnostics = diagnostics::DiagnosticLoggers::new("php"); + let mut main_thread_logger = diagnostics.logger(); + let num_threads = match codeql_extractor::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 + } + }; + drop(main_thread_logger); + + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .unwrap(); + + let trap_compression = + match trap::Compression::from_env("CODEQL_EXTRACTOR_PHP_OPTION_TRAP_COMPRESSION") { + Ok(x) => x, + Err(_) => trap::Compression::Gzip, + }; + + let src_archive_dir = file_paths::path_from_string(&options.source_archive_dir); + let trap_dir = file_paths::path_from_string(&options.output_dir); + let file_list = fs::File::open(file_paths::path_from_string(&options.file_list))?; + + let overlay_changed_files: Option> = get_overlay_changed_files(); + let path_transformer: Option = file_paths::load_path_transformer()?; + + let language: Language = tree_sitter_php::LANGUAGE_PHP.into(); + let schema = node_types::read_node_types_str("php", tree_sitter_php::PHP_NODE_TYPES)?; + + let lines: std::io::Result> = 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()?; + match &overlay_changed_files { + Some(changed_files) if !changed_files.contains(&path) => { + return Result::Ok(()); + } + _ => {} + } + + let src_archive_file = + file_paths::path_for(&src_archive_dir, &path, "", path_transformer.as_ref()); + + let source = std::fs::read(&path)?; + let mut trap_writer = trap::Writer::new(); + extractor::extract( + &language, + "php", + &schema, + &mut diagnostics_writer, + &mut trap_writer, + path_transformer.as_ref(), + &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, + path_transformer.as_ref(), + ) + }) + .expect("failed to extract files"); + + let path = PathBuf::from("extras"); + let mut trap_writer = trap::Writer::new(); + extractor::populate_empty_location(&mut trap_writer); + let res = write_trap( + &trap_dir, + path, + &trap_writer, + trap_compression, + path_transformer.as_ref(), + ); + + if let Ok(output_path) = std::env::var("CODEQL_EXTRACTOR_PHP_OVERLAY_BASE_METADATA_OUT") { + std::fs::write(output_path, b"")?; + } + + tracing::info!("Extraction complete"); + res +} + +fn get_overlay_changed_files() -> Option> { + let changed_files_file = std::env::var("CODEQL_EXTRACTOR_PHP_OVERLAY_CHANGED_FILES").ok()?; + let lines: std::io::Result> = + std::io::BufReader::new(std::fs::File::open(changed_files_file).ok()?) + .lines() + .collect(); + let lines = lines.ok()?; + Some(lines.into_iter().map(PathBuf::from).collect()) +} + +fn write_trap( + trap_dir: &Path, + path: PathBuf, + trap_writer: &trap::Writer, + compression: trap::Compression, + path_transformer: Option<&PathTransformer>, +) -> std::io::Result<()> { + let output_path = file_paths::path_for(trap_dir, &path, "trap.gz", path_transformer); + std::fs::create_dir_all(output_path.parent().unwrap())?; + trap_writer.write_to_file(&output_path, compression) +} diff --git a/php/extractor/src/generator.rs b/php/extractor/src/generator.rs new file mode 100644 index 000000000000..ba643a44f39f --- /dev/null +++ b/php/extractor/src/generator.rs @@ -0,0 +1,26 @@ +use clap::Args; +use std::path::PathBuf; + +use codeql_extractor::generator::{generate, language::Language}; + +#[derive(Args)] +pub struct Options { + /// Path of the generated dbscheme file + #[arg(long)] + dbscheme: PathBuf, + + /// Path of the generated QLL file + #[arg(long)] + library: PathBuf, +} + +pub fn run(options: Options) -> std::io::Result<()> { + codeql_extractor::extractor::set_tracing_level("php"); + + let languages = vec![Language { + name: "Php".to_owned(), + node_types: tree_sitter_php::PHP_NODE_TYPES, + }]; + + generate(languages, options.dbscheme, options.library) +} diff --git a/php/extractor/src/main.rs b/php/extractor/src/main.rs new file mode 100644 index 000000000000..e6721d4e2243 --- /dev/null +++ b/php/extractor/src/main.rs @@ -0,0 +1,23 @@ +use clap::Parser; + +mod autobuilder; +mod extractor; +mod generator; + +#[derive(Parser)] +#[command(author, version, about)] +enum Cli { + Extract(extractor::Options), + Generate(generator::Options), + Autobuild(autobuilder::Options), +} + +fn main() -> std::io::Result<()> { + let cli = Cli::parse(); + + match cli { + Cli::Extract(options) => extractor::run(options), + Cli::Generate(options) => generator::run(options), + Cli::Autobuild(options) => autobuilder::run(options), + } +} diff --git a/php/ql/lib/BUILD.bazel b/php/ql/lib/BUILD.bazel new file mode 100644 index 000000000000..3f7f1bfc8f92 --- /dev/null +++ b/php/ql/lib/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_pkg//pkg:mappings.bzl", "pkg_files") + +package(default_visibility = ["//php:__pkg__"]) + +pkg_files( + name = "dbscheme", + srcs = ["php.dbscheme"], +) + +pkg_files( + name = "dbscheme-stats", + srcs = ["php.dbscheme.stats"], +) diff --git a/php/ql/lib/change-notes/2025-12-17-php-mvp.md b/php/ql/lib/change-notes/2025-12-17-php-mvp.md new file mode 100644 index 000000000000..cdeadcfb087a --- /dev/null +++ b/php/ql/lib/change-notes/2025-12-17-php-mvp.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added an initial PHP library pack and database schema. diff --git a/php/ql/lib/codeql-pack.lock.yml b/php/ql/lib/codeql-pack.lock.yml new file mode 100644 index 000000000000..53004274575d --- /dev/null +++ b/php/ql/lib/codeql-pack.lock.yml @@ -0,0 +1,4 @@ +--- +lockVersion: 1.0.0 +dependencies: {} +compiled: false diff --git a/php/ql/lib/codeql/Locations.qll b/php/ql/lib/codeql/Locations.qll new file mode 100644 index 000000000000..b893fa43249e --- /dev/null +++ b/php/ql/lib/codeql/Locations.qll @@ -0,0 +1,37 @@ +/** Provides classes for working with locations. */ +overlay[local] +module; + +/** + * A location as given by a file, a start line, a start column, + * an end line, and an end column. + */ +class Location extends @location_default { + /** Gets the 1-based line number (inclusive) where this location starts. */ + int getStartLine() { locations_default(this, _, result, _, _, _) } + + /** Gets the 1-based column number (inclusive) where this location starts. */ + int getStartColumn() { locations_default(this, _, _, result, _, _) } + + /** Gets the 1-based line number (inclusive) where this location ends. */ + int getEndLine() { locations_default(this, _, _, _, result, _) } + + /** Gets the 1-based column number (inclusive) where this location ends. */ + int getEndColumn() { locations_default(this, _, _, _, _, result) } + + /** Gets a textual representation of this location. */ + bindingset[this] + pragma[inline_late] + string toString() { + exists(@file file, string path, int startLine, int startColumn, int endLine, int endColumn | + locations_default(this, file, startLine, startColumn, endLine, endColumn) and + files(file, path) and + result = path + "@" + startLine + ":" + startColumn + ":" + endLine + ":" + endColumn + ) + } +} + +/** An entity representing an empty location. */ +class EmptyLocation extends Location { + EmptyLocation() { empty_location(this) } +} diff --git a/php/ql/lib/codeql/php/ast/Calls.qll b/php/ql/lib/codeql/php/ast/Calls.qll new file mode 100644 index 000000000000..0c0a33ea8f8d --- /dev/null +++ b/php/ql/lib/codeql/php/ast/Calls.qll @@ -0,0 +1,84 @@ +import codeql.php.ast.internal.TreeSitter + +/** A PHP call expression (function call, method call, static call). */ +class Call extends Php::AstNode { + Call() { + this instanceof Php::FunctionCallExpression or + this instanceof Php::MemberCallExpression or + this instanceof Php::NullsafeMemberCallExpression or + this instanceof Php::ScopedCallExpression + } + + /** Gets the syntactic callee node. */ + Php::AstNode getCallee() { + result = this.(Php::FunctionCallExpression).getFunction() or + result = this.(Php::MemberCallExpression).getName() or + result = this.(Php::NullsafeMemberCallExpression).getName() or + result = this.(Php::ScopedCallExpression).getName() + } + + /** Gets the argument list node. */ + Php::Arguments getArguments() { + result = this.(Php::FunctionCallExpression).getArguments() or + result = this.(Php::MemberCallExpression).getArguments() or + result = this.(Php::NullsafeMemberCallExpression).getArguments() or + result = this.(Php::ScopedCallExpression).getArguments() + } + + /** + * Gets the statically-known name of the callee, where available. + * + * This intentionally returns the unqualified final name segment. + */ + string getCalleeName() { + exists(Php::AstNode callee | callee = this.getCallee() | + callee instanceof Php::Name and result = callee.(Php::Name).getValue() or + callee instanceof Php::QualifiedName and + result = callee.(Php::QualifiedName).getChild().getValue() + ) + } + + /** Gets an argument node of this call. */ + Php::Argument getAnArgument() { + result = this.getArguments().getAFieldOrChild().(Php::Argument) + } + + /** Gets the `i`th argument of this call (0-based), skipping placeholders. */ + Php::Argument getArgument(int i) { + exists(Php::Argument arg | + arg = this.getAnArgument() and + i = count(Php::Argument prev | + prev = this.getAnArgument() and prev.getParentIndex() < arg.getParentIndex() + ) and + result = arg + ) + } + + /** Gets an argument expression of this call. */ + Php::Expression getAnArgumentExpr() { + result = this.getAnArgument().getChild().(Php::Expression) + } + + /** Gets the expression of the `i`th argument of this call (0-based). */ + Php::Expression getArgumentExpr(int i) { + result = this.getArgument(i).getChild().(Php::Expression) + } +} + +/** A plain function call, e.g. `f(...)` or `\f(...)`. */ +class FunctionCall extends Call { + FunctionCall() { this instanceof Php::FunctionCallExpression } +} + +/** An instance method call, e.g. `$o->m(...)` or `$o?->m(...)`. */ +class MemberCall extends Call { + MemberCall() { + this instanceof Php::MemberCallExpression or + this instanceof Php::NullsafeMemberCallExpression + } +} + +/** A scoped (static) call, e.g. `C::m(...)`. */ +class ScopedCall extends Call { + ScopedCall() { this instanceof Php::ScopedCallExpression } +} diff --git a/php/ql/lib/codeql/php/ast/internal/TreeSitter.qll b/php/ql/lib/codeql/php/ast/internal/TreeSitter.qll new file mode 100644 index 000000000000..a1fde259e052 --- /dev/null +++ b/php/ql/lib/codeql/php/ast/internal/TreeSitter.qll @@ -0,0 +1,2456 @@ +/** + * CodeQL library for Php + * Automatically generated from the tree-sitter grammar; do not edit + */ + +import codeql.Locations as L + +/** Holds if the database is an overlay. */ +overlay[local] +private predicate isOverlay() { databaseMetadata("isOverlay", "true") } + +/** Holds if `loc` is in the `file` and is part of the overlay base database. */ +overlay[local] +private predicate discardableLocation(@file file, @location_default loc) { + not isOverlay() and locations_default(loc, file, _, _, _, _) +} + +/** Holds if `loc` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */ +overlay[discard_entity] +private predicate discardLocation(@location_default loc) { + exists(@file file, string path | files(file, path) | + discardableLocation(file, loc) and overlayChangedFiles(path) + ) +} + +overlay[local] +module Php { + /** The base class for all AST nodes */ + class AstNode extends @php_ast_node { + /** Gets a string representation of this element. */ + string toString() { result = this.getAPrimaryQlClass() } + + /** Gets the location of this element. */ + final L::Location getLocation() { php_ast_node_location(this, result) } + + /** Gets the parent of this element. */ + final AstNode getParent() { php_ast_node_parent(this, result, _) } + + /** Gets the index of this node among the children of its parent. */ + final int getParentIndex() { php_ast_node_parent(this, _, result) } + + /** Gets a field or child node of this node. */ + AstNode getAFieldOrChild() { none() } + + /** Gets the name of the primary QL class for this element. */ + string getAPrimaryQlClass() { result = "???" } + + /** Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */ + string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } + } + + /** A token. */ + class Token extends @php_token, AstNode { + /** Gets the value of this token. */ + final string getValue() { php_tokeninfo(this, _, result) } + + /** Gets a string representation of this element. */ + final override string toString() { result = this.getValue() } + + /** Gets the name of the primary QL class for this element. */ + override string getAPrimaryQlClass() { result = "Token" } + } + + /** A reserved word. */ + class ReservedWord extends @php_reserved_word, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReservedWord" } + } + + /** Gets the file containing the given `node`. */ + private @file getNodeFile(@php_ast_node node) { + exists(@location_default loc | php_ast_node_location(node, loc) | + locations_default(loc, result, _, _, _, _) + ) + } + + /** Holds if `node` is in the `file` and is part of the overlay base database. */ + private predicate discardableAstNode(@file file, @php_ast_node node) { + not isOverlay() and file = getNodeFile(node) + } + + /** Holds if `node` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */ + overlay[discard_entity] + private predicate discardAstNode(@php_ast_node node) { + exists(@file file, string path | files(file, path) | + discardableAstNode(file, node) and overlayChangedFiles(path) + ) + } + + /** A class representing `abstract_modifier` tokens. */ + class AbstractModifier extends @php_token_abstract_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AbstractModifier" } + } + + /** A class representing `anonymous_class` nodes. */ + class AnonymousClass extends @php_anonymous_class, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AnonymousClass" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_anonymous_class_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final DeclarationList getBody() { php_anonymous_class_def(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_anonymous_class_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_anonymous_class_attributes(this, result) or + php_anonymous_class_def(this, result) or + php_anonymous_class_child(this, _, result) + } + } + + /** A class representing `anonymous_function` nodes. */ + class AnonymousFunction extends @php_anonymous_function, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AnonymousFunction" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_anonymous_function_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final CompoundStatement getBody() { php_anonymous_function_def(this, result, _) } + + /** Gets the node corresponding to the field `parameters`. */ + final FormalParameters getParameters() { php_anonymous_function_def(this, _, result) } + + /** Gets the node corresponding to the field `reference_modifier`. */ + final ReferenceModifier getReferenceModifier() { + php_anonymous_function_reference_modifier(this, result) + } + + /** Gets the node corresponding to the field `return_type`. */ + final AstNode getReturnType() { php_anonymous_function_return_type(this, result) } + + /** Gets the node corresponding to the field `static_modifier`. */ + final StaticModifier getStaticModifier() { + php_anonymous_function_static_modifier(this, result) + } + + /** Gets the child of this node. */ + final AnonymousFunctionUseClause getChild() { php_anonymous_function_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_anonymous_function_attributes(this, result) or + php_anonymous_function_def(this, result, _) or + php_anonymous_function_def(this, _, result) or + php_anonymous_function_reference_modifier(this, result) or + php_anonymous_function_return_type(this, result) or + php_anonymous_function_static_modifier(this, result) or + php_anonymous_function_child(this, result) + } + } + + /** A class representing `anonymous_function_use_clause` nodes. */ + class AnonymousFunctionUseClause extends @php_anonymous_function_use_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AnonymousFunctionUseClause" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_anonymous_function_use_clause_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_anonymous_function_use_clause_child(this, _, result) + } + } + + /** A class representing `argument` nodes. */ + class Argument extends @php_argument, 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 `name`. */ + final Name getName() { php_argument_name(this, result) } + + /** Gets the node corresponding to the field `reference_modifier`. */ + final ReferenceModifier getReferenceModifier() { php_argument_reference_modifier(this, result) } + + /** Gets the child of this node. */ + final AstNode getChild() { php_argument_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_argument_name(this, result) or + php_argument_reference_modifier(this, result) or + php_argument_def(this, result) + } + } + + /** A class representing `arguments` nodes. */ + class Arguments extends @php_arguments, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Arguments" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_arguments_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_arguments_child(this, _, result) } + } + + /** A class representing `array_creation_expression` nodes. */ + class ArrayCreationExpression extends @php_array_creation_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ArrayCreationExpression" } + + /** Gets the `i`th child of this node. */ + final ArrayElementInitializer getChild(int i) { + php_array_creation_expression_child(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_array_creation_expression_child(this, _, result) + } + } + + /** A class representing `array_element_initializer` nodes. */ + class ArrayElementInitializer extends @php_array_element_initializer, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ArrayElementInitializer" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_array_element_initializer_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_array_element_initializer_child(this, _, result) + } + } + + /** A class representing `arrow_function` nodes. */ + class ArrowFunction extends @php_arrow_function, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ArrowFunction" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_arrow_function_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final Expression getBody() { php_arrow_function_def(this, result, _) } + + /** Gets the node corresponding to the field `parameters`. */ + final FormalParameters getParameters() { php_arrow_function_def(this, _, result) } + + /** Gets the node corresponding to the field `reference_modifier`. */ + final ReferenceModifier getReferenceModifier() { + php_arrow_function_reference_modifier(this, result) + } + + /** Gets the node corresponding to the field `return_type`. */ + final AstNode getReturnType() { php_arrow_function_return_type(this, result) } + + /** Gets the node corresponding to the field `static_modifier`. */ + final StaticModifier getStaticModifier() { php_arrow_function_static_modifier(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_arrow_function_attributes(this, result) or + php_arrow_function_def(this, result, _) or + php_arrow_function_def(this, _, result) or + php_arrow_function_reference_modifier(this, result) or + php_arrow_function_return_type(this, result) or + php_arrow_function_static_modifier(this, result) + } + } + + /** A class representing `assignment_expression` nodes. */ + class AssignmentExpression extends @php_assignment_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AssignmentExpression" } + + /** Gets the node corresponding to the field `left`. */ + final AstNode getLeft() { php_assignment_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `right`. */ + final Expression getRight() { php_assignment_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_assignment_expression_def(this, result, _) or + php_assignment_expression_def(this, _, result) + } + } + + /** A class representing `attribute` nodes. */ + class Attribute extends @php_attribute, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Attribute" } + + /** Gets the node corresponding to the field `parameters`. */ + final Arguments getParameters() { php_attribute_parameters(this, result) } + + /** Gets the child of this node. */ + final AstNode getChild() { php_attribute_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_attribute_parameters(this, result) or php_attribute_def(this, result) + } + } + + /** A class representing `attribute_group` nodes. */ + class AttributeGroup extends @php_attribute_group, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AttributeGroup" } + + /** Gets the `i`th child of this node. */ + final Attribute getChild(int i) { php_attribute_group_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_attribute_group_child(this, _, result) } + } + + /** A class representing `attribute_list` nodes. */ + class AttributeList extends @php_attribute_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AttributeList" } + + /** Gets the `i`th child of this node. */ + final AttributeGroup getChild(int i) { php_attribute_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_attribute_list_child(this, _, result) } + } + + /** A class representing `augmented_assignment_expression` nodes. */ + class AugmentedAssignmentExpression extends @php_augmented_assignment_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "AugmentedAssignmentExpression" } + + /** Gets the node corresponding to the field `left`. */ + final AstNode getLeft() { php_augmented_assignment_expression_def(this, result, _, _) } + + /** Gets the node corresponding to the field `operator`. */ + final string getOperator() { + exists(int value | php_augmented_assignment_expression_def(this, _, value, _) | + result = "%=" and value = 0 + or + result = "&=" and value = 1 + or + result = "**=" and value = 2 + or + result = "*=" and value = 3 + or + result = "+=" and value = 4 + or + result = "-=" and value = 5 + or + result = ".=" and value = 6 + or + result = "/=" and value = 7 + or + result = "<<=" and value = 8 + or + result = ">>=" and value = 9 + or + result = "??=" and value = 10 + or + result = "^=" and value = 11 + or + result = "|=" and value = 12 + ) + } + + /** Gets the node corresponding to the field `right`. */ + final Expression getRight() { php_augmented_assignment_expression_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_augmented_assignment_expression_def(this, result, _, _) or + php_augmented_assignment_expression_def(this, _, _, result) + } + } + + /** A class representing `base_clause` nodes. */ + class BaseClause extends @php_base_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BaseClause" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_base_clause_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_base_clause_child(this, _, result) } + } + + /** A class representing `binary_expression` nodes. */ + class BinaryExpression extends @php_binary_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BinaryExpression" } + + /** Gets the node corresponding to the field `left`. */ + final Expression getLeft() { php_binary_expression_def(this, result, _, _) } + + /** Gets the node corresponding to the field `operator`. */ + final string getOperator() { + exists(int value | php_binary_expression_def(this, _, value, _) | + result = "!=" and value = 0 + or + result = "!==" and value = 1 + or + result = "%" and value = 2 + or + result = "&" and value = 3 + or + result = "&&" and value = 4 + or + result = "*" and value = 5 + or + result = "**" and value = 6 + or + result = "+" and value = 7 + or + result = "-" and value = 8 + or + result = "." and value = 9 + or + result = "/" and value = 10 + or + result = "<" and value = 11 + or + result = "<<" and value = 12 + or + result = "<=" and value = 13 + or + result = "<=>" and value = 14 + or + result = "<>" and value = 15 + or + result = "==" and value = 16 + or + result = "===" and value = 17 + or + result = ">" and value = 18 + or + result = ">=" and value = 19 + or + result = ">>" and value = 20 + or + result = "??" and value = 21 + or + result = "^" and value = 22 + or + result = "and" and value = 23 + or + result = "instanceof" and value = 24 + or + result = "or" and value = 25 + or + result = "xor" and value = 26 + or + result = "|" and value = 27 + or + result = "||" and value = 28 + ) + } + + /** Gets the node corresponding to the field `right`. */ + final AstNode getRight() { php_binary_expression_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_binary_expression_def(this, result, _, _) or php_binary_expression_def(this, _, _, result) + } + } + + /** A class representing `boolean` tokens. */ + class Boolean extends @php_token_boolean, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Boolean" } + } + + /** A class representing `bottom_type` tokens. */ + class BottomType extends @php_token_bottom_type, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BottomType" } + } + + /** A class representing `break_statement` nodes. */ + class BreakStatement extends @php_break_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BreakStatement" } + + /** Gets the child of this node. */ + final Expression getChild() { php_break_statement_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_break_statement_child(this, result) } + } + + /** A class representing `by_ref` nodes. */ + class ByRef extends @php_by_ref, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ByRef" } + + /** Gets the child of this node. */ + final AstNode getChild() { php_by_ref_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_by_ref_def(this, result) } + } + + /** A class representing `case_statement` nodes. */ + class CaseStatement extends @php_case_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "CaseStatement" } + + /** Gets the node corresponding to the field `value`. */ + final Expression getValue() { php_case_statement_def(this, result) } + + /** Gets the `i`th child of this node. */ + final Statement getChild(int i) { php_case_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_case_statement_def(this, result) or php_case_statement_child(this, _, result) + } + } + + /** A class representing `cast_expression` nodes. */ + class CastExpression extends @php_cast_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "CastExpression" } + + /** Gets the node corresponding to the field `type`. */ + final CastType getType() { php_cast_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `value`. */ + final AstNode getValue() { php_cast_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_cast_expression_def(this, result, _) or php_cast_expression_def(this, _, result) + } + } + + /** A class representing `cast_type` tokens. */ + class CastType extends @php_token_cast_type, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "CastType" } + } + + /** A class representing `catch_clause` nodes. */ + class CatchClause extends @php_catch_clause, 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 CompoundStatement getBody() { php_catch_clause_def(this, result, _) } + + /** Gets the node corresponding to the field `name`. */ + final VariableName getName() { php_catch_clause_name(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final TypeList getType() { php_catch_clause_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_catch_clause_def(this, result, _) or + php_catch_clause_name(this, result) or + php_catch_clause_def(this, _, result) + } + } + + /** A class representing `class_constant_access_expression` nodes. */ + class ClassConstantAccessExpression extends @php_class_constant_access_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ClassConstantAccessExpression" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_class_constant_access_expression_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_class_constant_access_expression_child(this, _, result) + } + } + + /** A class representing `class_declaration` nodes. */ + class ClassDeclaration extends @php_class_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ClassDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_class_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final DeclarationList getBody() { php_class_declaration_def(this, result, _) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_class_declaration_def(this, _, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_class_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_class_declaration_attributes(this, result) or + php_class_declaration_def(this, result, _) or + php_class_declaration_def(this, _, result) or + php_class_declaration_child(this, _, result) + } + } + + /** A class representing `class_interface_clause` nodes. */ + class ClassInterfaceClause extends @php_class_interface_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ClassInterfaceClause" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_class_interface_clause_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_class_interface_clause_child(this, _, result) } + } + + /** A class representing `clone_expression` nodes. */ + class CloneExpression extends @php_clone_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "CloneExpression" } + + /** Gets the child of this node. */ + final PrimaryExpression getChild() { php_clone_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_clone_expression_def(this, result) } + } + + /** A class representing `colon_block` nodes. */ + class ColonBlock extends @php_colon_block, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ColonBlock" } + + /** Gets the `i`th child of this node. */ + final Statement getChild(int i) { php_colon_block_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_colon_block_child(this, _, result) } + } + + /** A class representing `comment` tokens. */ + class Comment extends @php_token_comment, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Comment" } + } + + /** A class representing `compound_statement` nodes. */ + class CompoundStatement extends @php_compound_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "CompoundStatement" } + + /** Gets the `i`th child of this node. */ + final Statement getChild(int i) { php_compound_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_compound_statement_child(this, _, result) } + } + + /** A class representing `conditional_expression` nodes. */ + class ConditionalExpression extends @php_conditional_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConditionalExpression" } + + /** Gets the node corresponding to the field `alternative`. */ + final Expression getAlternative() { php_conditional_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `body`. */ + final Expression getBody() { php_conditional_expression_body(this, result) } + + /** Gets the node corresponding to the field `condition`. */ + final Expression getCondition() { php_conditional_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_conditional_expression_def(this, result, _) or + php_conditional_expression_body(this, result) or + php_conditional_expression_def(this, _, result) + } + } + + /** A class representing `const_declaration` nodes. */ + class ConstDeclaration extends @php_const_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConstDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_const_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final Type getType() { php_const_declaration_type(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_const_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_const_declaration_attributes(this, result) or + php_const_declaration_type(this, result) or + php_const_declaration_child(this, _, result) + } + } + + /** A class representing `const_element` nodes. */ + class ConstElement extends @php_const_element, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ConstElement" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_const_element_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_const_element_child(this, _, result) } + } + + /** A class representing `continue_statement` nodes. */ + class ContinueStatement extends @php_continue_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ContinueStatement" } + + /** Gets the child of this node. */ + final Expression getChild() { php_continue_statement_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_continue_statement_child(this, result) } + } + + /** A class representing `declaration_list` nodes. */ + class DeclarationList extends @php_declaration_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DeclarationList" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_declaration_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_declaration_list_child(this, _, result) } + } + + /** A class representing `declare_directive` nodes. */ + class DeclareDirective extends @php_declare_directive, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DeclareDirective" } + + /** Gets the child of this node. */ + final Literal getChild() { php_declare_directive_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_declare_directive_def(this, result) } + } + + /** A class representing `declare_statement` nodes. */ + class DeclareStatement extends @php_declare_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DeclareStatement" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_declare_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_declare_statement_child(this, _, result) } + } + + /** A class representing `default_statement` nodes. */ + class DefaultStatement extends @php_default_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DefaultStatement" } + + /** Gets the `i`th child of this node. */ + final Statement getChild(int i) { php_default_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_default_statement_child(this, _, result) } + } + + /** A class representing `disjunctive_normal_form_type` nodes. */ + class DisjunctiveNormalFormType extends @php_disjunctive_normal_form_type, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DisjunctiveNormalFormType" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_disjunctive_normal_form_type_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_disjunctive_normal_form_type_child(this, _, result) + } + } + + /** A class representing `do_statement` nodes. */ + class DoStatement extends @php_do_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DoStatement" } + + /** Gets the node corresponding to the field `body`. */ + final Statement getBody() { php_do_statement_def(this, result, _) } + + /** Gets the node corresponding to the field `condition`. */ + final ParenthesizedExpression getCondition() { php_do_statement_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_do_statement_def(this, result, _) or php_do_statement_def(this, _, result) + } + } + + /** A class representing `dynamic_variable_name` nodes. */ + class DynamicVariableName extends @php_dynamic_variable_name, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "DynamicVariableName" } + + /** Gets the child of this node. */ + final AstNode getChild() { php_dynamic_variable_name_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_dynamic_variable_name_def(this, result) } + } + + /** A class representing `echo_statement` nodes. */ + class EchoStatement extends @php_echo_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EchoStatement" } + + /** Gets the child of this node. */ + final AstNode getChild() { php_echo_statement_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_echo_statement_def(this, result) } + } + + /** A class representing `else_clause` nodes. */ + class ElseClause extends @php_else_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ElseClause" } + + /** Gets the node corresponding to the field `body`. */ + final AstNode getBody() { php_else_clause_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_else_clause_def(this, result) } + } + + /** A class representing `else_if_clause` nodes. */ + class ElseIfClause extends @php_else_if_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ElseIfClause" } + + /** Gets the node corresponding to the field `body`. */ + final AstNode getBody() { php_else_if_clause_def(this, result, _) } + + /** Gets the node corresponding to the field `condition`. */ + final ParenthesizedExpression getCondition() { php_else_if_clause_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_else_if_clause_def(this, result, _) or php_else_if_clause_def(this, _, result) + } + } + + /** A class representing `empty_statement` tokens. */ + class EmptyStatement extends @php_token_empty_statement, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EmptyStatement" } + } + + /** A class representing `encapsed_string` nodes. */ + class EncapsedString extends @php_encapsed_string, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EncapsedString" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_encapsed_string_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_encapsed_string_child(this, _, result) } + } + + /** A class representing `enum_case` nodes. */ + class EnumCase extends @php_enum_case, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EnumCase" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_enum_case_attributes(this, result) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_enum_case_def(this, result) } + + /** Gets the node corresponding to the field `value`. */ + final Expression getValue() { php_enum_case_value(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_enum_case_attributes(this, result) or + php_enum_case_def(this, result) or + php_enum_case_value(this, result) + } + } + + /** A class representing `enum_declaration` nodes. */ + class EnumDeclaration extends @php_enum_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EnumDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_enum_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final EnumDeclarationList getBody() { php_enum_declaration_def(this, result, _) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_enum_declaration_def(this, _, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_enum_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_enum_declaration_attributes(this, result) or + php_enum_declaration_def(this, result, _) or + php_enum_declaration_def(this, _, result) or + php_enum_declaration_child(this, _, result) + } + } + + /** A class representing `enum_declaration_list` nodes. */ + class EnumDeclarationList extends @php_enum_declaration_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EnumDeclarationList" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_enum_declaration_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_enum_declaration_list_child(this, _, result) } + } + + /** A class representing `error_suppression_expression` nodes. */ + class ErrorSuppressionExpression extends @php_error_suppression_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ErrorSuppressionExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_error_suppression_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_error_suppression_expression_def(this, result) } + } + + /** A class representing `escape_sequence` tokens. */ + class EscapeSequence extends @php_token_escape_sequence, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EscapeSequence" } + } + + /** A class representing `exit_statement` nodes. */ + class ExitStatement extends @php_exit_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ExitStatement" } + + /** Gets the child of this node. */ + final Expression getChild() { php_exit_statement_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_exit_statement_child(this, result) } + } + + class Expression extends @php_expression, AstNode { } + + /** A class representing `expression_statement` nodes. */ + class ExpressionStatement extends @php_expression_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ExpressionStatement" } + + /** Gets the child of this node. */ + final Expression getChild() { php_expression_statement_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_expression_statement_def(this, result) } + } + + /** A class representing `final_modifier` tokens. */ + class FinalModifier extends @php_token_final_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FinalModifier" } + } + + /** A class representing `finally_clause` nodes. */ + class FinallyClause extends @php_finally_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FinallyClause" } + + /** Gets the node corresponding to the field `body`. */ + final CompoundStatement getBody() { php_finally_clause_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_finally_clause_def(this, result) } + } + + /** A class representing `float` tokens. */ + class Float extends @php_token_float, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Float" } + } + + /** A class representing `for_statement` nodes. */ + class ForStatement extends @php_for_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ForStatement" } + + /** Gets the node corresponding to the field `body`. */ + final Statement getBody(int i) { php_for_statement_body(this, i, result) } + + /** Gets the node corresponding to the field `condition`. */ + final AstNode getCondition() { php_for_statement_condition(this, result) } + + /** Gets the node corresponding to the field `initialize`. */ + final AstNode getInitialize() { php_for_statement_initialize(this, result) } + + /** Gets the node corresponding to the field `update`. */ + final AstNode getUpdate() { php_for_statement_update(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_for_statement_body(this, _, result) or + php_for_statement_condition(this, result) or + php_for_statement_initialize(this, result) or + php_for_statement_update(this, result) + } + } + + /** A class representing `foreach_statement` nodes. */ + class ForeachStatement extends @php_foreach_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ForeachStatement" } + + /** Gets the node corresponding to the field `body`. */ + final AstNode getBody() { php_foreach_statement_body(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_foreach_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_foreach_statement_body(this, result) or php_foreach_statement_child(this, _, result) + } + } + + /** A class representing `formal_parameters` nodes. */ + class FormalParameters extends @php_formal_parameters, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FormalParameters" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_formal_parameters_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_formal_parameters_child(this, _, result) } + } + + /** A class representing `function_call_expression` nodes. */ + class FunctionCallExpression extends @php_function_call_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FunctionCallExpression" } + + /** Gets the node corresponding to the field `arguments`. */ + final Arguments getArguments() { php_function_call_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `function`. */ + final AstNode getFunction() { php_function_call_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_function_call_expression_def(this, result, _) or + php_function_call_expression_def(this, _, result) + } + } + + /** A class representing `function_definition` nodes. */ + class FunctionDefinition extends @php_function_definition, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FunctionDefinition" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_function_definition_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final CompoundStatement getBody() { php_function_definition_def(this, result, _, _) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_function_definition_def(this, _, result, _) } + + /** Gets the node corresponding to the field `parameters`. */ + final FormalParameters getParameters() { php_function_definition_def(this, _, _, result) } + + /** Gets the node corresponding to the field `return_type`. */ + final AstNode getReturnType() { php_function_definition_return_type(this, result) } + + /** Gets the child of this node. */ + final ReferenceModifier getChild() { php_function_definition_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_function_definition_attributes(this, result) or + php_function_definition_def(this, result, _, _) or + php_function_definition_def(this, _, result, _) or + php_function_definition_def(this, _, _, result) or + php_function_definition_return_type(this, result) or + php_function_definition_child(this, result) + } + } + + /** A class representing `function_static_declaration` nodes. */ + class FunctionStaticDeclaration extends @php_function_static_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FunctionStaticDeclaration" } + + /** Gets the `i`th child of this node. */ + final StaticVariableDeclaration getChild(int i) { + php_function_static_declaration_child(this, i, result) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_function_static_declaration_child(this, _, result) + } + } + + /** A class representing `global_declaration` nodes. */ + class GlobalDeclaration extends @php_global_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "GlobalDeclaration" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_global_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_global_declaration_child(this, _, result) } + } + + /** A class representing `goto_statement` nodes. */ + class GotoStatement extends @php_goto_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "GotoStatement" } + + /** Gets the child of this node. */ + final Name getChild() { php_goto_statement_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_goto_statement_def(this, result) } + } + + /** A class representing `heredoc` nodes. */ + class Heredoc extends @php_heredoc, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Heredoc" } + + /** Gets the node corresponding to the field `end_tag`. */ + final HeredocEnd getEndTag() { php_heredoc_def(this, result, _) } + + /** Gets the node corresponding to the field `identifier`. */ + final HeredocStart getIdentifier() { php_heredoc_def(this, _, result) } + + /** Gets the node corresponding to the field `value`. */ + final HeredocBody getValue() { php_heredoc_value(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_heredoc_def(this, result, _) or + php_heredoc_def(this, _, result) or + php_heredoc_value(this, result) + } + } + + /** A class representing `heredoc_body` nodes. */ + class HeredocBody extends @php_heredoc_body, 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) { php_heredoc_body_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_heredoc_body_child(this, _, result) } + } + + /** A class representing `heredoc_end` tokens. */ + class HeredocEnd extends @php_token_heredoc_end, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "HeredocEnd" } + } + + /** A class representing `heredoc_start` tokens. */ + class HeredocStart extends @php_token_heredoc_start, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "HeredocStart" } + } + + /** A class representing `if_statement` nodes. */ + class IfStatement extends @php_if_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "IfStatement" } + + /** Gets the node corresponding to the field `alternative`. */ + final AstNode getAlternative(int i) { php_if_statement_alternative(this, i, result) } + + /** Gets the node corresponding to the field `body`. */ + final AstNode getBody() { php_if_statement_def(this, result, _) } + + /** Gets the node corresponding to the field `condition`. */ + final ParenthesizedExpression getCondition() { php_if_statement_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_if_statement_alternative(this, _, result) or + php_if_statement_def(this, result, _) or + php_if_statement_def(this, _, result) + } + } + + /** A class representing `include_expression` nodes. */ + class IncludeExpression extends @php_include_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "IncludeExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_include_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_include_expression_def(this, result) } + } + + /** A class representing `include_once_expression` nodes. */ + class IncludeOnceExpression extends @php_include_once_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "IncludeOnceExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_include_once_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_include_once_expression_def(this, result) } + } + + /** A class representing `integer` tokens. */ + class Integer extends @php_token_integer, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Integer" } + } + + /** A class representing `interface_declaration` nodes. */ + class InterfaceDeclaration extends @php_interface_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "InterfaceDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_interface_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final DeclarationList getBody() { php_interface_declaration_def(this, result, _) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_interface_declaration_def(this, _, result) } + + /** Gets the child of this node. */ + final BaseClause getChild() { php_interface_declaration_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_interface_declaration_attributes(this, result) or + php_interface_declaration_def(this, result, _) or + php_interface_declaration_def(this, _, result) or + php_interface_declaration_child(this, result) + } + } + + /** A class representing `intersection_type` nodes. */ + class IntersectionType extends @php_intersection_type, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "IntersectionType" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_intersection_type_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_intersection_type_child(this, _, result) } + } + + /** A class representing `list_literal` nodes. */ + class ListLiteral extends @php_list_literal, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ListLiteral" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_list_literal_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_list_literal_child(this, _, result) } + } + + class Literal extends @php_literal, AstNode { } + + /** A class representing `match_block` nodes. */ + class MatchBlock extends @php_match_block, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MatchBlock" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_match_block_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_match_block_child(this, _, result) } + } + + /** A class representing `match_condition_list` nodes. */ + class MatchConditionList extends @php_match_condition_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MatchConditionList" } + + /** Gets the `i`th child of this node. */ + final Expression getChild(int i) { php_match_condition_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_match_condition_list_child(this, _, result) } + } + + /** A class representing `match_conditional_expression` nodes. */ + class MatchConditionalExpression extends @php_match_conditional_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MatchConditionalExpression" } + + /** Gets the node corresponding to the field `conditional_expressions`. */ + final MatchConditionList getConditionalExpressions() { + php_match_conditional_expression_def(this, result, _) + } + + /** Gets the node corresponding to the field `return_expression`. */ + final Expression getReturnExpression() { php_match_conditional_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_match_conditional_expression_def(this, result, _) or + php_match_conditional_expression_def(this, _, result) + } + } + + /** A class representing `match_default_expression` nodes. */ + class MatchDefaultExpression extends @php_match_default_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MatchDefaultExpression" } + + /** Gets the node corresponding to the field `return_expression`. */ + final Expression getReturnExpression() { php_match_default_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_match_default_expression_def(this, result) } + } + + /** A class representing `match_expression` nodes. */ + class MatchExpression extends @php_match_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MatchExpression" } + + /** Gets the node corresponding to the field `body`. */ + final MatchBlock getBody() { php_match_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `condition`. */ + final ParenthesizedExpression getCondition() { php_match_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_match_expression_def(this, result, _) or php_match_expression_def(this, _, result) + } + } + + /** A class representing `member_access_expression` nodes. */ + class MemberAccessExpression extends @php_member_access_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MemberAccessExpression" } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_member_access_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `object`. */ + final AstNode getObject() { php_member_access_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_member_access_expression_def(this, result, _) or + php_member_access_expression_def(this, _, result) + } + } + + /** A class representing `member_call_expression` nodes. */ + class MemberCallExpression extends @php_member_call_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MemberCallExpression" } + + /** Gets the node corresponding to the field `arguments`. */ + final Arguments getArguments() { php_member_call_expression_def(this, result, _, _) } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_member_call_expression_def(this, _, result, _) } + + /** Gets the node corresponding to the field `object`. */ + final AstNode getObject() { php_member_call_expression_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_member_call_expression_def(this, result, _, _) or + php_member_call_expression_def(this, _, result, _) or + php_member_call_expression_def(this, _, _, result) + } + } + + /** A class representing `method_declaration` nodes. */ + class MethodDeclaration extends @php_method_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "MethodDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_method_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final CompoundStatement getBody() { php_method_declaration_body(this, result) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_method_declaration_def(this, result, _) } + + /** Gets the node corresponding to the field `parameters`. */ + final FormalParameters getParameters() { php_method_declaration_def(this, _, result) } + + /** Gets the node corresponding to the field `return_type`. */ + final AstNode getReturnType() { php_method_declaration_return_type(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_method_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_method_declaration_attributes(this, result) or + php_method_declaration_body(this, result) or + php_method_declaration_def(this, result, _) or + php_method_declaration_def(this, _, result) or + php_method_declaration_return_type(this, result) or + php_method_declaration_child(this, _, result) + } + } + + /** A class representing `name` tokens. */ + class Name extends @php_token_name, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Name" } + } + + /** A class representing `named_label_statement` nodes. */ + class NamedLabelStatement extends @php_named_label_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamedLabelStatement" } + + /** Gets the child of this node. */ + final Name getChild() { php_named_label_statement_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_named_label_statement_def(this, result) } + } + + /** A class representing `named_type` nodes. */ + class NamedType extends @php_named_type, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamedType" } + + /** Gets the child of this node. */ + final AstNode getChild() { php_named_type_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_named_type_def(this, result) } + } + + /** A class representing `namespace_definition` nodes. */ + class NamespaceDefinition extends @php_namespace_definition, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamespaceDefinition" } + + /** Gets the node corresponding to the field `body`. */ + final CompoundStatement getBody() { php_namespace_definition_body(this, result) } + + /** Gets the node corresponding to the field `name`. */ + final NamespaceName getName() { php_namespace_definition_name(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_namespace_definition_body(this, result) or php_namespace_definition_name(this, result) + } + } + + /** A class representing `namespace_name` nodes. */ + class NamespaceName extends @php_namespace_name, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamespaceName" } + + /** Gets the `i`th child of this node. */ + final Name getChild(int i) { php_namespace_name_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_namespace_name_child(this, _, result) } + } + + /** A class representing `namespace_use_clause` nodes. */ + class NamespaceUseClause extends @php_namespace_use_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamespaceUseClause" } + + /** Gets the node corresponding to the field `alias`. */ + final Name getAlias() { php_namespace_use_clause_alias(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final AstNode getType() { php_namespace_use_clause_type(this, result) } + + /** Gets the child of this node. */ + final AstNode getChild() { php_namespace_use_clause_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_namespace_use_clause_alias(this, result) or + php_namespace_use_clause_type(this, result) or + php_namespace_use_clause_def(this, result) + } + } + + /** A class representing `namespace_use_declaration` nodes. */ + class NamespaceUseDeclaration extends @php_namespace_use_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamespaceUseDeclaration" } + + /** Gets the node corresponding to the field `body`. */ + final NamespaceUseGroup getBody() { php_namespace_use_declaration_body(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final AstNode getType() { php_namespace_use_declaration_type(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_namespace_use_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_namespace_use_declaration_body(this, result) or + php_namespace_use_declaration_type(this, result) or + php_namespace_use_declaration_child(this, _, result) + } + } + + /** A class representing `namespace_use_group` nodes. */ + class NamespaceUseGroup extends @php_namespace_use_group, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NamespaceUseGroup" } + + /** Gets the `i`th child of this node. */ + final NamespaceUseClause getChild(int i) { php_namespace_use_group_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_namespace_use_group_child(this, _, result) } + } + + /** A class representing `nowdoc` nodes. */ + class Nowdoc extends @php_nowdoc, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Nowdoc" } + + /** Gets the node corresponding to the field `end_tag`. */ + final HeredocEnd getEndTag() { php_nowdoc_def(this, result, _) } + + /** Gets the node corresponding to the field `identifier`. */ + final HeredocStart getIdentifier() { php_nowdoc_def(this, _, result) } + + /** Gets the node corresponding to the field `value`. */ + final NowdocBody getValue() { php_nowdoc_value(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_nowdoc_def(this, result, _) or + php_nowdoc_def(this, _, result) or + php_nowdoc_value(this, result) + } + } + + /** A class representing `nowdoc_body` nodes. */ + class NowdocBody extends @php_nowdoc_body, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NowdocBody" } + + /** Gets the `i`th child of this node. */ + final NowdocString getChild(int i) { php_nowdoc_body_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_nowdoc_body_child(this, _, result) } + } + + /** A class representing `nowdoc_string` tokens. */ + class NowdocString extends @php_token_nowdoc_string, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NowdocString" } + } + + /** A class representing `null` tokens. */ + class Null extends @php_token_null, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Null" } + } + + /** A class representing `nullsafe_member_access_expression` nodes. */ + class NullsafeMemberAccessExpression extends @php_nullsafe_member_access_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NullsafeMemberAccessExpression" } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_nullsafe_member_access_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `object`. */ + final AstNode getObject() { php_nullsafe_member_access_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_nullsafe_member_access_expression_def(this, result, _) or + php_nullsafe_member_access_expression_def(this, _, result) + } + } + + /** A class representing `nullsafe_member_call_expression` nodes. */ + class NullsafeMemberCallExpression extends @php_nullsafe_member_call_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "NullsafeMemberCallExpression" } + + /** Gets the node corresponding to the field `arguments`. */ + final Arguments getArguments() { php_nullsafe_member_call_expression_def(this, result, _, _) } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_nullsafe_member_call_expression_def(this, _, result, _) } + + /** Gets the node corresponding to the field `object`. */ + final AstNode getObject() { php_nullsafe_member_call_expression_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_nullsafe_member_call_expression_def(this, result, _, _) or + php_nullsafe_member_call_expression_def(this, _, result, _) or + php_nullsafe_member_call_expression_def(this, _, _, result) + } + } + + /** A class representing `object_creation_expression` nodes. */ + class ObjectCreationExpression extends @php_object_creation_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ObjectCreationExpression" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_object_creation_expression_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_object_creation_expression_child(this, _, result) + } + } + + /** A class representing `operation` tokens. */ + class Operation extends @php_token_operation, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Operation" } + } + + /** A class representing `optional_type` nodes. */ + class OptionalType extends @php_optional_type, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "OptionalType" } + + /** Gets the child of this node. */ + final AstNode getChild() { php_optional_type_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_optional_type_def(this, result) } + } + + /** A class representing `pair` nodes. */ + class Pair extends @php_pair, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Pair" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_pair_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_pair_child(this, _, result) } + } + + /** A class representing `parenthesized_expression` nodes. */ + class ParenthesizedExpression extends @php_parenthesized_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ParenthesizedExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_parenthesized_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_parenthesized_expression_def(this, result) } + } + + /** A class representing `php_tag` tokens. */ + class PhpTag extends @php_token_php_tag, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PhpTag" } + } + + class PrimaryExpression extends @php_primary_expression, AstNode { } + + /** A class representing `primitive_type` tokens. */ + class PrimitiveType extends @php_token_primitive_type, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PrimitiveType" } + } + + /** A class representing `print_intrinsic` nodes. */ + class PrintIntrinsic extends @php_print_intrinsic, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PrintIntrinsic" } + + /** Gets the child of this node. */ + final Expression getChild() { php_print_intrinsic_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_print_intrinsic_def(this, result) } + } + + /** A class representing `program` nodes. */ + class Program extends @php_program, 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) { php_program_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_program_child(this, _, result) } + } + + /** A class representing `property_declaration` nodes. */ + class PropertyDeclaration extends @php_property_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PropertyDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_property_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final Type getType() { php_property_declaration_type(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_property_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_property_declaration_attributes(this, result) or + php_property_declaration_type(this, result) or + php_property_declaration_child(this, _, result) + } + } + + /** A class representing `property_element` nodes. */ + class PropertyElement extends @php_property_element, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PropertyElement" } + + /** Gets the node corresponding to the field `default_value`. */ + final Expression getDefaultValue() { php_property_element_default_value(this, result) } + + /** Gets the node corresponding to the field `name`. */ + final VariableName getName() { php_property_element_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_property_element_default_value(this, result) or php_property_element_def(this, result) + } + } + + /** A class representing `property_hook` nodes. */ + class PropertyHook extends @php_property_hook, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PropertyHook" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_property_hook_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final AstNode getBody() { php_property_hook_body(this, result) } + + /** Gets the node corresponding to the field `final`. */ + final FinalModifier getFinal() { php_property_hook_final(this, result) } + + /** Gets the node corresponding to the field `parameters`. */ + final FormalParameters getParameters() { php_property_hook_parameters(this, result) } + + /** Gets the node corresponding to the field `reference_modifier`. */ + final ReferenceModifier getReferenceModifier() { + php_property_hook_reference_modifier(this, result) + } + + /** Gets the child of this node. */ + final Name getChild() { php_property_hook_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_property_hook_attributes(this, result) or + php_property_hook_body(this, result) or + php_property_hook_final(this, result) or + php_property_hook_parameters(this, result) or + php_property_hook_reference_modifier(this, result) or + php_property_hook_def(this, result) + } + } + + /** A class representing `property_hook_list` nodes. */ + class PropertyHookList extends @php_property_hook_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PropertyHookList" } + + /** Gets the `i`th child of this node. */ + final PropertyHook getChild(int i) { php_property_hook_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_property_hook_list_child(this, _, result) } + } + + /** A class representing `property_promotion_parameter` nodes. */ + class PropertyPromotionParameter extends @php_property_promotion_parameter, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "PropertyPromotionParameter" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { + php_property_promotion_parameter_attributes(this, result) + } + + /** Gets the node corresponding to the field `default_value`. */ + final Expression getDefaultValue() { + php_property_promotion_parameter_default_value(this, result) + } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_property_promotion_parameter_def(this, result, _) } + + /** Gets the node corresponding to the field `readonly`. */ + final ReadonlyModifier getReadonly() { php_property_promotion_parameter_readonly(this, result) } + + /** Gets the node corresponding to the field `type`. */ + final Type getType() { php_property_promotion_parameter_type(this, result) } + + /** Gets the node corresponding to the field `visibility`. */ + final VisibilityModifier getVisibility() { + php_property_promotion_parameter_def(this, _, result) + } + + /** Gets the child of this node. */ + final PropertyHookList getChild() { php_property_promotion_parameter_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_property_promotion_parameter_attributes(this, result) or + php_property_promotion_parameter_default_value(this, result) or + php_property_promotion_parameter_def(this, result, _) or + php_property_promotion_parameter_readonly(this, result) or + php_property_promotion_parameter_type(this, result) or + php_property_promotion_parameter_def(this, _, result) or + php_property_promotion_parameter_child(this, result) + } + } + + /** A class representing `qualified_name` nodes. */ + class QualifiedName extends @php_qualified_name, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "QualifiedName" } + + /** Gets the node corresponding to the field `prefix`. */ + final AstNode getPrefix(int i) { php_qualified_name_prefix(this, i, result) } + + /** Gets the child of this node. */ + final Name getChild() { php_qualified_name_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_qualified_name_prefix(this, _, result) or php_qualified_name_def(this, result) + } + } + + /** A class representing `readonly_modifier` tokens. */ + class ReadonlyModifier extends @php_token_readonly_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReadonlyModifier" } + } + + /** A class representing `reference_assignment_expression` nodes. */ + class ReferenceAssignmentExpression extends @php_reference_assignment_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReferenceAssignmentExpression" } + + /** Gets the node corresponding to the field `left`. */ + final AstNode getLeft() { php_reference_assignment_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `right`. */ + final Expression getRight() { php_reference_assignment_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_reference_assignment_expression_def(this, result, _) or + php_reference_assignment_expression_def(this, _, result) + } + } + + /** A class representing `reference_modifier` tokens. */ + class ReferenceModifier extends @php_token_reference_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReferenceModifier" } + } + + /** A class representing `relative_scope` tokens. */ + class RelativeScope extends @php_token_relative_scope, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "RelativeScope" } + } + + /** A class representing `require_expression` nodes. */ + class RequireExpression extends @php_require_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "RequireExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_require_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_require_expression_def(this, result) } + } + + /** A class representing `require_once_expression` nodes. */ + class RequireOnceExpression extends @php_require_once_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "RequireOnceExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_require_once_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_require_once_expression_def(this, result) } + } + + /** A class representing `return_statement` nodes. */ + class ReturnStatement extends @php_return_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReturnStatement" } + + /** Gets the child of this node. */ + final Expression getChild() { php_return_statement_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_return_statement_child(this, result) } + } + + /** A class representing `scoped_call_expression` nodes. */ + class ScopedCallExpression extends @php_scoped_call_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ScopedCallExpression" } + + /** Gets the node corresponding to the field `arguments`. */ + final Arguments getArguments() { php_scoped_call_expression_def(this, result, _, _) } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_scoped_call_expression_def(this, _, result, _) } + + /** Gets the node corresponding to the field `scope`. */ + final AstNode getScope() { php_scoped_call_expression_def(this, _, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_scoped_call_expression_def(this, result, _, _) or + php_scoped_call_expression_def(this, _, result, _) or + php_scoped_call_expression_def(this, _, _, result) + } + } + + /** A class representing `scoped_property_access_expression` nodes. */ + class ScopedPropertyAccessExpression extends @php_scoped_property_access_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ScopedPropertyAccessExpression" } + + /** Gets the node corresponding to the field `name`. */ + final AstNode getName() { php_scoped_property_access_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `scope`. */ + final AstNode getScope() { php_scoped_property_access_expression_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_scoped_property_access_expression_def(this, result, _) or + php_scoped_property_access_expression_def(this, _, result) + } + } + + /** A class representing `sequence_expression` nodes. */ + class SequenceExpression extends @php_sequence_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SequenceExpression" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_sequence_expression_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_sequence_expression_child(this, _, result) } + } + + /** A class representing `shell_command_expression` nodes. */ + class ShellCommandExpression extends @php_shell_command_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ShellCommandExpression" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_shell_command_expression_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_shell_command_expression_child(this, _, result) + } + } + + /** A class representing `simple_parameter` nodes. */ + class SimpleParameter extends @php_simple_parameter, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SimpleParameter" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_simple_parameter_attributes(this, result) } + + /** Gets the node corresponding to the field `default_value`. */ + final Expression getDefaultValue() { php_simple_parameter_default_value(this, result) } + + /** Gets the node corresponding to the field `name`. */ + final VariableName getName() { php_simple_parameter_def(this, result) } + + /** Gets the node corresponding to the field `reference_modifier`. */ + final ReferenceModifier getReferenceModifier() { + php_simple_parameter_reference_modifier(this, result) + } + + /** Gets the node corresponding to the field `type`. */ + final Type getType() { php_simple_parameter_type(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_simple_parameter_attributes(this, result) or + php_simple_parameter_default_value(this, result) or + php_simple_parameter_def(this, result) or + php_simple_parameter_reference_modifier(this, result) or + php_simple_parameter_type(this, result) + } + } + + class Statement extends @php_statement, AstNode { } + + /** A class representing `static_modifier` tokens. */ + class StaticModifier extends @php_token_static_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "StaticModifier" } + } + + /** A class representing `static_variable_declaration` nodes. */ + class StaticVariableDeclaration extends @php_static_variable_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "StaticVariableDeclaration" } + + /** Gets the node corresponding to the field `name`. */ + final VariableName getName() { php_static_variable_declaration_def(this, result) } + + /** Gets the node corresponding to the field `value`. */ + final Expression getValue() { php_static_variable_declaration_value(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_static_variable_declaration_def(this, result) or + php_static_variable_declaration_value(this, result) + } + } + + /** A class representing `string` nodes. */ + class String extends @php_string__, AstNode { + /** 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) { php_string_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_string_child(this, _, result) } + } + + /** A class representing `string_content` tokens. */ + class StringContent extends @php_token_string_content, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "StringContent" } + } + + /** A class representing `subscript_expression` nodes. */ + class SubscriptExpression extends @php_subscript_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SubscriptExpression" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_subscript_expression_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_subscript_expression_child(this, _, result) } + } + + /** A class representing `switch_block` nodes. */ + class SwitchBlock extends @php_switch_block, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SwitchBlock" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_switch_block_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_switch_block_child(this, _, result) } + } + + /** A class representing `switch_statement` nodes. */ + class SwitchStatement extends @php_switch_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "SwitchStatement" } + + /** Gets the node corresponding to the field `body`. */ + final SwitchBlock getBody() { php_switch_statement_def(this, result, _) } + + /** Gets the node corresponding to the field `condition`. */ + final ParenthesizedExpression getCondition() { php_switch_statement_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_switch_statement_def(this, result, _) or php_switch_statement_def(this, _, result) + } + } + + /** A class representing `text` tokens. */ + class Text extends @php_token_text, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Text" } + } + + /** A class representing `text_interpolation` nodes. */ + class TextInterpolation extends @php_text_interpolation, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TextInterpolation" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_text_interpolation_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_text_interpolation_child(this, _, result) } + } + + /** A class representing `throw_expression` nodes. */ + class ThrowExpression extends @php_throw_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ThrowExpression" } + + /** Gets the child of this node. */ + final Expression getChild() { php_throw_expression_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_throw_expression_def(this, result) } + } + + /** A class representing `trait_declaration` nodes. */ + class TraitDeclaration extends @php_trait_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TraitDeclaration" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_trait_declaration_attributes(this, result) } + + /** Gets the node corresponding to the field `body`. */ + final DeclarationList getBody() { php_trait_declaration_def(this, result, _) } + + /** Gets the node corresponding to the field `name`. */ + final Name getName() { php_trait_declaration_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_trait_declaration_attributes(this, result) or + php_trait_declaration_def(this, result, _) or + php_trait_declaration_def(this, _, result) + } + } + + /** A class representing `try_statement` nodes. */ + class TryStatement extends @php_try_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TryStatement" } + + /** Gets the node corresponding to the field `body`. */ + final CompoundStatement getBody() { php_try_statement_def(this, result) } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_try_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_try_statement_def(this, result) or php_try_statement_child(this, _, result) + } + } + + class Type extends @php_type__, AstNode { } + + /** A class representing `type_list` nodes. */ + class TypeList extends @php_type_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "TypeList" } + + /** Gets the `i`th child of this node. */ + final NamedType getChild(int i) { php_type_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_type_list_child(this, _, result) } + } + + /** A class representing `unary_op_expression` nodes. */ + class UnaryOpExpression extends @php_unary_op_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UnaryOpExpression" } + + /** Gets the node corresponding to the field `argument`. */ + final Expression getArgument() { php_unary_op_expression_argument(this, result) } + + /** Gets the node corresponding to the field `operator`. */ + final AstNode getOperator() { php_unary_op_expression_operator(this, result) } + + /** Gets the child of this node. */ + final Integer getChild() { php_unary_op_expression_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_unary_op_expression_argument(this, result) or + php_unary_op_expression_operator(this, result) or + php_unary_op_expression_child(this, result) + } + } + + /** A class representing `union_type` nodes. */ + class UnionType extends @php_union_type, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UnionType" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_union_type_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_union_type_child(this, _, result) } + } + + /** A class representing `unset_statement` nodes. */ + class UnsetStatement extends @php_unset_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UnsetStatement" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_unset_statement_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_unset_statement_child(this, _, result) } + } + + /** A class representing `update_expression` nodes. */ + class UpdateExpression extends @php_update_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UpdateExpression" } + + /** Gets the node corresponding to the field `argument`. */ + final AstNode getArgument() { php_update_expression_def(this, result, _) } + + /** Gets the node corresponding to the field `operator`. */ + final string getOperator() { + exists(int value | php_update_expression_def(this, _, value) | + result = "++" and value = 0 + or + result = "--" and value = 1 + ) + } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_update_expression_def(this, result, _) } + } + + /** A class representing `use_as_clause` nodes. */ + class UseAsClause extends @php_use_as_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UseAsClause" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_use_as_clause_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_use_as_clause_child(this, _, result) } + } + + /** A class representing `use_declaration` nodes. */ + class UseDeclaration extends @php_use_declaration, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UseDeclaration" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_use_declaration_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_use_declaration_child(this, _, result) } + } + + /** A class representing `use_instead_of_clause` nodes. */ + class UseInsteadOfClause extends @php_use_instead_of_clause, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UseInsteadOfClause" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_use_instead_of_clause_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_use_instead_of_clause_child(this, _, result) } + } + + /** A class representing `use_list` nodes. */ + class UseList extends @php_use_list, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "UseList" } + + /** Gets the `i`th child of this node. */ + final AstNode getChild(int i) { php_use_list_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_use_list_child(this, _, result) } + } + + /** A class representing `var_modifier` tokens. */ + class VarModifier extends @php_token_var_modifier, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "VarModifier" } + } + + /** A class representing `variable_name` nodes. */ + class VariableName extends @php_variable_name, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "VariableName" } + + /** Gets the child of this node. */ + final Name getChild() { php_variable_name_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_variable_name_def(this, result) } + } + + /** A class representing `variadic_parameter` nodes. */ + class VariadicParameter extends @php_variadic_parameter, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "VariadicParameter" } + + /** Gets the node corresponding to the field `attributes`. */ + final AttributeList getAttributes() { php_variadic_parameter_attributes(this, result) } + + /** Gets the node corresponding to the field `name`. */ + final VariableName getName() { php_variadic_parameter_def(this, result) } + + /** Gets the node corresponding to the field `reference_modifier`. */ + final ReferenceModifier getReferenceModifier() { + php_variadic_parameter_reference_modifier(this, result) + } + + /** Gets the node corresponding to the field `type`. */ + final Type getType() { php_variadic_parameter_type(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_variadic_parameter_attributes(this, result) or + php_variadic_parameter_def(this, result) or + php_variadic_parameter_reference_modifier(this, result) or + php_variadic_parameter_type(this, result) + } + } + + /** A class representing `variadic_placeholder` tokens. */ + class VariadicPlaceholder extends @php_token_variadic_placeholder, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "VariadicPlaceholder" } + } + + /** A class representing `variadic_unpacking` nodes. */ + class VariadicUnpacking extends @php_variadic_unpacking, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "VariadicUnpacking" } + + /** Gets the child of this node. */ + final Expression getChild() { php_variadic_unpacking_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_variadic_unpacking_def(this, result) } + } + + /** A class representing `visibility_modifier` nodes. */ + class VisibilityModifier extends @php_visibility_modifier, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "VisibilityModifier" } + + /** Gets the child of this node. */ + final Operation getChild() { php_visibility_modifier_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_visibility_modifier_child(this, result) } + } + + /** A class representing `while_statement` nodes. */ + class WhileStatement extends @php_while_statement, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "WhileStatement" } + + /** Gets the node corresponding to the field `body`. */ + final AstNode getBody() { php_while_statement_def(this, result, _) } + + /** Gets the node corresponding to the field `condition`. */ + final ParenthesizedExpression getCondition() { php_while_statement_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + php_while_statement_def(this, result, _) or php_while_statement_def(this, _, result) + } + } + + /** A class representing `yield_expression` nodes. */ + class YieldExpression extends @php_yield_expression, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "YieldExpression" } + + /** Gets the child of this node. */ + final AstNode getChild() { php_yield_expression_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { php_yield_expression_child(this, result) } + } +} diff --git a/php/ql/lib/codeql/php/security/Sinks.qll b/php/ql/lib/codeql/php/security/Sinks.qll new file mode 100644 index 000000000000..46eb07eb313e --- /dev/null +++ b/php/ql/lib/codeql/php/security/Sinks.qll @@ -0,0 +1,12 @@ +import codeql.php.ast.Calls + +/** Very small syntactic model of risky sinks for the MVP. */ +module PhpSecuritySinks { + predicate isDangerousBuiltinName(string name) { + name in ["eval", "assert", "unserialize", "system", "exec"] + } + + predicate isDangerousBuiltinCall(FunctionCall call) { + isDangerousBuiltinName(call.getCalleeName()) + } +} diff --git a/php/ql/lib/codeql/php/security/Sources.qll b/php/ql/lib/codeql/php/security/Sources.qll new file mode 100644 index 000000000000..7d96a10bed8f --- /dev/null +++ b/php/ql/lib/codeql/php/security/Sources.qll @@ -0,0 +1,35 @@ +import codeql.php.ast.internal.TreeSitter + +/** + * Very small, syntax-based model of untrusted input sources. + * + * MVP: only recognizes direct reads from PHP superglobals (for example `$_GET["x"]`). + */ +module PhpSecuritySources { + /** Holds if `name` is the name of a PHP superglobal variable (without the leading `$`). */ + predicate isSuperglobalName(string name) { + name in [ + "_GET", + "_POST", + "_COOKIE", + "_REQUEST", + "_SERVER", + "_FILES", + "_ENV" + ] + } + + /** Holds if `v` is a superglobal variable name. */ + predicate isSuperglobalVar(Php::VariableName v) { + isSuperglobalName(v.getChild().getValue()) + } + + /** Holds if `node` has (transitively) a superglobal variable-name descendant. */ + predicate hasSuperglobalDescendant(Php::AstNode node) { + exists(Php::VariableName v | v = node and isSuperglobalVar(v)) or + exists(Php::AstNode child | child = node.getAFieldOrChild() and hasSuperglobalDescendant(child)) + } + + /** Holds if `e` is an expression that directly uses a superglobal. */ + predicate isUntrustedSourceExpr(Php::Expression e) { hasSuperglobalDescendant(e) } +} diff --git a/php/ql/lib/codeql/php/security/Taint.qll b/php/ql/lib/codeql/php/security/Taint.qll new file mode 100644 index 000000000000..f37bb3e3dc68 --- /dev/null +++ b/php/ql/lib/codeql/php/security/Taint.qll @@ -0,0 +1,43 @@ +import codeql.php.ast.Calls +import codeql.php.ast.internal.TreeSitter +import codeql.php.security.Sources + +/** Very small, syntax-based taint predicate for the MVP. */ +module PhpSecurityTaint { + private predicate isTaintedVarName(string name) { + exists(Php::AssignmentExpression a, Php::VariableName v | + a.getLeft() = v and + v.getChild().getValue() = name and + isTainted(a.getRight()) + ) + or + exists(Php::ReferenceAssignmentExpression a, Php::VariableName v | + a.getLeft() = v and + v.getChild().getValue() = name and + isTainted(a.getRight()) + ) + } + + /** Holds if `e` is considered tainted. + * + * MVP: + * - direct use of a superglobal + * - or a variable that is assigned from a tainted expression + * - or an expression containing a tainted sub-expression + */ + predicate isTainted(Php::Expression e) { + PhpSecuritySources::isUntrustedSourceExpr(e) + or + exists(Php::VariableName v | + v = e and + isTaintedVarName(v.getChild().getValue()) + ) + or + exists(Php::Expression child | child = e.getAFieldOrChild() and isTainted(child)) + } + + /** Holds if any argument expression of `call` is tainted. */ + predicate hasTaintedArgument(Call call) { + exists(Php::Expression arg | arg = call.getAnArgumentExpr() and isTainted(arg)) + } +} diff --git a/php/ql/lib/php.dbscheme b/php/ql/lib/php.dbscheme new file mode 100644 index 000000000000..8ccda07e0afd --- /dev/null +++ b/php/ql/lib/php.dbscheme @@ -0,0 +1,1809 @@ +// CodeQL database schema for Php +// Automatically generated from the tree-sitter grammar; do not edit + +/*- Files and folders -*/ + +/** + * The location of an element. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @file | @folder + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/*- Empty location -*/ + +empty_location( + int location: @location_default ref +); + +/*- Source location prefix -*/ + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/*- Diagnostic messages -*/ + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/*- Diagnostic messages: severity -*/ + +case @diagnostic.severity of + 10 = @diagnostic_debug +| 20 = @diagnostic_info +| 30 = @diagnostic_warning +| 40 = @diagnostic_error +; + +/*- YAML -*/ + +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + string tag: string ref, + string tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + string anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + string target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + string value: string ref); + +yaml_errors (unique int id: @yaml_error, + string message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/*- Database metadata -*/ +databaseMetadata( + string metadataKey: string ref, + string value: string ref +); + +overlayChangedFiles( + string path: string ref +); + +/*- Php dbscheme -*/ +php_anonymous_class_attributes( + unique int php_anonymous_class: @php_anonymous_class ref, + unique int attributes: @php_attribute_list ref +); + +@php_anonymous_class_child_type = @php_arguments | @php_base_clause | @php_class_interface_clause | @php_token_abstract_modifier | @php_token_final_modifier | @php_token_readonly_modifier | @php_token_static_modifier | @php_token_var_modifier | @php_visibility_modifier + +#keyset[php_anonymous_class, index] +php_anonymous_class_child( + int php_anonymous_class: @php_anonymous_class ref, + int index: int ref, + unique int child: @php_anonymous_class_child_type ref +); + +php_anonymous_class_def( + unique int id: @php_anonymous_class, + int body: @php_declaration_list ref +); + +php_anonymous_function_attributes( + unique int php_anonymous_function: @php_anonymous_function ref, + unique int attributes: @php_attribute_list ref +); + +php_anonymous_function_reference_modifier( + unique int php_anonymous_function: @php_anonymous_function ref, + unique int reference_modifier: @php_token_reference_modifier ref +); + +@php_anonymous_function_return_type_type = @php_token_bottom_type | @php_type__ + +php_anonymous_function_return_type( + unique int php_anonymous_function: @php_anonymous_function ref, + unique int return_type: @php_anonymous_function_return_type_type ref +); + +php_anonymous_function_static_modifier( + unique int php_anonymous_function: @php_anonymous_function ref, + unique int static_modifier: @php_token_static_modifier ref +); + +php_anonymous_function_child( + unique int php_anonymous_function: @php_anonymous_function ref, + unique int child: @php_anonymous_function_use_clause ref +); + +php_anonymous_function_def( + unique int id: @php_anonymous_function, + int body: @php_compound_statement ref, + int parameters: @php_formal_parameters ref +); + +@php_anonymous_function_use_clause_child_type = @php_by_ref | @php_variable_name + +#keyset[php_anonymous_function_use_clause, index] +php_anonymous_function_use_clause_child( + int php_anonymous_function_use_clause: @php_anonymous_function_use_clause ref, + int index: int ref, + unique int child: @php_anonymous_function_use_clause_child_type ref +); + +php_anonymous_function_use_clause_def( + unique int id: @php_anonymous_function_use_clause +); + +php_argument_name( + unique int php_argument: @php_argument ref, + unique int name: @php_token_name ref +); + +php_argument_reference_modifier( + unique int php_argument: @php_argument ref, + unique int reference_modifier: @php_token_reference_modifier ref +); + +@php_argument_child_type = @php_expression | @php_token_name | @php_variadic_unpacking + +php_argument_def( + unique int id: @php_argument, + int child: @php_argument_child_type ref +); + +@php_arguments_child_type = @php_argument | @php_token_variadic_placeholder + +#keyset[php_arguments, index] +php_arguments_child( + int php_arguments: @php_arguments ref, + int index: int ref, + unique int child: @php_arguments_child_type ref +); + +php_arguments_def( + unique int id: @php_arguments +); + +#keyset[php_array_creation_expression, index] +php_array_creation_expression_child( + int php_array_creation_expression: @php_array_creation_expression ref, + int index: int ref, + unique int child: @php_array_element_initializer ref +); + +php_array_creation_expression_def( + unique int id: @php_array_creation_expression +); + +@php_array_element_initializer_child_type = @php_by_ref | @php_expression | @php_variadic_unpacking + +#keyset[php_array_element_initializer, index] +php_array_element_initializer_child( + int php_array_element_initializer: @php_array_element_initializer ref, + int index: int ref, + unique int child: @php_array_element_initializer_child_type ref +); + +php_array_element_initializer_def( + unique int id: @php_array_element_initializer +); + +php_arrow_function_attributes( + unique int php_arrow_function: @php_arrow_function ref, + unique int attributes: @php_attribute_list ref +); + +php_arrow_function_reference_modifier( + unique int php_arrow_function: @php_arrow_function ref, + unique int reference_modifier: @php_token_reference_modifier ref +); + +@php_arrow_function_return_type_type = @php_token_bottom_type | @php_type__ + +php_arrow_function_return_type( + unique int php_arrow_function: @php_arrow_function ref, + unique int return_type: @php_arrow_function_return_type_type ref +); + +php_arrow_function_static_modifier( + unique int php_arrow_function: @php_arrow_function ref, + unique int static_modifier: @php_token_static_modifier ref +); + +php_arrow_function_def( + unique int id: @php_arrow_function, + int body: @php_expression ref, + int parameters: @php_formal_parameters ref +); + +@php_assignment_expression_left_type = @php_cast_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_list_literal | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +php_assignment_expression_def( + unique int id: @php_assignment_expression, + int left: @php_assignment_expression_left_type ref, + int right: @php_expression ref +); + +php_attribute_parameters( + unique int php_attribute: @php_attribute ref, + unique int parameters: @php_arguments ref +); + +@php_attribute_child_type = @php_qualified_name | @php_token_name + +php_attribute_def( + unique int id: @php_attribute, + int child: @php_attribute_child_type ref +); + +#keyset[php_attribute_group, index] +php_attribute_group_child( + int php_attribute_group: @php_attribute_group ref, + int index: int ref, + unique int child: @php_attribute ref +); + +php_attribute_group_def( + unique int id: @php_attribute_group +); + +#keyset[php_attribute_list, index] +php_attribute_list_child( + int php_attribute_list: @php_attribute_list ref, + int index: int ref, + unique int child: @php_attribute_group ref +); + +php_attribute_list_def( + unique int id: @php_attribute_list +); + +@php_augmented_assignment_expression_left_type = @php_cast_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +case @php_augmented_assignment_expression.operator of + 0 = @php_augmented_assignment_expression_percentequal +| 1 = @php_augmented_assignment_expression_ampersandequal +| 2 = @php_augmented_assignment_expression_starstarequal +| 3 = @php_augmented_assignment_expression_starequal +| 4 = @php_augmented_assignment_expression_plusequal +| 5 = @php_augmented_assignment_expression_minusequal +| 6 = @php_augmented_assignment_expression_dotequal +| 7 = @php_augmented_assignment_expression_slashequal +| 8 = @php_augmented_assignment_expression_langlelangleequal +| 9 = @php_augmented_assignment_expression_ranglerangleequal +| 10 = @php_augmented_assignment_expression_questionquestionequal +| 11 = @php_augmented_assignment_expression_caretequal +| 12 = @php_augmented_assignment_expression_pipeequal +; + + +php_augmented_assignment_expression_def( + unique int id: @php_augmented_assignment_expression, + int left: @php_augmented_assignment_expression_left_type ref, + int operator: int ref, + int right: @php_expression ref +); + +@php_base_clause_child_type = @php_qualified_name | @php_token_name + +#keyset[php_base_clause, index] +php_base_clause_child( + int php_base_clause: @php_base_clause ref, + int index: int ref, + unique int child: @php_base_clause_child_type ref +); + +php_base_clause_def( + unique int id: @php_base_clause +); + +case @php_binary_expression.operator of + 0 = @php_binary_expression_bangequal +| 1 = @php_binary_expression_bangequalequal +| 2 = @php_binary_expression_percent +| 3 = @php_binary_expression_ampersand +| 4 = @php_binary_expression_ampersandampersand +| 5 = @php_binary_expression_star +| 6 = @php_binary_expression_starstar +| 7 = @php_binary_expression_plus +| 8 = @php_binary_expression_minus +| 9 = @php_binary_expression_dot +| 10 = @php_binary_expression_slash +| 11 = @php_binary_expression_langle +| 12 = @php_binary_expression_langlelangle +| 13 = @php_binary_expression_langleequal +| 14 = @php_binary_expression_langleequalrangle +| 15 = @php_binary_expression_langlerangle +| 16 = @php_binary_expression_equalequal +| 17 = @php_binary_expression_equalequalequal +| 18 = @php_binary_expression_rangle +| 19 = @php_binary_expression_rangleequal +| 20 = @php_binary_expression_ranglerangle +| 21 = @php_binary_expression_questionquestion +| 22 = @php_binary_expression_caret +| 23 = @php_binary_expression_and +| 24 = @php_binary_expression_instanceof +| 25 = @php_binary_expression_or +| 26 = @php_binary_expression_xor +| 27 = @php_binary_expression_pipe +| 28 = @php_binary_expression_pipepipe +; + + +@php_binary_expression_right_type = @php_dynamic_variable_name | @php_expression | @php_member_access_expression | @php_nullsafe_member_access_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_property_access_expression | @php_subscript_expression | @php_token_name | @php_variable_name + +php_binary_expression_def( + unique int id: @php_binary_expression, + int left: @php_expression ref, + int operator: int ref, + int right: @php_binary_expression_right_type ref +); + +php_break_statement_child( + unique int php_break_statement: @php_break_statement ref, + unique int child: @php_expression ref +); + +php_break_statement_def( + unique int id: @php_break_statement +); + +@php_by_ref_child_type = @php_cast_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +php_by_ref_def( + unique int id: @php_by_ref, + int child: @php_by_ref_child_type ref +); + +#keyset[php_case_statement, index] +php_case_statement_child( + int php_case_statement: @php_case_statement ref, + int index: int ref, + unique int child: @php_statement ref +); + +php_case_statement_def( + unique int id: @php_case_statement, + int value: @php_expression ref +); + +@php_cast_expression_value_type = @php_clone_expression | @php_error_suppression_expression | @php_include_expression | @php_include_once_expression | @php_primary_expression | @php_unary_op_expression + +php_cast_expression_def( + unique int id: @php_cast_expression, + int type__: @php_token_cast_type ref, + int value: @php_cast_expression_value_type ref +); + +php_catch_clause_name( + unique int php_catch_clause: @php_catch_clause ref, + unique int name: @php_variable_name ref +); + +php_catch_clause_def( + unique int id: @php_catch_clause, + int body: @php_compound_statement ref, + int type__: @php_type_list ref +); + +@php_class_constant_access_expression_child_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_token_relative_scope | @php_variable_name + +#keyset[php_class_constant_access_expression, index] +php_class_constant_access_expression_child( + int php_class_constant_access_expression: @php_class_constant_access_expression ref, + int index: int ref, + unique int child: @php_class_constant_access_expression_child_type ref +); + +php_class_constant_access_expression_def( + unique int id: @php_class_constant_access_expression +); + +php_class_declaration_attributes( + unique int php_class_declaration: @php_class_declaration ref, + unique int attributes: @php_attribute_list ref +); + +@php_class_declaration_child_type = @php_base_clause | @php_class_interface_clause | @php_token_abstract_modifier | @php_token_final_modifier | @php_token_readonly_modifier | @php_token_static_modifier | @php_token_var_modifier | @php_visibility_modifier + +#keyset[php_class_declaration, index] +php_class_declaration_child( + int php_class_declaration: @php_class_declaration ref, + int index: int ref, + unique int child: @php_class_declaration_child_type ref +); + +php_class_declaration_def( + unique int id: @php_class_declaration, + int body: @php_declaration_list ref, + int name: @php_token_name ref +); + +@php_class_interface_clause_child_type = @php_qualified_name | @php_token_name + +#keyset[php_class_interface_clause, index] +php_class_interface_clause_child( + int php_class_interface_clause: @php_class_interface_clause ref, + int index: int ref, + unique int child: @php_class_interface_clause_child_type ref +); + +php_class_interface_clause_def( + unique int id: @php_class_interface_clause +); + +php_clone_expression_def( + unique int id: @php_clone_expression, + int child: @php_primary_expression ref +); + +#keyset[php_colon_block, index] +php_colon_block_child( + int php_colon_block: @php_colon_block ref, + int index: int ref, + unique int child: @php_statement ref +); + +php_colon_block_def( + unique int id: @php_colon_block +); + +#keyset[php_compound_statement, index] +php_compound_statement_child( + int php_compound_statement: @php_compound_statement ref, + int index: int ref, + unique int child: @php_statement ref +); + +php_compound_statement_def( + unique int id: @php_compound_statement +); + +php_conditional_expression_body( + unique int php_conditional_expression: @php_conditional_expression ref, + unique int body: @php_expression ref +); + +php_conditional_expression_def( + unique int id: @php_conditional_expression, + int alternative: @php_expression ref, + int condition: @php_expression ref +); + +php_const_declaration_attributes( + unique int php_const_declaration: @php_const_declaration ref, + unique int attributes: @php_attribute_list ref +); + +php_const_declaration_type( + unique int php_const_declaration: @php_const_declaration ref, + unique int type__: @php_type__ ref +); + +@php_const_declaration_child_type = @php_const_element | @php_token_abstract_modifier | @php_token_final_modifier | @php_token_readonly_modifier | @php_token_static_modifier | @php_token_var_modifier | @php_visibility_modifier + +#keyset[php_const_declaration, index] +php_const_declaration_child( + int php_const_declaration: @php_const_declaration ref, + int index: int ref, + unique int child: @php_const_declaration_child_type ref +); + +php_const_declaration_def( + unique int id: @php_const_declaration +); + +@php_const_element_child_type = @php_expression | @php_token_name + +#keyset[php_const_element, index] +php_const_element_child( + int php_const_element: @php_const_element ref, + int index: int ref, + unique int child: @php_const_element_child_type ref +); + +php_const_element_def( + unique int id: @php_const_element +); + +php_continue_statement_child( + unique int php_continue_statement: @php_continue_statement ref, + unique int child: @php_expression ref +); + +php_continue_statement_def( + unique int id: @php_continue_statement +); + +@php_declaration_list_child_type = @php_const_declaration | @php_method_declaration | @php_property_declaration | @php_use_declaration + +#keyset[php_declaration_list, index] +php_declaration_list_child( + int php_declaration_list: @php_declaration_list ref, + int index: int ref, + unique int child: @php_declaration_list_child_type ref +); + +php_declaration_list_def( + unique int id: @php_declaration_list +); + +php_declare_directive_def( + unique int id: @php_declare_directive, + int child: @php_literal ref +); + +@php_declare_statement_child_type = @php_declare_directive | @php_statement + +#keyset[php_declare_statement, index] +php_declare_statement_child( + int php_declare_statement: @php_declare_statement ref, + int index: int ref, + unique int child: @php_declare_statement_child_type ref +); + +php_declare_statement_def( + unique int id: @php_declare_statement +); + +#keyset[php_default_statement, index] +php_default_statement_child( + int php_default_statement: @php_default_statement ref, + int index: int ref, + unique int child: @php_statement ref +); + +php_default_statement_def( + unique int id: @php_default_statement +); + +@php_disjunctive_normal_form_type_child_type = @php_intersection_type | @php_named_type | @php_optional_type | @php_token_primitive_type + +#keyset[php_disjunctive_normal_form_type, index] +php_disjunctive_normal_form_type_child( + int php_disjunctive_normal_form_type: @php_disjunctive_normal_form_type ref, + int index: int ref, + unique int child: @php_disjunctive_normal_form_type_child_type ref +); + +php_disjunctive_normal_form_type_def( + unique int id: @php_disjunctive_normal_form_type +); + +php_do_statement_def( + unique int id: @php_do_statement, + int body: @php_statement ref, + int condition: @php_parenthesized_expression ref +); + +@php_dynamic_variable_name_child_type = @php_dynamic_variable_name | @php_expression | @php_variable_name + +php_dynamic_variable_name_def( + unique int id: @php_dynamic_variable_name, + int child: @php_dynamic_variable_name_child_type ref +); + +@php_echo_statement_child_type = @php_expression | @php_sequence_expression + +php_echo_statement_def( + unique int id: @php_echo_statement, + int child: @php_echo_statement_child_type ref +); + +@php_else_clause_body_type = @php_colon_block | @php_statement + +php_else_clause_def( + unique int id: @php_else_clause, + int body: @php_else_clause_body_type ref +); + +@php_else_if_clause_body_type = @php_colon_block | @php_statement + +php_else_if_clause_def( + unique int id: @php_else_if_clause, + int body: @php_else_if_clause_body_type ref, + int condition: @php_parenthesized_expression ref +); + +@php_encapsed_string_child_type = @php_dynamic_variable_name | @php_expression | @php_member_access_expression | @php_subscript_expression | @php_token_escape_sequence | @php_token_string_content | @php_variable_name + +#keyset[php_encapsed_string, index] +php_encapsed_string_child( + int php_encapsed_string: @php_encapsed_string ref, + int index: int ref, + unique int child: @php_encapsed_string_child_type ref +); + +php_encapsed_string_def( + unique int id: @php_encapsed_string +); + +php_enum_case_attributes( + unique int php_enum_case: @php_enum_case ref, + unique int attributes: @php_attribute_list ref +); + +php_enum_case_value( + unique int php_enum_case: @php_enum_case ref, + unique int value: @php_expression ref +); + +php_enum_case_def( + unique int id: @php_enum_case, + int name: @php_token_name ref +); + +php_enum_declaration_attributes( + unique int php_enum_declaration: @php_enum_declaration ref, + unique int attributes: @php_attribute_list ref +); + +@php_enum_declaration_child_type = @php_class_interface_clause | @php_token_primitive_type + +#keyset[php_enum_declaration, index] +php_enum_declaration_child( + int php_enum_declaration: @php_enum_declaration ref, + int index: int ref, + unique int child: @php_enum_declaration_child_type ref +); + +php_enum_declaration_def( + unique int id: @php_enum_declaration, + int body: @php_enum_declaration_list ref, + int name: @php_token_name ref +); + +@php_enum_declaration_list_child_type = @php_enum_case | @php_method_declaration | @php_use_declaration + +#keyset[php_enum_declaration_list, index] +php_enum_declaration_list_child( + int php_enum_declaration_list: @php_enum_declaration_list ref, + int index: int ref, + unique int child: @php_enum_declaration_list_child_type ref +); + +php_enum_declaration_list_def( + unique int id: @php_enum_declaration_list +); + +php_error_suppression_expression_def( + unique int id: @php_error_suppression_expression, + int child: @php_expression ref +); + +php_exit_statement_child( + unique int php_exit_statement: @php_exit_statement ref, + unique int child: @php_expression ref +); + +php_exit_statement_def( + unique int id: @php_exit_statement +); + +@php_expression = @php_assignment_expression | @php_augmented_assignment_expression | @php_binary_expression | @php_cast_expression | @php_clone_expression | @php_conditional_expression | @php_error_suppression_expression | @php_include_expression | @php_include_once_expression | @php_match_expression | @php_primary_expression | @php_reference_assignment_expression | @php_require_expression | @php_require_once_expression | @php_unary_op_expression | @php_yield_expression + +php_expression_statement_def( + unique int id: @php_expression_statement, + int child: @php_expression ref +); + +php_finally_clause_def( + unique int id: @php_finally_clause, + int body: @php_compound_statement ref +); + +#keyset[php_for_statement, index] +php_for_statement_body( + int php_for_statement: @php_for_statement ref, + int index: int ref, + unique int body: @php_statement ref +); + +@php_for_statement_condition_type = @php_expression | @php_sequence_expression + +php_for_statement_condition( + unique int php_for_statement: @php_for_statement ref, + unique int condition: @php_for_statement_condition_type ref +); + +@php_for_statement_initialize_type = @php_expression | @php_sequence_expression + +php_for_statement_initialize( + unique int php_for_statement: @php_for_statement ref, + unique int initialize: @php_for_statement_initialize_type ref +); + +@php_for_statement_update_type = @php_expression | @php_sequence_expression + +php_for_statement_update( + unique int php_for_statement: @php_for_statement ref, + unique int update: @php_for_statement_update_type ref +); + +php_for_statement_def( + unique int id: @php_for_statement +); + +@php_foreach_statement_body_type = @php_colon_block | @php_statement + +php_foreach_statement_body( + unique int php_foreach_statement: @php_foreach_statement ref, + unique int body: @php_foreach_statement_body_type ref +); + +@php_foreach_statement_child_type = @php_by_ref | @php_expression | @php_list_literal | @php_pair + +#keyset[php_foreach_statement, index] +php_foreach_statement_child( + int php_foreach_statement: @php_foreach_statement ref, + int index: int ref, + unique int child: @php_foreach_statement_child_type ref +); + +php_foreach_statement_def( + unique int id: @php_foreach_statement +); + +@php_formal_parameters_child_type = @php_property_promotion_parameter | @php_simple_parameter | @php_variadic_parameter + +#keyset[php_formal_parameters, index] +php_formal_parameters_child( + int php_formal_parameters: @php_formal_parameters ref, + int index: int ref, + unique int child: @php_formal_parameters_child_type ref +); + +php_formal_parameters_def( + unique int id: @php_formal_parameters +); + +@php_function_call_expression_function_type = @php_array_creation_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_variable_name + +php_function_call_expression_def( + unique int id: @php_function_call_expression, + int arguments: @php_arguments ref, + int function: @php_function_call_expression_function_type ref +); + +php_function_definition_attributes( + unique int php_function_definition: @php_function_definition ref, + unique int attributes: @php_attribute_list ref +); + +@php_function_definition_return_type_type = @php_token_bottom_type | @php_type__ + +php_function_definition_return_type( + unique int php_function_definition: @php_function_definition ref, + unique int return_type: @php_function_definition_return_type_type ref +); + +php_function_definition_child( + unique int php_function_definition: @php_function_definition ref, + unique int child: @php_token_reference_modifier ref +); + +php_function_definition_def( + unique int id: @php_function_definition, + int body: @php_compound_statement ref, + int name: @php_token_name ref, + int parameters: @php_formal_parameters ref +); + +#keyset[php_function_static_declaration, index] +php_function_static_declaration_child( + int php_function_static_declaration: @php_function_static_declaration ref, + int index: int ref, + unique int child: @php_static_variable_declaration ref +); + +php_function_static_declaration_def( + unique int id: @php_function_static_declaration +); + +@php_global_declaration_child_type = @php_dynamic_variable_name | @php_variable_name + +#keyset[php_global_declaration, index] +php_global_declaration_child( + int php_global_declaration: @php_global_declaration ref, + int index: int ref, + unique int child: @php_global_declaration_child_type ref +); + +php_global_declaration_def( + unique int id: @php_global_declaration +); + +php_goto_statement_def( + unique int id: @php_goto_statement, + int child: @php_token_name ref +); + +php_heredoc_value( + unique int php_heredoc: @php_heredoc ref, + unique int value: @php_heredoc_body ref +); + +php_heredoc_def( + unique int id: @php_heredoc, + int end_tag: @php_token_heredoc_end ref, + int identifier: @php_token_heredoc_start ref +); + +@php_heredoc_body_child_type = @php_dynamic_variable_name | @php_expression | @php_member_access_expression | @php_subscript_expression | @php_token_escape_sequence | @php_token_string_content | @php_variable_name + +#keyset[php_heredoc_body, index] +php_heredoc_body_child( + int php_heredoc_body: @php_heredoc_body ref, + int index: int ref, + unique int child: @php_heredoc_body_child_type ref +); + +php_heredoc_body_def( + unique int id: @php_heredoc_body +); + +@php_if_statement_alternative_type = @php_else_clause | @php_else_if_clause + +#keyset[php_if_statement, index] +php_if_statement_alternative( + int php_if_statement: @php_if_statement ref, + int index: int ref, + unique int alternative: @php_if_statement_alternative_type ref +); + +@php_if_statement_body_type = @php_colon_block | @php_statement + +php_if_statement_def( + unique int id: @php_if_statement, + int body: @php_if_statement_body_type ref, + int condition: @php_parenthesized_expression ref +); + +php_include_expression_def( + unique int id: @php_include_expression, + int child: @php_expression ref +); + +php_include_once_expression_def( + unique int id: @php_include_once_expression, + int child: @php_expression ref +); + +php_interface_declaration_attributes( + unique int php_interface_declaration: @php_interface_declaration ref, + unique int attributes: @php_attribute_list ref +); + +php_interface_declaration_child( + unique int php_interface_declaration: @php_interface_declaration ref, + unique int child: @php_base_clause ref +); + +php_interface_declaration_def( + unique int id: @php_interface_declaration, + int body: @php_declaration_list ref, + int name: @php_token_name ref +); + +@php_intersection_type_child_type = @php_named_type | @php_optional_type | @php_token_primitive_type + +#keyset[php_intersection_type, index] +php_intersection_type_child( + int php_intersection_type: @php_intersection_type ref, + int index: int ref, + unique int child: @php_intersection_type_child_type ref +); + +php_intersection_type_def( + unique int id: @php_intersection_type +); + +@php_list_literal_child_type = @php_by_ref | @php_dynamic_variable_name | @php_expression | @php_function_call_expression | @php_list_literal | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +#keyset[php_list_literal, index] +php_list_literal_child( + int php_list_literal: @php_list_literal ref, + int index: int ref, + unique int child: @php_list_literal_child_type ref +); + +php_list_literal_def( + unique int id: @php_list_literal +); + +@php_literal = @php_encapsed_string | @php_heredoc | @php_nowdoc | @php_string__ | @php_token_boolean | @php_token_float | @php_token_integer | @php_token_null + +@php_match_block_child_type = @php_match_conditional_expression | @php_match_default_expression + +#keyset[php_match_block, index] +php_match_block_child( + int php_match_block: @php_match_block ref, + int index: int ref, + unique int child: @php_match_block_child_type ref +); + +php_match_block_def( + unique int id: @php_match_block +); + +#keyset[php_match_condition_list, index] +php_match_condition_list_child( + int php_match_condition_list: @php_match_condition_list ref, + int index: int ref, + unique int child: @php_expression ref +); + +php_match_condition_list_def( + unique int id: @php_match_condition_list +); + +php_match_conditional_expression_def( + unique int id: @php_match_conditional_expression, + int conditional_expressions: @php_match_condition_list ref, + int return_expression: @php_expression ref +); + +php_match_default_expression_def( + unique int id: @php_match_default_expression, + int return_expression: @php_expression ref +); + +php_match_expression_def( + unique int id: @php_match_expression, + int body: @php_match_block ref, + int condition: @php_parenthesized_expression ref +); + +@php_member_access_expression_name_type = @php_dynamic_variable_name | @php_expression | @php_token_name | @php_variable_name + +@php_member_access_expression_object_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_variable_name + +php_member_access_expression_def( + unique int id: @php_member_access_expression, + int name: @php_member_access_expression_name_type ref, + int object: @php_member_access_expression_object_type ref +); + +@php_member_call_expression_name_type = @php_dynamic_variable_name | @php_expression | @php_token_name | @php_variable_name + +@php_member_call_expression_object_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_variable_name + +php_member_call_expression_def( + unique int id: @php_member_call_expression, + int arguments: @php_arguments ref, + int name: @php_member_call_expression_name_type ref, + int object: @php_member_call_expression_object_type ref +); + +php_method_declaration_attributes( + unique int php_method_declaration: @php_method_declaration ref, + unique int attributes: @php_attribute_list ref +); + +php_method_declaration_body( + unique int php_method_declaration: @php_method_declaration ref, + unique int body: @php_compound_statement ref +); + +@php_method_declaration_return_type_type = @php_token_bottom_type | @php_type__ + +php_method_declaration_return_type( + unique int php_method_declaration: @php_method_declaration ref, + unique int return_type: @php_method_declaration_return_type_type ref +); + +@php_method_declaration_child_type = @php_token_abstract_modifier | @php_token_final_modifier | @php_token_readonly_modifier | @php_token_reference_modifier | @php_token_static_modifier | @php_token_var_modifier | @php_visibility_modifier + +#keyset[php_method_declaration, index] +php_method_declaration_child( + int php_method_declaration: @php_method_declaration ref, + int index: int ref, + unique int child: @php_method_declaration_child_type ref +); + +php_method_declaration_def( + unique int id: @php_method_declaration, + int name: @php_token_name ref, + int parameters: @php_formal_parameters ref +); + +php_named_label_statement_def( + unique int id: @php_named_label_statement, + int child: @php_token_name ref +); + +@php_named_type_child_type = @php_qualified_name | @php_token_name + +php_named_type_def( + unique int id: @php_named_type, + int child: @php_named_type_child_type ref +); + +php_namespace_definition_body( + unique int php_namespace_definition: @php_namespace_definition ref, + unique int body: @php_compound_statement ref +); + +php_namespace_definition_name( + unique int php_namespace_definition: @php_namespace_definition ref, + unique int name: @php_namespace_name ref +); + +php_namespace_definition_def( + unique int id: @php_namespace_definition +); + +#keyset[php_namespace_name, index] +php_namespace_name_child( + int php_namespace_name: @php_namespace_name ref, + int index: int ref, + unique int child: @php_token_name ref +); + +php_namespace_name_def( + unique int id: @php_namespace_name +); + +php_namespace_use_clause_alias( + unique int php_namespace_use_clause: @php_namespace_use_clause ref, + unique int alias: @php_token_name ref +); + +@php_namespace_use_clause_type_type = @php_reserved_word + +php_namespace_use_clause_type( + unique int php_namespace_use_clause: @php_namespace_use_clause ref, + unique int type__: @php_namespace_use_clause_type_type ref +); + +@php_namespace_use_clause_child_type = @php_qualified_name | @php_token_name + +php_namespace_use_clause_def( + unique int id: @php_namespace_use_clause, + int child: @php_namespace_use_clause_child_type ref +); + +php_namespace_use_declaration_body( + unique int php_namespace_use_declaration: @php_namespace_use_declaration ref, + unique int body: @php_namespace_use_group ref +); + +@php_namespace_use_declaration_type_type = @php_reserved_word + +php_namespace_use_declaration_type( + unique int php_namespace_use_declaration: @php_namespace_use_declaration ref, + unique int type__: @php_namespace_use_declaration_type_type ref +); + +@php_namespace_use_declaration_child_type = @php_namespace_name | @php_namespace_use_clause + +#keyset[php_namespace_use_declaration, index] +php_namespace_use_declaration_child( + int php_namespace_use_declaration: @php_namespace_use_declaration ref, + int index: int ref, + unique int child: @php_namespace_use_declaration_child_type ref +); + +php_namespace_use_declaration_def( + unique int id: @php_namespace_use_declaration +); + +#keyset[php_namespace_use_group, index] +php_namespace_use_group_child( + int php_namespace_use_group: @php_namespace_use_group ref, + int index: int ref, + unique int child: @php_namespace_use_clause ref +); + +php_namespace_use_group_def( + unique int id: @php_namespace_use_group +); + +php_nowdoc_value( + unique int php_nowdoc: @php_nowdoc ref, + unique int value: @php_nowdoc_body ref +); + +php_nowdoc_def( + unique int id: @php_nowdoc, + int end_tag: @php_token_heredoc_end ref, + int identifier: @php_token_heredoc_start ref +); + +#keyset[php_nowdoc_body, index] +php_nowdoc_body_child( + int php_nowdoc_body: @php_nowdoc_body ref, + int index: int ref, + unique int child: @php_token_nowdoc_string ref +); + +php_nowdoc_body_def( + unique int id: @php_nowdoc_body +); + +@php_nullsafe_member_access_expression_name_type = @php_dynamic_variable_name | @php_expression | @php_token_name | @php_variable_name + +@php_nullsafe_member_access_expression_object_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_variable_name + +php_nullsafe_member_access_expression_def( + unique int id: @php_nullsafe_member_access_expression, + int name: @php_nullsafe_member_access_expression_name_type ref, + int object: @php_nullsafe_member_access_expression_object_type ref +); + +@php_nullsafe_member_call_expression_name_type = @php_dynamic_variable_name | @php_expression | @php_token_name | @php_variable_name + +@php_nullsafe_member_call_expression_object_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_variable_name + +php_nullsafe_member_call_expression_def( + unique int id: @php_nullsafe_member_call_expression, + int arguments: @php_arguments ref, + int name: @php_nullsafe_member_call_expression_name_type ref, + int object: @php_nullsafe_member_call_expression_object_type ref +); + +@php_object_creation_expression_child_type = @php_anonymous_class | @php_arguments | @php_dynamic_variable_name | @php_member_access_expression | @php_nullsafe_member_access_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_property_access_expression | @php_subscript_expression | @php_token_name | @php_variable_name + +#keyset[php_object_creation_expression, index] +php_object_creation_expression_child( + int php_object_creation_expression: @php_object_creation_expression ref, + int index: int ref, + unique int child: @php_object_creation_expression_child_type ref +); + +php_object_creation_expression_def( + unique int id: @php_object_creation_expression +); + +@php_optional_type_child_type = @php_named_type | @php_token_primitive_type + +php_optional_type_def( + unique int id: @php_optional_type, + int child: @php_optional_type_child_type ref +); + +@php_pair_child_type = @php_by_ref | @php_expression | @php_list_literal + +#keyset[php_pair, index] +php_pair_child( + int php_pair: @php_pair ref, + int index: int ref, + unique int child: @php_pair_child_type ref +); + +php_pair_def( + unique int id: @php_pair +); + +php_parenthesized_expression_def( + unique int id: @php_parenthesized_expression, + int child: @php_expression ref +); + +@php_primary_expression = @php_anonymous_function | @php_array_creation_expression | @php_arrow_function | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_literal | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_print_intrinsic | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_shell_command_expression | @php_subscript_expression | @php_throw_expression | @php_token_name | @php_update_expression | @php_variable_name + +php_print_intrinsic_def( + unique int id: @php_print_intrinsic, + int child: @php_expression ref +); + +@php_program_child_type = @php_statement | @php_token_php_tag | @php_token_text + +#keyset[php_program, index] +php_program_child( + int php_program: @php_program ref, + int index: int ref, + unique int child: @php_program_child_type ref +); + +php_program_def( + unique int id: @php_program +); + +php_property_declaration_attributes( + unique int php_property_declaration: @php_property_declaration ref, + unique int attributes: @php_attribute_list ref +); + +php_property_declaration_type( + unique int php_property_declaration: @php_property_declaration ref, + unique int type__: @php_type__ ref +); + +@php_property_declaration_child_type = @php_property_element | @php_property_hook_list | @php_token_abstract_modifier | @php_token_final_modifier | @php_token_readonly_modifier | @php_token_static_modifier | @php_token_var_modifier | @php_visibility_modifier + +#keyset[php_property_declaration, index] +php_property_declaration_child( + int php_property_declaration: @php_property_declaration ref, + int index: int ref, + unique int child: @php_property_declaration_child_type ref +); + +php_property_declaration_def( + unique int id: @php_property_declaration +); + +php_property_element_default_value( + unique int php_property_element: @php_property_element ref, + unique int default_value: @php_expression ref +); + +php_property_element_def( + unique int id: @php_property_element, + int name: @php_variable_name ref +); + +php_property_hook_attributes( + unique int php_property_hook: @php_property_hook ref, + unique int attributes: @php_attribute_list ref +); + +@php_property_hook_body_type = @php_compound_statement | @php_expression + +php_property_hook_body( + unique int php_property_hook: @php_property_hook ref, + unique int body: @php_property_hook_body_type ref +); + +php_property_hook_final( + unique int php_property_hook: @php_property_hook ref, + unique int final: @php_token_final_modifier ref +); + +php_property_hook_parameters( + unique int php_property_hook: @php_property_hook ref, + unique int parameters: @php_formal_parameters ref +); + +php_property_hook_reference_modifier( + unique int php_property_hook: @php_property_hook ref, + unique int reference_modifier: @php_token_reference_modifier ref +); + +php_property_hook_def( + unique int id: @php_property_hook, + int child: @php_token_name ref +); + +#keyset[php_property_hook_list, index] +php_property_hook_list_child( + int php_property_hook_list: @php_property_hook_list ref, + int index: int ref, + unique int child: @php_property_hook ref +); + +php_property_hook_list_def( + unique int id: @php_property_hook_list +); + +php_property_promotion_parameter_attributes( + unique int php_property_promotion_parameter: @php_property_promotion_parameter ref, + unique int attributes: @php_attribute_list ref +); + +php_property_promotion_parameter_default_value( + unique int php_property_promotion_parameter: @php_property_promotion_parameter ref, + unique int default_value: @php_expression ref +); + +@php_property_promotion_parameter_name_type = @php_by_ref | @php_variable_name + +php_property_promotion_parameter_readonly( + unique int php_property_promotion_parameter: @php_property_promotion_parameter ref, + unique int readonly: @php_token_readonly_modifier ref +); + +php_property_promotion_parameter_type( + unique int php_property_promotion_parameter: @php_property_promotion_parameter ref, + unique int type__: @php_type__ ref +); + +php_property_promotion_parameter_child( + unique int php_property_promotion_parameter: @php_property_promotion_parameter ref, + unique int child: @php_property_hook_list ref +); + +php_property_promotion_parameter_def( + unique int id: @php_property_promotion_parameter, + int name: @php_property_promotion_parameter_name_type ref, + int visibility: @php_visibility_modifier ref +); + +@php_qualified_name_prefix_type = @php_namespace_name | @php_reserved_word + +#keyset[php_qualified_name, index] +php_qualified_name_prefix( + int php_qualified_name: @php_qualified_name ref, + int index: int ref, + unique int prefix: @php_qualified_name_prefix_type ref +); + +php_qualified_name_def( + unique int id: @php_qualified_name, + int child: @php_token_name ref +); + +@php_reference_assignment_expression_left_type = @php_cast_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_list_literal | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +php_reference_assignment_expression_def( + unique int id: @php_reference_assignment_expression, + int left: @php_reference_assignment_expression_left_type ref, + int right: @php_expression ref +); + +php_require_expression_def( + unique int id: @php_require_expression, + int child: @php_expression ref +); + +php_require_once_expression_def( + unique int id: @php_require_once_expression, + int child: @php_expression ref +); + +php_return_statement_child( + unique int php_return_statement: @php_return_statement ref, + unique int child: @php_expression ref +); + +php_return_statement_def( + unique int id: @php_return_statement +); + +@php_scoped_call_expression_name_type = @php_dynamic_variable_name | @php_expression | @php_token_name | @php_variable_name + +@php_scoped_call_expression_scope_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_token_relative_scope | @php_variable_name + +php_scoped_call_expression_def( + unique int id: @php_scoped_call_expression, + int arguments: @php_arguments ref, + int name: @php_scoped_call_expression_name_type ref, + int scope: @php_scoped_call_expression_scope_type ref +); + +@php_scoped_property_access_expression_name_type = @php_dynamic_variable_name | @php_variable_name + +@php_scoped_property_access_expression_scope_type = @php_array_creation_expression | @php_cast_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_name | @php_token_relative_scope | @php_variable_name + +php_scoped_property_access_expression_def( + unique int id: @php_scoped_property_access_expression, + int name: @php_scoped_property_access_expression_name_type ref, + int scope: @php_scoped_property_access_expression_scope_type ref +); + +@php_sequence_expression_child_type = @php_expression | @php_sequence_expression + +#keyset[php_sequence_expression, index] +php_sequence_expression_child( + int php_sequence_expression: @php_sequence_expression ref, + int index: int ref, + unique int child: @php_sequence_expression_child_type ref +); + +php_sequence_expression_def( + unique int id: @php_sequence_expression +); + +@php_shell_command_expression_child_type = @php_dynamic_variable_name | @php_expression | @php_member_access_expression | @php_subscript_expression | @php_token_escape_sequence | @php_token_string_content | @php_variable_name + +#keyset[php_shell_command_expression, index] +php_shell_command_expression_child( + int php_shell_command_expression: @php_shell_command_expression ref, + int index: int ref, + unique int child: @php_shell_command_expression_child_type ref +); + +php_shell_command_expression_def( + unique int id: @php_shell_command_expression +); + +php_simple_parameter_attributes( + unique int php_simple_parameter: @php_simple_parameter ref, + unique int attributes: @php_attribute_list ref +); + +php_simple_parameter_default_value( + unique int php_simple_parameter: @php_simple_parameter ref, + unique int default_value: @php_expression ref +); + +php_simple_parameter_reference_modifier( + unique int php_simple_parameter: @php_simple_parameter ref, + unique int reference_modifier: @php_token_reference_modifier ref +); + +php_simple_parameter_type( + unique int php_simple_parameter: @php_simple_parameter ref, + unique int type__: @php_type__ ref +); + +php_simple_parameter_def( + unique int id: @php_simple_parameter, + int name: @php_variable_name ref +); + +@php_statement = @php_break_statement | @php_class_declaration | @php_compound_statement | @php_const_declaration | @php_continue_statement | @php_declare_statement | @php_do_statement | @php_echo_statement | @php_enum_declaration | @php_exit_statement | @php_expression_statement | @php_for_statement | @php_foreach_statement | @php_function_definition | @php_function_static_declaration | @php_global_declaration | @php_goto_statement | @php_if_statement | @php_interface_declaration | @php_named_label_statement | @php_namespace_definition | @php_namespace_use_declaration | @php_return_statement | @php_switch_statement | @php_token_empty_statement | @php_trait_declaration | @php_try_statement | @php_unset_statement | @php_while_statement + +php_static_variable_declaration_value( + unique int php_static_variable_declaration: @php_static_variable_declaration ref, + unique int value: @php_expression ref +); + +php_static_variable_declaration_def( + unique int id: @php_static_variable_declaration, + int name: @php_variable_name ref +); + +@php_string_child_type = @php_token_escape_sequence | @php_token_string_content + +#keyset[php_string__, index] +php_string_child( + int php_string__: @php_string__ ref, + int index: int ref, + unique int child: @php_string_child_type ref +); + +php_string_def( + unique int id: @php_string__ +); + +@php_subscript_expression_child_type = @php_array_creation_expression | @php_class_constant_access_expression | @php_dynamic_variable_name | @php_encapsed_string | @php_expression | @php_function_call_expression | @php_heredoc | @php_member_access_expression | @php_member_call_expression | @php_nowdoc | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_parenthesized_expression | @php_qualified_name | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_string__ | @php_subscript_expression | @php_token_integer | @php_token_name | @php_variable_name + +#keyset[php_subscript_expression, index] +php_subscript_expression_child( + int php_subscript_expression: @php_subscript_expression ref, + int index: int ref, + unique int child: @php_subscript_expression_child_type ref +); + +php_subscript_expression_def( + unique int id: @php_subscript_expression +); + +@php_switch_block_child_type = @php_case_statement | @php_default_statement + +#keyset[php_switch_block, index] +php_switch_block_child( + int php_switch_block: @php_switch_block ref, + int index: int ref, + unique int child: @php_switch_block_child_type ref +); + +php_switch_block_def( + unique int id: @php_switch_block +); + +php_switch_statement_def( + unique int id: @php_switch_statement, + int body: @php_switch_block ref, + int condition: @php_parenthesized_expression ref +); + +@php_text_interpolation_child_type = @php_token_php_tag | @php_token_text + +#keyset[php_text_interpolation, index] +php_text_interpolation_child( + int php_text_interpolation: @php_text_interpolation ref, + int index: int ref, + unique int child: @php_text_interpolation_child_type ref +); + +php_text_interpolation_def( + unique int id: @php_text_interpolation +); + +php_throw_expression_def( + unique int id: @php_throw_expression, + int child: @php_expression ref +); + +php_trait_declaration_attributes( + unique int php_trait_declaration: @php_trait_declaration ref, + unique int attributes: @php_attribute_list ref +); + +php_trait_declaration_def( + unique int id: @php_trait_declaration, + int body: @php_declaration_list ref, + int name: @php_token_name ref +); + +@php_try_statement_child_type = @php_catch_clause | @php_finally_clause + +#keyset[php_try_statement, index] +php_try_statement_child( + int php_try_statement: @php_try_statement ref, + int index: int ref, + unique int child: @php_try_statement_child_type ref +); + +php_try_statement_def( + unique int id: @php_try_statement, + int body: @php_compound_statement ref +); + +@php_type__ = @php_disjunctive_normal_form_type | @php_intersection_type | @php_named_type | @php_optional_type | @php_token_primitive_type | @php_union_type + +#keyset[php_type_list, index] +php_type_list_child( + int php_type_list: @php_type_list ref, + int index: int ref, + unique int child: @php_named_type ref +); + +php_type_list_def( + unique int id: @php_type_list +); + +php_unary_op_expression_argument( + unique int php_unary_op_expression: @php_unary_op_expression ref, + unique int argument: @php_expression ref +); + +@php_unary_op_expression_operator_type = @php_reserved_word + +php_unary_op_expression_operator( + unique int php_unary_op_expression: @php_unary_op_expression ref, + unique int operator: @php_unary_op_expression_operator_type ref +); + +php_unary_op_expression_child( + unique int php_unary_op_expression: @php_unary_op_expression ref, + unique int child: @php_token_integer ref +); + +php_unary_op_expression_def( + unique int id: @php_unary_op_expression +); + +@php_union_type_child_type = @php_named_type | @php_optional_type | @php_token_primitive_type + +#keyset[php_union_type, index] +php_union_type_child( + int php_union_type: @php_union_type ref, + int index: int ref, + unique int child: @php_union_type_child_type ref +); + +php_union_type_def( + unique int id: @php_union_type +); + +@php_unset_statement_child_type = @php_cast_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +#keyset[php_unset_statement, index] +php_unset_statement_child( + int php_unset_statement: @php_unset_statement ref, + int index: int ref, + unique int child: @php_unset_statement_child_type ref +); + +php_unset_statement_def( + unique int id: @php_unset_statement +); + +@php_update_expression_argument_type = @php_cast_expression | @php_dynamic_variable_name | @php_function_call_expression | @php_member_access_expression | @php_member_call_expression | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_subscript_expression | @php_variable_name + +case @php_update_expression.operator of + 0 = @php_update_expression_plusplus +| 1 = @php_update_expression_minusminus +; + + +php_update_expression_def( + unique int id: @php_update_expression, + int argument: @php_update_expression_argument_type ref, + int operator: int ref +); + +@php_use_as_clause_child_type = @php_class_constant_access_expression | @php_token_name | @php_visibility_modifier + +#keyset[php_use_as_clause, index] +php_use_as_clause_child( + int php_use_as_clause: @php_use_as_clause ref, + int index: int ref, + unique int child: @php_use_as_clause_child_type ref +); + +php_use_as_clause_def( + unique int id: @php_use_as_clause +); + +@php_use_declaration_child_type = @php_qualified_name | @php_token_name | @php_use_list + +#keyset[php_use_declaration, index] +php_use_declaration_child( + int php_use_declaration: @php_use_declaration ref, + int index: int ref, + unique int child: @php_use_declaration_child_type ref +); + +php_use_declaration_def( + unique int id: @php_use_declaration +); + +@php_use_instead_of_clause_child_type = @php_class_constant_access_expression | @php_token_name + +#keyset[php_use_instead_of_clause, index] +php_use_instead_of_clause_child( + int php_use_instead_of_clause: @php_use_instead_of_clause ref, + int index: int ref, + unique int child: @php_use_instead_of_clause_child_type ref +); + +php_use_instead_of_clause_def( + unique int id: @php_use_instead_of_clause +); + +@php_use_list_child_type = @php_use_as_clause | @php_use_instead_of_clause + +#keyset[php_use_list, index] +php_use_list_child( + int php_use_list: @php_use_list ref, + int index: int ref, + unique int child: @php_use_list_child_type ref +); + +php_use_list_def( + unique int id: @php_use_list +); + +php_variable_name_def( + unique int id: @php_variable_name, + int child: @php_token_name ref +); + +php_variadic_parameter_attributes( + unique int php_variadic_parameter: @php_variadic_parameter ref, + unique int attributes: @php_attribute_list ref +); + +php_variadic_parameter_reference_modifier( + unique int php_variadic_parameter: @php_variadic_parameter ref, + unique int reference_modifier: @php_token_reference_modifier ref +); + +php_variadic_parameter_type( + unique int php_variadic_parameter: @php_variadic_parameter ref, + unique int type__: @php_type__ ref +); + +php_variadic_parameter_def( + unique int id: @php_variadic_parameter, + int name: @php_variable_name ref +); + +php_variadic_unpacking_def( + unique int id: @php_variadic_unpacking, + int child: @php_expression ref +); + +php_visibility_modifier_child( + unique int php_visibility_modifier: @php_visibility_modifier ref, + unique int child: @php_token_operation ref +); + +php_visibility_modifier_def( + unique int id: @php_visibility_modifier +); + +@php_while_statement_body_type = @php_colon_block | @php_statement + +php_while_statement_def( + unique int id: @php_while_statement, + int body: @php_while_statement_body_type ref, + int condition: @php_parenthesized_expression ref +); + +@php_yield_expression_child_type = @php_array_element_initializer | @php_expression + +php_yield_expression_child( + unique int php_yield_expression: @php_yield_expression ref, + unique int child: @php_yield_expression_child_type ref +); + +php_yield_expression_def( + unique int id: @php_yield_expression +); + +php_tokeninfo( + unique int id: @php_token, + int kind: int ref, + string value: string ref +); + +case @php_token.kind of + 0 = @php_reserved_word +| 1 = @php_token_abstract_modifier +| 2 = @php_token_boolean +| 3 = @php_token_bottom_type +| 4 = @php_token_cast_type +| 5 = @php_token_comment +| 6 = @php_token_empty_statement +| 7 = @php_token_escape_sequence +| 8 = @php_token_final_modifier +| 9 = @php_token_float +| 10 = @php_token_heredoc_end +| 11 = @php_token_heredoc_start +| 12 = @php_token_integer +| 13 = @php_token_name +| 14 = @php_token_nowdoc_string +| 15 = @php_token_null +| 16 = @php_token_operation +| 17 = @php_token_php_tag +| 18 = @php_token_primitive_type +| 19 = @php_token_readonly_modifier +| 20 = @php_token_reference_modifier +| 21 = @php_token_relative_scope +| 22 = @php_token_static_modifier +| 23 = @php_token_string_content +| 24 = @php_token_text +| 25 = @php_token_var_modifier +| 26 = @php_token_variadic_placeholder +; + + +@php_ast_node = @php_anonymous_class | @php_anonymous_function | @php_anonymous_function_use_clause | @php_argument | @php_arguments | @php_array_creation_expression | @php_array_element_initializer | @php_arrow_function | @php_assignment_expression | @php_attribute | @php_attribute_group | @php_attribute_list | @php_augmented_assignment_expression | @php_base_clause | @php_binary_expression | @php_break_statement | @php_by_ref | @php_case_statement | @php_cast_expression | @php_catch_clause | @php_class_constant_access_expression | @php_class_declaration | @php_class_interface_clause | @php_clone_expression | @php_colon_block | @php_compound_statement | @php_conditional_expression | @php_const_declaration | @php_const_element | @php_continue_statement | @php_declaration_list | @php_declare_directive | @php_declare_statement | @php_default_statement | @php_disjunctive_normal_form_type | @php_do_statement | @php_dynamic_variable_name | @php_echo_statement | @php_else_clause | @php_else_if_clause | @php_encapsed_string | @php_enum_case | @php_enum_declaration | @php_enum_declaration_list | @php_error_suppression_expression | @php_exit_statement | @php_expression_statement | @php_finally_clause | @php_for_statement | @php_foreach_statement | @php_formal_parameters | @php_function_call_expression | @php_function_definition | @php_function_static_declaration | @php_global_declaration | @php_goto_statement | @php_heredoc | @php_heredoc_body | @php_if_statement | @php_include_expression | @php_include_once_expression | @php_interface_declaration | @php_intersection_type | @php_list_literal | @php_match_block | @php_match_condition_list | @php_match_conditional_expression | @php_match_default_expression | @php_match_expression | @php_member_access_expression | @php_member_call_expression | @php_method_declaration | @php_named_label_statement | @php_named_type | @php_namespace_definition | @php_namespace_name | @php_namespace_use_clause | @php_namespace_use_declaration | @php_namespace_use_group | @php_nowdoc | @php_nowdoc_body | @php_nullsafe_member_access_expression | @php_nullsafe_member_call_expression | @php_object_creation_expression | @php_optional_type | @php_pair | @php_parenthesized_expression | @php_print_intrinsic | @php_program | @php_property_declaration | @php_property_element | @php_property_hook | @php_property_hook_list | @php_property_promotion_parameter | @php_qualified_name | @php_reference_assignment_expression | @php_require_expression | @php_require_once_expression | @php_return_statement | @php_scoped_call_expression | @php_scoped_property_access_expression | @php_sequence_expression | @php_shell_command_expression | @php_simple_parameter | @php_static_variable_declaration | @php_string__ | @php_subscript_expression | @php_switch_block | @php_switch_statement | @php_text_interpolation | @php_throw_expression | @php_token | @php_trait_declaration | @php_try_statement | @php_type_list | @php_unary_op_expression | @php_union_type | @php_unset_statement | @php_update_expression | @php_use_as_clause | @php_use_declaration | @php_use_instead_of_clause | @php_use_list | @php_variable_name | @php_variadic_parameter | @php_variadic_unpacking | @php_visibility_modifier | @php_while_statement | @php_yield_expression + +php_ast_node_location( + unique int node: @php_ast_node ref, + int loc: @location_default ref +); + +#keyset[parent, parent_index] +php_ast_node_parent( + unique int node: @php_ast_node ref, + int parent: @php_ast_node ref, + int parent_index: int ref +); + diff --git a/php/ql/lib/php.dbscheme.stats b/php/ql/lib/php.dbscheme.stats new file mode 100644 index 000000000000..092745c9c85e --- /dev/null +++ b/php/ql/lib/php.dbscheme.stats @@ -0,0 +1,4 @@ + + + + diff --git a/php/ql/lib/qlpack.yml b/php/ql/lib/qlpack.yml new file mode 100644 index 000000000000..ada8c4b424d7 --- /dev/null +++ b/php/ql/lib/qlpack.yml @@ -0,0 +1,10 @@ +name: codeql/php-all +version: 0.0.1-dev +groups: php +extractor: php +dbscheme: php.dbscheme +library: true +dependencies: + codeql/tutorial: ${workspace} + codeql/util: ${workspace} +warnOnImplicitThis: true diff --git a/php/ql/src/Security/AssertWithStringArgument.ql b/php/ql/src/Security/AssertWithStringArgument.ql new file mode 100644 index 000000000000..c8d3eb695be5 --- /dev/null +++ b/php/ql/src/Security/AssertWithStringArgument.ql @@ -0,0 +1,20 @@ +/** + * @name Assert with string argument + * @description Calling `assert` with a string argument can be dangerous because it may evaluate the string as code. + * @kind problem + * @problem.severity warning + * @precision high + * @id php/assert-string-argument + * @tags security + */ + +import codeql.php.ast.Calls + +from FunctionCall call +where + call.getCalleeName() = "assert" and + exists(Php::Expression arg0 | + arg0 = call.getArgumentExpr(0) and + (arg0 instanceof Php::String or arg0 instanceof Php::EncapsedString) + ) +select call, "Call to 'assert' with a string argument." diff --git a/php/ql/src/Security/DangerousBuiltinCall.ql b/php/ql/src/Security/DangerousBuiltinCall.ql new file mode 100644 index 000000000000..4ceda914d7dd --- /dev/null +++ b/php/ql/src/Security/DangerousBuiltinCall.ql @@ -0,0 +1,15 @@ +/** + * @name Call to dangerous PHP built-in + * @description A call to a PHP built-in that is commonly dangerous when used with untrusted input. + * @kind problem + * @problem.severity warning + * @precision high + * @id php/dangerous-builtin-call + * @tags security + */ + +import codeql.php.ast.Calls + +from FunctionCall call +where call.getCalleeName() in ["eval", "assert", "unserialize", "system", "exec"] +select call, "Use of dangerous PHP built-in: '" + call.getCalleeName() + "'." diff --git a/php/ql/src/Security/TaintedDangerousBuiltinCall.ql b/php/ql/src/Security/TaintedDangerousBuiltinCall.ql new file mode 100644 index 000000000000..2b2cde01d23d --- /dev/null +++ b/php/ql/src/Security/TaintedDangerousBuiltinCall.ql @@ -0,0 +1,17 @@ +/** + * @name Dangerous builtin called with untrusted input + * @description Finds calls to dangerous builtins where at least one argument directly uses a PHP superglobal. + * @kind problem + * @problem.severity warning + * @id php/security/tainted-dangerous-builtin-call + */ + +import codeql.php.ast.Calls +import codeql.php.security.Sinks +import codeql.php.security.Taint + +from FunctionCall call +where + PhpSecuritySinks::isDangerousBuiltinCall(call) and + PhpSecurityTaint::hasTaintedArgument(call) +select call, "This dangerous builtin is called with an argument that directly uses a superglobal." diff --git a/php/ql/src/change-notes/2025-12-17-php-mvp.md b/php/ql/src/change-notes/2025-12-17-php-mvp.md new file mode 100644 index 000000000000..c894bbd9206f --- /dev/null +++ b/php/ql/src/change-notes/2025-12-17-php-mvp.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added initial PHP query support, including a small call abstraction library, basic source/sink modeling, and starter security queries. diff --git a/php/ql/src/codeql-pack.lock.yml b/php/ql/src/codeql-pack.lock.yml new file mode 100644 index 000000000000..53004274575d --- /dev/null +++ b/php/ql/src/codeql-pack.lock.yml @@ -0,0 +1,4 @@ +--- +lockVersion: 1.0.0 +dependencies: {} +compiled: false diff --git a/php/ql/src/codeql-suites/php-code-scanning.qls b/php/ql/src/codeql-suites/php-code-scanning.qls new file mode 100644 index 000000000000..217654d48fab --- /dev/null +++ b/php/ql/src/codeql-suites/php-code-scanning.qls @@ -0,0 +1,4 @@ +- description: Standard Code Scanning queries for PHP +- queries: . +- apply: code-scanning-selectors.yml + from: codeql/suite-helpers diff --git a/php/ql/src/qlpack.yml b/php/ql/src/qlpack.yml new file mode 100644 index 000000000000..39403ab4336d --- /dev/null +++ b/php/ql/src/qlpack.yml @@ -0,0 +1,12 @@ +name: codeql/php-queries +version: 0.0.1-dev +groups: + - php + - queries +suites: codeql-suites +defaultSuiteFile: codeql-suites/php-code-scanning.qls +dependencies: + codeql/php-all: ${workspace} + codeql/suite-helpers: ${workspace} + codeql/util: ${workspace} +warnOnImplicitThis: true diff --git a/php/ql/test/qlpack.yml b/php/ql/test/qlpack.yml new file mode 100644 index 000000000000..07089115fe17 --- /dev/null +++ b/php/ql/test/qlpack.yml @@ -0,0 +1,8 @@ +name: codeql/php-tests +groups: [php, test] +dependencies: + codeql/php-queries: ${workspace} + codeql/php-all: ${workspace} +extractor: php +tests: . +warnOnImplicitThis: true diff --git a/php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.expected b/php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.expected new file mode 100644 index 000000000000..42673bac4e11 --- /dev/null +++ b/php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.expected @@ -0,0 +1,2 @@ +| FunctionCallExpression | Call to 'assert' with a string argument. | +| FunctionCallExpression | Call to 'assert' with a string argument. | diff --git a/php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.php b/php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.php new file mode 100644 index 000000000000..64e116fd1d5a --- /dev/null +++ b/php/ql/test/query-tests/Security/AssertWithStringArgument/AssertWithStringArgument.php @@ -0,0 +1,7 @@ +