Compare commits

...

3 Commits

Author SHA1 Message Date
Josef Svenningsson
77dc871b21 Use SSA and type-aware dispatch in the PHP extractor 2026-03-06 09:52:03 +00:00
Josef Svenningsson
57ff0bb2c8 Improve the PHP dataflow analysis and add queries 2026-03-05 17:02:06 +00:00
Josef Svenningsson
cea862bfb3 PHP extractor and query library, built with AI
This is built with copilot, via a number
of iterations and run various test. But it should
by no means be considered production ready. I'm
looking for feeback on how to take this forward.
2026-03-05 17:02:05 +00:00
71 changed files with 9705 additions and 0 deletions

27
Cargo.lock generated
View File

@@ -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"

View File

@@ -4,6 +4,7 @@
resolver = "2"
members = [
"shared/tree-sitter-extractor",
"php/extractor",
"ruby/extractor",
"rust/extractor",
"rust/extractor/macros",

59
php/BUILD.bazel Normal file
View File

@@ -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",
],
)

36
php/codeql-extractor.yml Normal file
View File

@@ -0,0 +1,36 @@
name: "php"
display_name: "PHP"
version: 0.1.0
column_kind: "utf8"
legacy_qltest_extraction: true
build_modes:
- none
github_api_languages:
- PHP
scc_languages:
- PHP
file_types:
- name: php
display_name: PHP files
extensions:
- .php
- .phtml
- .php3
- .php4
- .php5
- .php7
- .phps
- .inc
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)$"

19
php/extractor/BUILD.bazel Normal file
View File

@@ -0,0 +1,19 @@
load("//misc/bazel:rust.bzl", "codeql_rust_binary")
load("//misc/bazel/3rdparty/tree_sitter_extractors_deps:defs.bzl", "aliases", "all_crate_deps")
exports_files(["Cargo.toml"])
codeql_rust_binary(
name = "extractor",
srcs = glob(["src/*.rs"]),
aliases = aliases(),
proc_macro_deps = all_crate_deps(
proc_macro = True,
),
visibility = ["//visibility:public"],
deps = all_crate_deps(
normal = True,
) + [
"//shared/tree-sitter-extractor",
],
)

21
php/extractor/Cargo.toml Normal file
View File

@@ -0,0 +1,21 @@
[package]
name = "codeql-extractor-php"
description = "CodeQL PHP extractor"
version = "0.1.0"
authors = ["GitHub"]
edition = "2024"
# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
[dependencies]
tree-sitter = ">= 0.23.0"
tree-sitter-php = "0.23.11"
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" }

View File

@@ -0,0 +1,20 @@
use std::env;
use std::path::PathBuf;
use clap::Args;
use codeql_extractor::autobuilder;
#[derive(Args)]
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", ".phtml", ".inc", ".php3", ".php4", ".php5", ".php7", ".phps"])
.exclude_globs(&["**/.git", "**/vendor"])
.size_limit("10m")
.run()
}

View File

@@ -0,0 +1,142 @@
use clap::Args;
use codeql_extractor::file_paths;
use rayon::prelude::*;
use std::collections::HashSet;
use std::fs;
use std::io::BufRead;
use std::path::PathBuf;
use tree_sitter::Language;
use codeql_extractor::{diagnostics, extractor, node_types, trap};
#[derive(Args)]
pub struct Options {
/// Sets a custom source archive 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,
}
fn get_overlay_changed_files() -> Option<HashSet<PathBuf>> {
let path = std::env::var("CODEQL_EXTRACTOR_PHP_OVERLAY_CHANGED_FILES").ok()?;
let contents = fs::read_to_string(path).ok()?;
Some(
contents
.lines()
.filter(|l| !l.is_empty())
.map(|l| PathBuf::from(l).canonicalize().unwrap_or_else(|_| PathBuf::from(l)))
.collect(),
)
}
pub fn run(options: Options) -> std::io::Result<()> {
extractor::set_tracing_level("php");
tracing::info!("PHP 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
}
};
tracing::info!(
"Using {} {}",
num_threads,
if num_threads == 1 {
"thread"
} else {
"threads"
}
);
let trap_compression =
match trap::Compression::from_env("CODEQL_EXTRACTOR_PHP_OPTION_TRAP_COMPRESSION") {
Ok(x) => x,
Err(e) => {
main_thread_logger.write(
main_thread_logger
.new_entry("configuration-error", "Configuration error")
.message("{}; using gzip.", &[diagnostics::MessageArg::Code(&e)])
.severity(diagnostics::Severity::Warning),
);
trap::Compression::Gzip
}
};
drop(main_thread_logger);
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.unwrap();
let 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<HashSet<PathBuf>> = get_overlay_changed_files();
let path_transformer = 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<Vec<String>> = std::io::BufReader::new(file_list).lines().collect();
let lines = lines?;
lines
.par_iter()
.try_for_each(|line| -> std::io::Result<()> {
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 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();
tracing::info!("extracting: {}", path.display());
extractor::extract(
&language,
"php",
&schema,
&mut diagnostics_writer,
&mut trap_writer,
path_transformer.as_ref(),
&path,
&source,
&[],
);
let trap_ext = format!(".{}", trap_compression.extension());
let trap_file = file_paths::path_for(&trap_dir, &path, &trap_ext, path_transformer.as_ref());
std::fs::create_dir_all(trap_file.parent().unwrap())?;
trap_writer
.write_to_file(&trap_file, trap_compression)
.unwrap_or_else(|e| {
tracing::error!("Failed to write trap file {}: {}", trap_file.display(), e);
});
std::fs::create_dir_all(src_archive_file.parent().unwrap())?;
std::fs::copy(&path, &src_archive_file)?;
Ok(())
})?;
tracing::info!("PHP extraction completed");
Ok(())
}

View File

@@ -0,0 +1,31 @@
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,
"run the PHP extractor generate command",
)
}

23
php/extractor/src/main.rs Normal file
View File

@@ -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),
}
}

1822
php/php.dbscheme Normal file

File diff suppressed because it is too large Load Diff

0
php/php.dbscheme.stats Normal file
View File

View File

@@ -0,0 +1,10 @@
/**
* Contains customizations to the standard library.
*
* This module is imported by `php.qll`, so any customizations defined here automatically
* apply to all queries.
*
* Typical examples of customizations include adding new subclasses of abstract classes such as
* the `Source` and `Sink` classes associated with the security queries to model frameworks
* that are not covered by the standard library.
*/

View File

@@ -0,0 +1,70 @@
/** Provides classes for working with locations. */
overlay[local]
module;
import files.FileSystem
/**
* A location as given by a file, a start line, a start column,
* an end line, and an end column.
*
* For more information about locations see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
class Location extends @location_default {
/** Gets the file for this location. */
File getFile() { locations_default(this, result, _, _, _, _) }
/** 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 the number of lines covered by this location. */
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
/** Gets a textual representation of this element. */
bindingset[this]
pragma[inline_late]
string toString() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
this.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
result = filepath + "@" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
)
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f |
locations_default(this, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
}
/** Holds if this location starts strictly before the specified location. */
pragma[inline]
predicate strictlyBefore(Location other) {
this.getStartLine() < other.getStartLine()
or
this.getStartLine() = other.getStartLine() and this.getStartColumn() < other.getStartColumn()
}
}
/** An entity representing an empty location. */
class EmptyLocation extends Location {
EmptyLocation() { empty_location(this) }
}

View File

@@ -0,0 +1,38 @@
/** Provides classes for working with files and folders. */
overlay[local]
module;
private import codeql.Locations
private import codeql.util.FileSystem
private module Input implements InputSig {
abstract class ContainerBase extends @container {
abstract string getAbsolutePath();
ContainerBase getParentContainer() { containerparent(result, this) }
string toString() { result = this.getAbsolutePath() }
}
class FolderBase extends ContainerBase, @folder {
override string getAbsolutePath() { folders(this, result) }
}
class FileBase extends ContainerBase, @file {
override string getAbsolutePath() { files(this, result) }
}
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
}
private module Impl = Make<Input>;
class Container = Impl::Container;
class Folder = Impl::Folder;
/** A file. */
class File extends Container, Impl::File {
/** Holds if this file was extracted from ordinary source code. */
predicate fromSource() { any() }
}

View File

@@ -0,0 +1,72 @@
/**
* Provides classes representing the abstract syntax tree (AST) of PHP programs.
*/
import codeql.Locations
import ast.Call
import ast.Control
import ast.Expr
import ast.Literal
import ast.Function
import ast.ClassLike
import ast.Parameter
import ast.Statement
import ast.Variable
private import ast.internal.AST
private import ast.internal.TreeSitter
private import Customizations
/**
* A node in the abstract syntax tree. This class is the base class for all PHP
* program elements.
*/
class AstNode extends TPhpAstNode {
/**
* Gets the name of a primary CodeQL class to which this node belongs.
*/
string getAPrimaryQlClass() { result = "???" }
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to
* which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
/** Gets a textual representation of this node. */
cached
string toString() { none() }
/** Gets the location of this node. */
Location getLocation() { php_ast_node_location(this, result) }
/** Gets the file of this node. */
final File getFile() { result = this.getLocation().getFile() }
/** Gets a child node of this `AstNode`. */
AstNode getAChild() { php_ast_node_parent(result, this, _) }
/** Gets the `i`th child of this `AstNode`. */
AstNode getChild(int i) { php_ast_node_parent(result, this, i) }
/** Gets the parent of this `AstNode`, if this node is not a root node. */
AstNode getParent() { php_ast_node_parent(this, result, _) }
/** Gets the index of this node within its parent. */
int getIndex() { php_ast_node_parent(this, _, result) }
}
/** A PHP program (source file). */
class Program extends AstNode, @php_program {
override string getAPrimaryQlClass() { result = "Program" }
override string toString() { result = "program" }
/** Gets the `i`th statement in this program. */
Stmt getStatement(int i) { php_program_child(this, i, result) }
/** Gets a statement in this program. */
Stmt getAStatement() { result = this.getStatement(_) }
/** Gets the number of statements in this program. */
int getNumberOfStatements() { result = count(int i | php_program_child(this, i, _)) }
}

View File

@@ -0,0 +1,9 @@
/**
* Provides classes representing the control flow graph for PHP programs.
*
* This module re-exports the full CFG implementation from
* `codeql.php.controlflow.ControlFlowGraph` and `codeql.php.controlflow.BasicBlocks`.
*/
import codeql.php.controlflow.ControlFlowGraph
import codeql.php.controlflow.BasicBlocks

View File

@@ -0,0 +1,5 @@
/**
* Contains customizations to the PHP CodeQL library.
*/
import codeql.php.AST

View File

@@ -0,0 +1,17 @@
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) data flow analyses for PHP.
*/
import codeql.Locations
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) data flow analyses.
*/
module DataFlow {
private import codeql.php.dataflow.internal.DataFlowImplSpecific
private import codeql.dataflow.DataFlow
import DataFlowMake<Location, PhpDataFlow>
import Public
}

View File

@@ -0,0 +1,12 @@
/**
* Provides classes for performing local (intra-procedural) and
* global (inter-procedural) taint-tracking analyses for PHP.
*/
module TaintTracking {
import codeql.php.dataflow.internal.TaintTrackingPublic
private import codeql.php.dataflow.internal.DataFlowImplSpecific
private import codeql.php.dataflow.internal.TaintTrackingImplSpecific
private import codeql.dataflow.TaintTracking
private import codeql.Locations
import TaintFlowMake<Location, PhpDataFlow, PhpTaintTracking>
}

View File

@@ -0,0 +1,110 @@
/**
* Provides classes for PHP call expressions.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A call expression (function call, method call, or static method call). */
class Call extends Expr {
Call() {
this instanceof @php_function_call_expression or
this instanceof @php_member_call_expression or
this instanceof @php_nullsafe_member_call_expression or
this instanceof @php_scoped_call_expression
}
/** Gets the arguments of this call. */
Arguments getArguments() { none() }
/** Gets the `i`th argument expression (unwrapped from Argument wrapper). */
AstNode getArgument(int i) {
exists(@php_argument arg |
php_arguments_child(this.getArguments(), i, arg) and
php_argument_def(arg, result)
)
}
/** Gets an argument of this call. */
AstNode getAnArgument() { result = this.getArgument(_) }
/** Gets the number of arguments. */
int getNumberOfArguments() { result = this.getArguments().getNumberOfArguments() }
}
/** A function call expression (`func(...)` or `$var(...)`). */
class FunctionCallExpr extends Call, @php_function_call_expression {
override string getAPrimaryQlClass() { result = "FunctionCallExpr" }
/** Gets the function being called. */
AstNode getFunction() { php_function_call_expression_def(this, _, result) }
/** Gets the arguments list. */
override Arguments getArguments() { php_function_call_expression_def(this, result, _) }
/**
* Gets the name of the function being called, if it is a simple name.
*/
string getFunctionName() {
exists(Name n |
n = this.getFunction() and
result = n.getValue()
)
or
exists(QualifiedName qn |
qn = this.getFunction() and
result = qn.getValue()
)
}
override string toString() { result = this.getFunctionName() + "(...)" }
}
/** A method call expression (`$obj->method(...)`). */
class MethodCallExpr extends Call, @php_member_call_expression {
override string getAPrimaryQlClass() { result = "MethodCallExpr" }
/** Gets the object on which the method is called. */
AstNode getObject() { php_member_call_expression_def(this, _, _, result) }
/** Gets the name of the method being called. */
Name getMethodName() { php_member_call_expression_def(this, _, result, _) }
/** Gets the arguments list. */
override Arguments getArguments() { php_member_call_expression_def(this, result, _, _) }
/** Gets the string name of the method being called. */
string getMethodNameString() { result = this.getMethodName().getValue() }
override string toString() { result = "...->(" + this.getMethodNameString() + ")(...)"}
}
/** A nullsafe method call expression (`$obj?->method(...)`). */
class NullsafeMethodCallExpr extends Call, @php_nullsafe_member_call_expression {
override string getAPrimaryQlClass() { result = "NullsafeMethodCallExpr" }
AstNode getObject() { php_nullsafe_member_call_expression_def(this, _, _, result) }
Name getMethodName() { php_nullsafe_member_call_expression_def(this, _, result, _) }
override Arguments getArguments() { php_nullsafe_member_call_expression_def(this, result, _, _) }
string getMethodNameString() { result = this.getMethodName().getValue() }
override string toString() { result = "...?->(" + this.getMethodNameString() + ")(...)"}
}
/** A scoped (static) call expression (`ClassName::method(...)`). */
class ScopedCallExpr extends Call, @php_scoped_call_expression {
override string getAPrimaryQlClass() { result = "ScopedCallExpr" }
AstNode getScope() { php_scoped_call_expression_def(this, _, _, result) }
Name getMethodName() { php_scoped_call_expression_def(this, _, result, _) }
override Arguments getArguments() { php_scoped_call_expression_def(this, result, _, _) }
string getMethodNameString() { result = this.getMethodName().getValue() }
override string toString() { result = "...::(" + this.getMethodNameString() + ")(...)"}
}

View File

@@ -0,0 +1,178 @@
/**
* Provides classes for PHP class-like declarations (classes, interfaces, traits, enums).
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A class-like declaration (class, interface, trait, or enum). */
class ClassLike extends Stmt {
ClassLike() {
this instanceof ClassDecl or
this instanceof InterfaceDecl or
this instanceof TraitDecl or
this instanceof EnumDecl
}
/** Gets the name of this class-like declaration. */
Name getName() { none() }
/** Gets the string name. */
string getNameString() {
result = this.getName().getValue()
}
}
/** A class declaration. */
class ClassDecl extends Stmt, @php_class_declaration {
override string getAPrimaryQlClass() { result = "ClassDecl" }
/** Gets the name. */
Name getName() { php_class_declaration_def(this, _, result) }
/** Gets the string name. */
string getNameString() { result = this.getName().getValue() }
/** Gets the declaration list (body). */
DeclarationList getBody() { php_class_declaration_def(this, result, _) }
/** Gets the base clause (extends). */
BaseClause getBaseClause() { php_class_declaration_child(this, _, result) }
/** Gets the interface implementation clause. */
ClassInterfaceClause getInterfaceClause() { php_class_declaration_child(this, _, result) }
/** Holds if this class extends another class. */
predicate hasBaseClass() { exists(this.getBaseClause()) }
override string toString() { result = "class " + this.getNameString() }
}
/** A base clause (`extends ClassName`). */
class BaseClause extends AstNode, @php_base_clause {
override string getAPrimaryQlClass() { result = "BaseClause" }
override AstNode getChild(int i) { php_base_clause_child(this, i, result) }
override string toString() { result = "extends ..." }
}
/** A class interface clause (`implements InterfaceName, ...`). */
class ClassInterfaceClause extends AstNode, @php_class_interface_clause {
override string getAPrimaryQlClass() { result = "ClassInterfaceClause" }
AstNode getInterface(int i) { php_class_interface_clause_child(this, i, result) }
AstNode getAnInterface() { result = this.getInterface(_) }
override string toString() { result = "implements ..." }
}
/** A declaration list (class body). */
class DeclarationList extends AstNode, @php_declaration_list {
override string getAPrimaryQlClass() { result = "DeclarationList" }
AstNode getMember(int i) { php_declaration_list_child(this, i, result) }
AstNode getAMember() { result = this.getMember(_) }
override string toString() { result = "{ ... }" }
}
/** An interface declaration. */
class InterfaceDecl extends Stmt, @php_interface_declaration {
override string getAPrimaryQlClass() { result = "InterfaceDecl" }
Name getName() { php_interface_declaration_def(this, _, result) }
string getNameString() { result = this.getName().getValue() }
DeclarationList getBody() { php_interface_declaration_def(this, result, _) }
BaseClause getBaseClause() { php_interface_declaration_child(this, result) }
override string toString() { result = "interface " + this.getNameString() }
}
/** A trait declaration. */
class TraitDecl extends Stmt, @php_trait_declaration {
override string getAPrimaryQlClass() { result = "TraitDecl" }
Name getName() { php_trait_declaration_def(this, _, result) }
string getNameString() { result = this.getName().getValue() }
DeclarationList getBody() { php_trait_declaration_def(this, result, _) }
override string toString() { result = "trait " + this.getNameString() }
}
/** An enum declaration. */
class EnumDecl extends Stmt, @php_enum_declaration {
override string getAPrimaryQlClass() { result = "EnumDecl" }
Name getName() { php_enum_declaration_def(this, _, result) }
string getNameString() { result = this.getName().getValue() }
AstNode getBody() { php_enum_declaration_def(this, result, _) }
override string toString() { result = "enum " + this.getNameString() }
}
/** An enum case declaration. */
class EnumCase extends AstNode, @php_enum_case {
override string getAPrimaryQlClass() { result = "EnumCase" }
Name getName() { php_enum_case_def(this, result) }
Expr getValue() { php_enum_case_value(this, result) }
override string toString() { result = "case " + this.getName().getValue() }
}
/** A property declaration. */
class PropertyDecl extends AstNode, @php_property_declaration {
override string getAPrimaryQlClass() { result = "PropertyDecl" }
TypeNode getType() { php_property_declaration_type(this, result) }
override AstNode getChild(int i) { php_property_declaration_child(this, i, result) }
PropertyElement getAProperty() { php_property_declaration_child(this, _, result) }
override string toString() { result = "property declaration" }
}
/** A property element within a property declaration. */
class PropertyElement extends AstNode, @php_property_element {
override string getAPrimaryQlClass() { result = "PropertyElement" }
VariableName getName() { php_property_element_def(this, result) }
Expr getDefault() { php_property_element_default_value(this, result) }
predicate hasDefault() { exists(this.getDefault()) }
override string toString() { result = this.getName().getValue() }
}
/** A constant declaration. */
class ConstDecl extends AstNode, @php_const_declaration {
override string getAPrimaryQlClass() { result = "ConstDecl" }
AstNode getConstant(int i) { php_const_declaration_child(this, i, result) }
AstNode getAConstant() { result = this.getConstant(_) }
override string toString() { result = "const ..." }
}
/** A constant element. */
class ConstElement extends AstNode, @php_const_element {
override string getAPrimaryQlClass() { result = "ConstElement" }
override AstNode getChild(int i) { php_const_element_child(this, i, result) }
override string toString() { result = "const element" }
}

View File

@@ -0,0 +1,158 @@
/**
* Provides classes for PHP control flow statements.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** An if statement. */
class IfStmt extends Stmt, @php_if_statement {
override string getAPrimaryQlClass() { result = "IfStmt" }
/** Gets the condition (a parenthesized expression). */
AstNode getCondition() { php_if_statement_def(this, _, result) }
/** Gets the then branch. */
AstNode getThen() { php_if_statement_def(this, result, _) }
/** Gets the `i`th alternative (elseif or else clause). */
AstNode getAlternative(int i) { php_if_statement_alternative(this, i, result) }
/** Gets an alternative clause. */
AstNode getAnAlternative() { result = this.getAlternative(_) }
override string toString() { result = "if (...) ..." }
}
/** An elseif clause. */
class ElseIfClause extends AstNode, @php_else_if_clause {
override string getAPrimaryQlClass() { result = "ElseIfClause" }
AstNode getCondition() { php_else_if_clause_def(this, _, result) }
AstNode getBody() { php_else_if_clause_def(this, result, _) }
override string toString() { result = "elseif (...) ..." }
}
/** A switch statement. */
class SwitchStmt extends Stmt, @php_switch_statement {
override string getAPrimaryQlClass() { result = "SwitchStmt" }
AstNode getCondition() { php_switch_statement_def(this, _, result) }
override string toString() { result = "switch (...) ..." }
}
/** A case statement within a switch. */
class CaseStmt extends AstNode, @php_case_statement {
override string getAPrimaryQlClass() { result = "CaseStmt" }
Expr getValue() { php_case_statement_def(this, result) }
Stmt getStatement(int i) { php_case_statement_child(this, i, result) }
Stmt getAStatement() { result = this.getStatement(_) }
override string toString() { result = "case ...:" }
}
/** A default statement within a switch. */
class DefaultStmt extends AstNode, @php_default_statement {
override string getAPrimaryQlClass() { result = "DefaultStmt" }
Stmt getStatement(int i) { php_default_statement_child(this, i, result) }
Stmt getAStatement() { result = this.getStatement(_) }
override string toString() { result = "default:" }
}
/** A while statement. */
class WhileStmt extends Stmt, @php_while_statement {
override string getAPrimaryQlClass() { result = "WhileStmt" }
AstNode getCondition() { php_while_statement_def(this, _, result) }
AstNode getBody() { php_while_statement_def(this, result, _) }
override string toString() { result = "while (...) ..." }
}
/** A do-while statement. */
class DoWhileStmt extends Stmt, @php_do_statement {
override string getAPrimaryQlClass() { result = "DoWhileStmt" }
Stmt getBody() { php_do_statement_def(this, result, _) }
AstNode getCondition() { php_do_statement_def(this, _, result) }
override string toString() { result = "do ... while (...)" }
}
/** A for statement. */
class ForStmt extends Stmt, @php_for_statement {
override string getAPrimaryQlClass() { result = "ForStmt" }
AstNode getInitialize() { php_for_statement_initialize(this, result) }
AstNode getCondition() { php_for_statement_condition(this, result) }
AstNode getUpdate() { php_for_statement_update(this, result) }
Stmt getBodyStmt(int i) { php_for_statement_body(this, i, result) }
Stmt getABodyStmt() { result = this.getBodyStmt(_) }
override string toString() { result = "for (...) ..." }
}
/** A foreach statement. */
class ForeachStmt extends Stmt, @php_foreach_statement {
override string getAPrimaryQlClass() { result = "ForeachStmt" }
override AstNode getChild(int i) { php_foreach_statement_child(this, i, result) }
AstNode getBody() { php_foreach_statement_body(this, result) }
override string toString() { result = "foreach (...) ..." }
}
/** A try statement. */
class TryStmt extends Stmt, @php_try_statement {
override string getAPrimaryQlClass() { result = "TryStmt" }
CompoundStmt getBody() { php_try_statement_def(this, result) }
override AstNode getChild(int i) { php_try_statement_child(this, i, result) }
CatchClause getCatch(int i) { php_try_statement_child(this, i, result) }
CatchClause getACatch() { result = this.getCatch(_) }
FinallyClause getFinally() { php_try_statement_child(this, _, result) }
predicate hasFinally() { exists(this.getFinally()) }
override string toString() { result = "try { ... }" }
}
/** A catch clause. */
class CatchClause extends AstNode, @php_catch_clause {
override string getAPrimaryQlClass() { result = "CatchClause" }
CompoundStmt getBody() { php_catch_clause_def(this, result, _) }
VariableName getVariable() { php_catch_clause_name(this, result) }
override string toString() { result = "catch (...) { ... }" }
}
/** A finally clause. */
class FinallyClause extends AstNode, @php_finally_clause {
override string getAPrimaryQlClass() { result = "FinallyClause" }
CompoundStmt getBody() { php_finally_clause_def(this, result) }
override string toString() { result = "finally { ... }" }
}

View File

@@ -0,0 +1,342 @@
/**
* Provides classes for PHP expressions.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** An expression. */
class Expr extends AstNode, @php_expression {
override string getAPrimaryQlClass() { result = "Expr" }
}
/** An assignment expression (`$x = expr`). */
class AssignExpr extends Expr, @php_assignment_expression {
override string getAPrimaryQlClass() { result = "AssignExpr" }
/** Gets the left-hand side (target) of the assignment. */
AstNode getLeftOperand() { php_assignment_expression_def(this, result, _) }
/** Gets the right-hand side (value) of the assignment. */
Expr getRightOperand() { php_assignment_expression_def(this, _, result) }
override string toString() { result = "... = ..." }
}
/** A reference assignment expression (`$x =& expr`). */
class RefAssignExpr extends Expr, @php_reference_assignment_expression {
override string getAPrimaryQlClass() { result = "RefAssignExpr" }
Expr getLeftOperand() { php_reference_assignment_expression_def(this, result, _) }
Expr getRightOperand() { php_reference_assignment_expression_def(this, _, result) }
override string toString() { result = "... =& ..." }
}
/** An augmented assignment expression (`$x += expr`, `$x .= expr`, etc.). */
class AugmentedAssignExpr extends Expr, @php_augmented_assignment_expression {
override string getAPrimaryQlClass() { result = "AugmentedAssignExpr" }
AstNode getLeftOperand() { php_augmented_assignment_expression_def(this, result, _, _) }
string getOperator() { result = this.(Php::AugmentedAssignmentExpression).getOperator() }
Expr getRightOperand() { php_augmented_assignment_expression_def(this, _, _, result) }
override string toString() { result = "... " + this.getOperator() + " ..." }
}
/** A binary expression (`$x + $y`, `$x . $y`, etc.). */
class BinaryExpr extends Expr, @php_binary_expression {
override string getAPrimaryQlClass() { result = "BinaryExpr" }
Expr getLeftOperand() { php_binary_expression_def(this, result, _, _) }
string getOperator() { result = this.(Php::BinaryExpression).getOperator() }
Expr getRightOperand() { php_binary_expression_def(this, _, _, result) }
override string toString() { result = "... " + this.getOperator() + " ..." }
}
/** A unary expression (`!$x`, `-$x`, `~$x`). */
class UnaryExpr extends Expr, @php_unary_op_expression {
override string getAPrimaryQlClass() { result = "UnaryExpr" }
string getOperator() {
exists(AstNode op |
php_unary_op_expression_operator(this, op) and
php_tokeninfo(op, _, result)
)
}
Expr getOperand() { php_unary_op_expression_argument(this, result) }
override string toString() { result = this.getOperator() + "..." }
}
/** An update expression (`$x++`, `$x--`, `++$x`, `--$x`). */
class UpdateExpr extends Expr, @php_update_expression {
override string getAPrimaryQlClass() { result = "UpdateExpr" }
AstNode getArgument() { php_update_expression_def(this, result, _) }
string getOperator() { result = this.(Php::UpdateExpression).getOperator() }
predicate isPrefix() { this.(Php::UpdateExpression).toString() = this.(Php::UpdateExpression).toString() }
override string toString() { result = this.getOperator() + "..." }
}
/** A conditional (ternary) expression (`$x ? $y : $z`). */
class ConditionalExpr extends Expr, @php_conditional_expression {
override string getAPrimaryQlClass() { result = "ConditionalExpr" }
Expr getCondition() { php_conditional_expression_def(this, _, result) }
Expr getConsequence() { php_conditional_expression_body(this, result) }
Expr getAlternative() { php_conditional_expression_def(this, result, _) }
override string toString() { result = "... ? ... : ..." }
}
/** A cast expression (`(int)$x`, `(string)$x`, etc.). */
class CastExpr extends Expr, @php_cast_expression {
override string getAPrimaryQlClass() { result = "CastExpr" }
AstNode getCastType() { php_cast_expression_def(this, result, _) }
AstNode getValue() { php_cast_expression_def(this, _, result) }
override string toString() { result = "(cast)..." }
}
/** An error suppression expression (`@expr`). */
class ErrorSuppressExpr extends Expr, @php_error_suppression_expression {
override string getAPrimaryQlClass() { result = "ErrorSuppressExpr" }
Expr getExpr() { php_error_suppression_expression_def(this, result) }
override string toString() { result = "@..." }
}
/** A clone expression (`clone $x`). */
class CloneExpr extends Expr, @php_clone_expression {
override string getAPrimaryQlClass() { result = "CloneExpr" }
Expr getExpr() { php_clone_expression_def(this, result) }
override string toString() { result = "clone ..." }
}
/** A throw expression (`throw $x`). */
class ThrowExpr extends Expr, @php_throw_expression {
override string getAPrimaryQlClass() { result = "ThrowExpr" }
Expr getExpr() { php_throw_expression_def(this, result) }
override string toString() { result = "throw ..." }
}
/** A parenthesized expression (`(expr)`). */
class ParenExpr extends Expr, @php_parenthesized_expression {
override string getAPrimaryQlClass() { result = "ParenExpr" }
Expr getExpr() { php_parenthesized_expression_def(this, result) }
override string toString() { result = "(...)" }
}
/** An array creation expression (`[1, 2, 3]` or `array(1, 2, 3)`). */
class ArrayCreationExpr extends Expr, @php_array_creation_expression {
override string getAPrimaryQlClass() { result = "ArrayCreationExpr" }
ArrayElementInitializer getElement(int i) {
php_array_creation_expression_child(this, i, result)
}
ArrayElementInitializer getAnElement() { result = this.getElement(_) }
int getNumberOfElements() {
result = count(int i | php_array_creation_expression_child(this, i, _))
}
override string toString() { result = "array(...)" }
}
/** An array element initializer. */
class ArrayElementInitializer extends AstNode, @php_array_element_initializer {
override string getAPrimaryQlClass() { result = "ArrayElementInitializer" }
override AstNode getChild(int i) { php_array_element_initializer_child(this, i, result) }
override string toString() { result = "... => ..." }
}
/** A subscript (array access) expression (`$x[0]`). */
class SubscriptExpr extends Expr, @php_subscript_expression {
override string getAPrimaryQlClass() { result = "SubscriptExpr" }
AstNode getObject() { php_subscript_expression_child(this, 0, result) }
AstNode getIndexExpr() { php_subscript_expression_child(this, 1, result) }
override string toString() { result = "...[...]" }
}
/** A member access expression (`$obj->prop`). */
class MemberAccessExpr extends Expr, @php_member_access_expression {
override string getAPrimaryQlClass() { result = "MemberAccessExpr" }
AstNode getObject() { php_member_access_expression_def(this, _, result) }
Name getName() { php_member_access_expression_def(this, result, _) }
override string toString() { result = "...->..." }
}
/** A nullsafe member access expression (`$obj?->prop`). */
class NullsafeMemberAccessExpr extends Expr, @php_nullsafe_member_access_expression {
override string getAPrimaryQlClass() { result = "NullsafeMemberAccessExpr" }
AstNode getObject() { php_nullsafe_member_access_expression_def(this, _, result) }
Name getName() { php_nullsafe_member_access_expression_def(this, result, _) }
override string toString() { result = "...?->..." }
}
/** A scoped property access expression (`ClassName::$prop`). */
class ScopedPropertyAccessExpr extends Expr, @php_scoped_property_access_expression {
override string getAPrimaryQlClass() { result = "ScopedPropertyAccessExpr" }
AstNode getScope() { php_scoped_property_access_expression_def(this, _, result) }
VariableName getName() { php_scoped_property_access_expression_def(this, result, _) }
override string toString() { result = "...::$..." }
}
/** A class constant access expression (`ClassName::CONST`). */
class ClassConstantAccessExpr extends Expr, @php_class_constant_access_expression {
override string getAPrimaryQlClass() { result = "ClassConstantAccessExpr" }
AstNode getScope() { php_class_constant_access_expression_child(this, 0, result) }
Name getName() { php_class_constant_access_expression_child(this, 1, result) }
override string toString() { result = "...::..." }
}
/** An `include` expression. */
class IncludeExpr extends Expr, @php_include_expression {
override string getAPrimaryQlClass() { result = "IncludeExpr" }
Expr getArgument() { php_include_expression_def(this, result) }
override string toString() { result = "include ..." }
}
/** An `include_once` expression. */
class IncludeOnceExpr extends Expr, @php_include_once_expression {
override string getAPrimaryQlClass() { result = "IncludeOnceExpr" }
Expr getArgument() { php_include_once_expression_def(this, result) }
override string toString() { result = "include_once ..." }
}
/** A `require` expression. */
class RequireExpr extends Expr, @php_require_expression {
override string getAPrimaryQlClass() { result = "RequireExpr" }
Expr getArgument() { php_require_expression_def(this, result) }
override string toString() { result = "require ..." }
}
/** A `require_once` expression. */
class RequireOnceExpr extends Expr, @php_require_once_expression {
override string getAPrimaryQlClass() { result = "RequireOnceExpr" }
Expr getArgument() { php_require_once_expression_def(this, result) }
override string toString() { result = "require_once ..." }
}
/** An object creation expression (`new ClassName(...)`). */
class ObjectCreationExpr extends Expr, @php_object_creation_expression {
override string getAPrimaryQlClass() { result = "ObjectCreationExpr" }
override AstNode getChild(int i) { php_object_creation_expression_child(this, i, result) }
override string toString() { result = "new ..." }
}
/** A `yield` expression. */
class YieldExpr extends Expr, @php_yield_expression {
override string getAPrimaryQlClass() { result = "YieldExpr" }
AstNode getChild() { php_yield_expression_child(this, result) }
override string toString() { result = "yield ..." }
}
/** A `print` expression. */
class PrintExpr extends Expr, @php_print_intrinsic {
override string getAPrimaryQlClass() { result = "PrintExpr" }
Expr getArgument() { php_print_intrinsic_def(this, result) }
override string toString() { result = "print ..." }
}
/** A shell command expression (backtick operator). */
class ShellCommandExpr extends Expr, @php_shell_command_expression {
override string getAPrimaryQlClass() { result = "ShellCommandExpr" }
/** Gets the i-th child element (interpolated parts). */
AstNode getElement(int i) { php_shell_command_expression_child(this, i, result) }
override string toString() { result = "`...`" }
}
/** A dynamic variable name expression (`$$var`). */
class DynamicVariableNameExpr extends Expr, @php_dynamic_variable_name {
override string getAPrimaryQlClass() { result = "DynamicVariableNameExpr" }
AstNode getNameExpr() { php_dynamic_variable_name_def(this, result) }
override string toString() { result = "$$..." }
}
/** A variadic unpacking expression (`...$arr`). */
class VariadicUnpackingExpr extends AstNode, @php_variadic_unpacking {
override string getAPrimaryQlClass() { result = "VariadicUnpackingExpr" }
Expr getExpr() { php_variadic_unpacking_def(this, result) }
override string toString() { result = "...expr" }
}
/** A match expression. */
class MatchExpr extends Expr, @php_match_expression {
override string getAPrimaryQlClass() { result = "MatchExpr" }
override string toString() { result = "match ..." }
}
/** An arguments list. */
class Arguments extends AstNode, @php_arguments {
override string getAPrimaryQlClass() { result = "Arguments" }
AstNode getArgument(int i) { php_arguments_child(this, i, result) }
AstNode getAnArgument() { result = this.getArgument(_) }
int getNumberOfArguments() { result = count(int i | php_arguments_child(this, i, _)) }
override string toString() { result = "(...)" }
}

View File

@@ -0,0 +1,121 @@
/**
* Provides classes for PHP functions, closures, and arrow functions.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A callable (function, method, closure, or arrow function). */
class Callable extends AstNode {
Callable() {
this instanceof FunctionDef or
this instanceof MethodDecl or
this instanceof AnonymousFunction or
this instanceof ArrowFunction
}
/** Gets the formal parameters node. */
FormalParameters getParameters() {
result = this.(FunctionDef).getParameters()
or
result = this.(MethodDecl).getParameters()
or
result = this.(AnonymousFunction).getParameters()
or
result = this.(ArrowFunction).getParameters()
}
/** Gets the `i`th parameter. */
Parameter getParameter(int i) { result = this.getParameters().getParameter(i) }
/** Gets a parameter. */
Parameter getAParameter() { result = this.getParameter(_) }
/** Gets the number of parameters. */
int getNumberOfParameters() { result = this.getParameters().getNumberOfParameters() }
}
/** A function definition. */
class FunctionDef extends Stmt, @php_function_definition {
override string getAPrimaryQlClass() { result = "FunctionDef" }
/** Gets the name of this function. */
Name getName() { php_function_definition_def(this, _, result, _) }
/** Gets the string name of this function. */
string getNameString() { result = this.getName().getValue() }
/** Gets the formal parameters. */
FormalParameters getParameters() { php_function_definition_def(this, _, _, result) }
/** Gets the body of this function. */
CompoundStmt getBody() { php_function_definition_def(this, result, _, _) }
/** Gets the return type annotation, if any. */
TypeNode getReturnType() { php_function_definition_return_type(this, result) }
override string toString() { result = "function " + this.getNameString() }
}
/** A method declaration within a class, interface, trait, or enum. */
class MethodDecl extends AstNode, @php_method_declaration {
override string getAPrimaryQlClass() { result = "MethodDecl" }
/** Gets the name. */
Name getName() { php_method_declaration_def(this, result, _) }
/** Gets the string name. */
string getNameString() { result = this.getName().getValue() }
/** Gets the formal parameters. */
FormalParameters getParameters() { php_method_declaration_def(this, _, result) }
/** Gets the body, if any (abstract methods have no body). */
CompoundStmt getBody() { php_method_declaration_body(this, result) }
/** Gets the return type annotation, if any. */
TypeNode getReturnType() { php_method_declaration_return_type(this, result) }
override string toString() { result = "method " + this.getNameString() }
}
/** An anonymous function (closure). */
class AnonymousFunction extends Expr, @php_anonymous_function {
override string getAPrimaryQlClass() { result = "AnonymousFunction" }
FormalParameters getParameters() { php_anonymous_function_def(this, _, result) }
CompoundStmt getBody() { php_anonymous_function_def(this, result, _) }
TypeNode getReturnType() { php_anonymous_function_return_type(this, result) }
override string toString() { result = "function (...) { ... }" }
}
/** An arrow function (`fn($x) => $x + 1`). */
class ArrowFunction extends Expr, @php_arrow_function {
override string getAPrimaryQlClass() { result = "ArrowFunction" }
FormalParameters getParameters() { php_arrow_function_def(this, _, result) }
Expr getBody() { php_arrow_function_def(this, result, _) }
TypeNode getReturnType() { php_arrow_function_return_type(this, result) }
override string toString() { result = "fn(...) => ..." }
}
/** A formal parameters list. */
class FormalParameters extends AstNode, @php_formal_parameters {
override string getAPrimaryQlClass() { result = "FormalParameters" }
AstNode getParameter(int i) { php_formal_parameters_child(this, i, result) }
AstNode getAParameter() { result = this.getParameter(_) }
int getNumberOfParameters() {
result = count(int i | php_formal_parameters_child(this, i, _))
}
override string toString() { result = "(...)" }
}

View File

@@ -0,0 +1,86 @@
/**
* Provides classes for PHP literal expressions.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A literal expression. */
class Literal extends Expr, @php_literal {
override string getAPrimaryQlClass() { result = "Literal" }
}
/** An integer literal. */
class IntegerLiteral extends Literal, @php_token_integer {
override string getAPrimaryQlClass() { result = "IntegerLiteral" }
/** Gets the string representation of the integer value. */
string getValue() { php_tokeninfo(this, _, result) }
override string toString() { result = this.getValue() }
}
/** A float literal. */
class FloatLiteral extends Literal, @php_token_float {
override string getAPrimaryQlClass() { result = "FloatLiteral" }
string getValue() { php_tokeninfo(this, _, result) }
override string toString() { result = this.getValue() }
}
/** A string literal. */
class StringLiteral extends Literal, @php_string__ {
override string getAPrimaryQlClass() { result = "StringLiteral" }
override string toString() { result = "\"...\"" }
}
/** An encapsed (interpolated) string. */
class EncapsedString extends Literal, @php_encapsed_string {
override string getAPrimaryQlClass() { result = "EncapsedString" }
/** Gets the i-th element (string content or interpolated expression). */
AstNode getElement(int i) { php_encapsed_string_child(this, i, result) }
/** Gets an element of this encapsed string. */
AstNode getAnElement() { result = this.getElement(_) }
override string toString() { result = "\"...\"" }
}
/** A heredoc string. */
class Heredoc extends Literal, @php_heredoc {
override string getAPrimaryQlClass() { result = "Heredoc" }
override string toString() { result = "<<<..." }
}
/** A nowdoc string. */
class Nowdoc extends Literal, @php_nowdoc {
override string getAPrimaryQlClass() { result = "Nowdoc" }
override string toString() { result = "<<<'...'" }
}
/** A boolean literal (`true` or `false`). */
class BooleanLiteral extends Literal, @php_token_boolean {
override string getAPrimaryQlClass() { result = "BooleanLiteral" }
string getValue() { php_tokeninfo(this, _, result) }
/** Holds if this is the `true` literal. */
predicate isTrue() { this.getValue().toLowerCase() = "true" }
/** Holds if this is the `false` literal. */
predicate isFalse() { this.getValue().toLowerCase() = "false" }
override string toString() { result = this.getValue() }
}
/** A null literal. */
class NullLiteral extends Literal, @php_token_null {
override string getAPrimaryQlClass() { result = "NullLiteral" }
override string toString() { result = "null" }
}

View File

@@ -0,0 +1,70 @@
/**
* Provides classes for PHP parameters.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A parameter in a function, method, closure, or arrow function. */
class Parameter extends AstNode {
Parameter() {
this instanceof SimpleParameter or
this instanceof VariadicParameter or
this instanceof PropertyPromotionParameter
}
/** Gets the name of this parameter as a variable name node. */
VariableName getVariableName() { none() }
/** Gets the string name of this parameter (including `$`). */
string getNameString() { result = this.getVariableName().getValue() }
/** Gets the type annotation, if any. */
TypeNode getType() { none() }
/** Gets the default value, if any. */
Expr getDefault() { none() }
/** Holds if this parameter has a default value. */
predicate hasDefault() { exists(this.getDefault()) }
}
/** A simple parameter (`$x` or `Type $x`). */
class SimpleParameter extends AstNode, @php_simple_parameter {
override string getAPrimaryQlClass() { result = "SimpleParameter" }
/** Gets the variable name. */
VariableName getVariableName() { php_simple_parameter_def(this, result) }
/** Gets the type annotation, if any. */
TypeNode getType() { php_simple_parameter_type(this, result) }
/** Gets the default value, if any. */
Expr getDefault() { php_simple_parameter_default_value(this, result) }
override string toString() { result = this.getVariableName().getValue() }
}
/** A variadic parameter (`...$args`). */
class VariadicParameter extends AstNode, @php_variadic_parameter {
override string getAPrimaryQlClass() { result = "VariadicParameter" }
VariableName getVariableName() { php_variadic_parameter_def(this, result) }
TypeNode getType() { php_variadic_parameter_type(this, result) }
override string toString() { result = "..." + this.getVariableName().getValue() }
}
/** A property promotion parameter (PHP 8.0+). */
class PropertyPromotionParameter extends AstNode, @php_property_promotion_parameter {
override string getAPrimaryQlClass() { result = "PropertyPromotionParameter" }
VariableName getVariableName() { php_property_promotion_parameter_def(this, result, _) }
TypeNode getType() { php_property_promotion_parameter_type(this, result) }
Expr getDefault() { php_property_promotion_parameter_default_value(this, result) }
override string toString() { result = this.getVariableName().getValue() }
}

View File

@@ -0,0 +1,160 @@
/**
* Provides classes for PHP statements.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A statement. */
class Stmt extends AstNode, @php_statement {
override string getAPrimaryQlClass() { result = "Stmt" }
}
/** An expression statement. */
class ExprStmt extends Stmt, @php_expression_statement {
override string getAPrimaryQlClass() { result = "ExprStmt" }
/** Gets the expression. */
Expr getExpr() { php_expression_statement_def(this, result) }
override string toString() { result = "...;" }
}
/** A compound (block) statement. */
class CompoundStmt extends Stmt, @php_compound_statement {
override string getAPrimaryQlClass() { result = "CompoundStmt" }
Stmt getStatement(int i) { php_compound_statement_child(this, i, result) }
Stmt getAStatement() { result = this.getStatement(_) }
int getNumberOfStatements() {
result = count(int i | php_compound_statement_child(this, i, _))
}
override string toString() { result = "{ ... }" }
}
/** An empty statement (`;`). */
class EmptyStmt extends Stmt, @php_token_empty_statement {
override string getAPrimaryQlClass() { result = "EmptyStmt" }
override string toString() { result = ";" }
}
/** A return statement. */
class ReturnStmt extends Stmt, @php_return_statement {
override string getAPrimaryQlClass() { result = "ReturnStmt" }
/** Gets the return value, if any. */
Expr getValue() { php_return_statement_child(this, result) }
/** Holds if this return statement has a value. */
predicate hasValue() { exists(this.getValue()) }
override string toString() { result = "return ..." }
}
/** A break statement. */
class BreakStmt extends Stmt, @php_break_statement {
override string getAPrimaryQlClass() { result = "BreakStmt" }
override string toString() { result = "break" }
}
/** A continue statement. */
class ContinueStmt extends Stmt, @php_continue_statement {
override string getAPrimaryQlClass() { result = "ContinueStmt" }
override string toString() { result = "continue" }
}
/** A goto statement. */
class GotoStmt extends Stmt, @php_goto_statement {
override string getAPrimaryQlClass() { result = "GotoStmt" }
Name getLabel() { php_goto_statement_def(this, result) }
override string toString() { result = "goto ..." }
}
/** A named label statement. */
class LabelStmt extends Stmt, @php_named_label_statement {
override string getAPrimaryQlClass() { result = "LabelStmt" }
Name getName() { php_named_label_statement_def(this, result) }
override string toString() { result = "label:" }
}
/** An echo statement. */
class EchoStmt extends Stmt, @php_echo_statement {
override string getAPrimaryQlClass() { result = "EchoStmt" }
/** Gets the child expression (may be a sequence_expression for multiple args). */
AstNode getExpression() { php_echo_statement_def(this, result) }
/** Gets an output expression of this echo statement. */
AstNode getAnOutputExpression() {
// Single expression: echo $x;
php_echo_statement_def(this, result) and not result instanceof @php_sequence_expression
or
// Sequence expression: echo $x, $y;
exists(@php_sequence_expression seq |
php_echo_statement_def(this, seq) and
php_sequence_expression_child(seq, _, result)
)
}
/** Gets an argument expression (alias for getAnOutputExpression). */
AstNode getAnArgument() { result = this.getAnOutputExpression() }
override string toString() { result = "echo ..." }
}
/** An unset statement. */
class UnsetStmt extends Stmt, @php_unset_statement {
override string getAPrimaryQlClass() { result = "UnsetStmt" }
AstNode getExpression(int i) { php_unset_statement_child(this, i, result) }
AstNode getAnExpression() { result = this.getExpression(_) }
override string toString() { result = "unset(...)" }
}
/** A global variable declaration. */
class GlobalDeclaration extends Stmt, @php_global_declaration {
override string getAPrimaryQlClass() { result = "GlobalDeclaration" }
AstNode getVariable(int i) { php_global_declaration_child(this, i, result) }
AstNode getAVariable() { result = this.getVariable(_) }
override string toString() { result = "global ..." }
}
/** A namespace definition. */
class NamespaceDefinition extends Stmt, @php_namespace_definition {
override string getAPrimaryQlClass() { result = "NamespaceDefinition" }
NamespaceName getNamespaceName() { php_namespace_definition_name(this, result) }
CompoundStmt getBody() { php_namespace_definition_body(this, result) }
override string toString() { result = "namespace ..." }
}
/** A namespace use declaration (`use ...`). */
class NamespaceUseDeclaration extends Stmt, @php_namespace_use_declaration {
override string getAPrimaryQlClass() { result = "NamespaceUseDeclaration" }
override string toString() { result = "use ..." }
}
/** A declare statement. */
class DeclareStmt extends Stmt, @php_declare_statement {
override string getAPrimaryQlClass() { result = "DeclareStmt" }
override string toString() { result = "declare(...)" }
}

View File

@@ -0,0 +1,117 @@
/**
* Provides classes for PHP variables and names.
*/
private import codeql.php.AST
private import internal.TreeSitter
/** A name token (identifier). */
class Name extends AstNode, @php_token_name {
override string getAPrimaryQlClass() { result = "Name" }
/** Gets the string value of this name. */
string getValue() { php_tokeninfo(this, _, result) }
override string toString() { result = this.getValue() }
}
/** A qualified name (`Namespace\ClassName`). */
class QualifiedName extends AstNode, @php_qualified_name {
override string getAPrimaryQlClass() { result = "QualifiedName" }
/** Gets the terminal name part. */
Name getNamePart() { php_qualified_name_def(this, result) }
/** Gets the string value of the terminal name. */
string getValue() { result = this.getNamePart().getValue() }
override string toString() { result = this.getValue() }
}
/** A namespace name. */
class NamespaceName extends AstNode, @php_namespace_name {
override string getAPrimaryQlClass() { result = "NamespaceName" }
/** Gets the i-th component name. */
Name getComponent(int i) { php_namespace_name_child(this, i, result) }
/** Gets a component name. */
Name getAComponent() { result = this.getComponent(_) }
override string toString() { result = "namespace_name" }
}
/** A variable name (`$x`). */
class VariableName extends AstNode, @php_variable_name {
override string getAPrimaryQlClass() { result = "VariableName" }
/** Gets the inner name token. */
Name getName() { php_variable_name_def(this, result) }
/** Gets the full variable name including the `$` prefix. */
string getValue() { result = "$" + this.getName().getValue() }
/** Gets the name without the `$` prefix. */
string getSimpleName() { result = this.getName().getValue() }
override string toString() { result = this.getValue() }
}
/**
* A type node in a type annotation.
*
* This covers named types (`ClassName`), primitive types (`int`, `string`),
* nullable types (`?int`), union types (`int|string`), and intersection types.
*/
class TypeNode extends AstNode, @php_type__ {
override string getAPrimaryQlClass() { result = "TypeNode" }
}
/** A named type (`ClassName`). */
class NamedType extends TypeNode, @php_named_type {
override string getAPrimaryQlClass() { result = "NamedType" }
AstNode getNameNode() { php_named_type_def(this, result) }
override string toString() { result = "named_type" }
}
/** A primitive type (`int`, `string`, `bool`, etc.). */
class PrimitiveType extends TypeNode, @php_token_primitive_type {
override string getAPrimaryQlClass() { result = "PrimitiveType" }
string getValue() { php_tokeninfo(this, _, result) }
override string toString() { result = this.getValue() }
}
/** A nullable (optional) type (`?int`). */
class OptionalType extends TypeNode, @php_optional_type {
override string getAPrimaryQlClass() { result = "OptionalType" }
TypeNode getInnerType() { php_optional_type_def(this, result) }
override string toString() { result = "?..." }
}
/** A union type (`int|string`). */
class UnionType extends TypeNode, @php_union_type {
override string getAPrimaryQlClass() { result = "UnionType" }
TypeNode getMember(int i) { php_union_type_child(this, i, result) }
TypeNode getAMember() { result = this.getMember(_) }
override string toString() { result = "...|..." }
}
/** An intersection type (`Foo&Bar`). */
class IntersectionType extends TypeNode, @php_intersection_type {
override string getAPrimaryQlClass() { result = "IntersectionType" }
TypeNode getMember(int i) { php_intersection_type_child(this, i, result) }
TypeNode getAMember() { result = this.getMember(_) }
override string toString() { result = "...&..." }
}

View File

@@ -0,0 +1,10 @@
/**
* Internal AST implementation for PHP.
*/
import codeql.php.ast.internal.TreeSitter
/**
* The base type for all PHP AST nodes.
*/
class TPhpAstNode = @php_ast_node;

View File

@@ -0,0 +1,875 @@
/**
* 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)) }
}
}

View File

@@ -0,0 +1,101 @@
/** Provides classes representing basic blocks. */
private import codeql.php.AST
private import codeql.php.controlflow.ControlFlowGraph
private import internal.ControlFlowGraphImpl as CfgImpl
private import CfgImpl::BasicBlocks as BasicBlocksImpl
private import codeql.controlflow.BasicBlock as BB
private import codeql.controlflow.SuccessorType
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*/
final class BasicBlock extends BasicBlocksImpl::BasicBlock {
/** Gets an immediate successor of this basic block, if any. */
BasicBlock getASuccessor() { result = super.getASuccessor() }
/** Gets an immediate successor of this basic block of a given type, if any. */
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor(t) }
/** Gets an immediate predecessor of this basic block, if any. */
BasicBlock getAPredecessor() { result = super.getAPredecessor() }
/** Gets an immediate predecessor of this basic block of a given type, if any. */
BasicBlock getAPredecessor(SuccessorType t) { result = super.getAPredecessor(t) }
/** Gets the control flow node at position `pos` in this basic block. */
CfgNode getNode(int pos) { result = super.getNode(pos) }
/** Gets a control flow node in this basic block. */
CfgNode getANode() { result = super.getANode() }
/** Gets the first control flow node in this basic block. */
CfgNode getFirstNode() { result = super.getFirstNode() }
/** Gets the last control flow node in this basic block. */
CfgNode getLastNode() { result = super.getLastNode() }
/** Holds if this basic block immediately dominates basic block `bb`. */
predicate immediatelyDominates(BasicBlock bb) { super.immediatelyDominates(bb) }
/** Holds if this basic block strictly dominates basic block `bb`. */
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
/** Holds if this basic block dominates basic block `bb`. */
predicate dominates(BasicBlock bb) { super.dominates(bb) }
/**
* Holds if `df` is in the dominance frontier of this basic block.
*/
predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) }
/** Gets the basic block that immediately dominates this basic block, if any. */
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
/** Holds if this basic block strictly post-dominates basic block `bb`. */
predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) }
/** Holds if this basic block post-dominates basic block `bb`. */
predicate postDominates(BasicBlock bb) { super.postDominates(bb) }
}
/** An entry basic block. */
final class EntryBasicBlock extends BasicBlock, BasicBlocksImpl::EntryBasicBlock { }
/** An annotated exit basic block. */
final class AnnotatedExitBasicBlock extends BasicBlock, BasicBlocksImpl::AnnotatedExitBasicBlock { }
/** An exit basic block. */
final class ExitBasicBlock extends BasicBlock, BasicBlocksImpl::ExitBasicBlock { }
/** A basic block with more than one predecessor. */
final class JoinBlock extends BasicBlock, BasicBlocksImpl::JoinBasicBlock {
JoinBlockPredecessor getJoinBlockPredecessor(int i) { result = super.getJoinBlockPredecessor(i) }
}
/** A basic block that is an immediate predecessor of a join block. */
final class JoinBlockPredecessor extends BasicBlock, BasicBlocksImpl::JoinPredecessorBasicBlock { }
/**
* A basic block that terminates in a condition, splitting the subsequent
* control flow.
*/
final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBlock { }
private class BasicBlockAlias = BasicBlock;
private class EntryBasicBlockAlias = EntryBasicBlock;
/** Implements the `CfgSig` module for use by the SSA library. */
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = CfgNode;
class BasicBlock = BasicBlockAlias;
class EntryBasicBlock = EntryBasicBlockAlias;
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
BasicBlocksImpl::dominatingEdge(bb1, bb2)
}
}

View File

@@ -0,0 +1,45 @@
/** Provides classes representing the control flow graph. */
import codeql.controlflow.SuccessorType
private import codeql.php.AST
private import codeql.php.controlflow.BasicBlocks
private import internal.ControlFlowGraphImpl as CfgImpl
private import internal.Completion
/**
* An AST node with an associated control-flow graph.
*
* Functions, methods, closures, arrow functions, and programs are CFG scopes.
*/
class CfgScope extends AstNode instanceof CfgImpl::CfgScopeImpl { }
/**
* A control flow node.
*
* A control flow node is a node in the control flow graph (CFG). There is a
* many-to-one relationship between CFG nodes and AST nodes.
*
* Only nodes that can be reached from an entry point are included in the CFG.
*/
class CfgNode extends CfgImpl::Node {
/** Gets a successor node of a given type, if any. */
final CfgNode getASuccessor(SuccessorType t) { result = super.getASuccessor(t) }
/** Gets an immediate successor, if any. */
final CfgNode getASuccessor() { result = this.getASuccessor(_) }
/** Gets an immediate predecessor node of a given flow type, if any. */
final CfgNode getAPredecessor(SuccessorType t) { result.getASuccessor(t) = this }
/** Gets an immediate predecessor, if any. */
final CfgNode getAPredecessor() { result = this.getAPredecessor(_) }
/** Gets the basic block that this control flow node belongs to. */
BasicBlock getBasicBlock() { result.getANode() = this }
/** Gets the AST node associated with this CFG node. */
AstNode getAstNode() { result = super.getAstNode() }
/** Gets the CFG scope that this node belongs to. */
CfgScope getScope() { result = super.getScope() }
}

View File

@@ -0,0 +1,170 @@
/**
* Provides classes representing control flow completions.
*
* A completion represents how a statement or expression terminates.
*/
private import codeql.php.AST
private import codeql.php.controlflow.ControlFlowGraph
private import ControlFlowGraphImpl as CfgImpl
private newtype TCompletion =
TSimpleCompletion() or
TBooleanCompletion(boolean b) { b in [false, true] } or
TReturnCompletion() or
TBreakCompletion() or
TContinueCompletion() or
TThrowCompletion() or
TExitCompletion()
/**
* Holds if `c` is a valid completion for node `n` based on its statement type.
*/
private predicate completionIsValidForStmt(AstNode n, Completion c) {
n instanceof BreakStmt and c = TBreakCompletion()
or
n instanceof ContinueStmt and c = TContinueCompletion()
or
n instanceof ReturnStmt and c = TReturnCompletion()
or
n instanceof ThrowExpr and c = TThrowCompletion()
}
/**
* Holds if `n` is used in a Boolean context. That is, the value
* that `n` evaluates to determines a true/false branch successor.
*/
private predicate inBooleanContext(AstNode n) {
// Condition of if/elseif
exists(IfStmt ifStmt | n = ifStmt.getCondition())
or
exists(ElseIfClause clause | n = clause.getCondition())
or
// Condition of while
exists(WhileStmt whileStmt | n = whileStmt.getCondition())
or
// Condition of do-while
exists(DoWhileStmt doWhile | n = doWhile.getCondition())
or
// Condition of for
exists(ForStmt forStmt | n = forStmt.getCondition())
or
// Condition of ternary
exists(ConditionalExpr cond | n = cond.getCondition())
or
// Logical operators: left operand is always in boolean context
exists(BinaryExpr bin |
bin.getOperator() = ["&&", "||", "and", "or"] and
n = bin.getLeftOperand()
)
or
// Negation operand
exists(UnaryExpr unary |
unary.getOperator() = "!" and
n = unary.getOperand()
)
}
/**
* Holds if a normal completion of `n` must be a Boolean completion.
*/
private predicate mustHaveBooleanCompletion(AstNode n) { inBooleanContext(n) }
/** A completion of a statement or an expression. */
abstract class Completion extends TCompletion {
private predicate isValidForSpecific(AstNode n) {
completionIsValidForStmt(n, this)
or
mustHaveBooleanCompletion(n) and
this = TBooleanCompletion(_)
}
/** Holds if this completion is valid for node `n`. */
predicate isValidFor(AstNode n) {
this.isValidForSpecific(n)
or
not any(Completion c).isValidForSpecific(n) and
this = TSimpleCompletion()
}
/**
* Holds if this completion will continue a loop when it is the completion
* of a loop body.
*/
predicate continuesLoop() {
this instanceof NormalCompletion or
this instanceof ContinueCompletion
}
/** Gets a successor type that matches this completion. */
abstract SuccessorType getAMatchingSuccessorType();
/** Gets a textual representation of this completion. */
abstract string toString();
}
/** A completion that represents normal evaluation. */
abstract class NormalCompletion extends Completion { }
/** A simple (normal) completion. */
class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
override SuccessorType getAMatchingSuccessorType() { result instanceof DirectSuccessor }
override string toString() { result = "simple" }
}
/** A Boolean completion. */
class BooleanCompletion extends NormalCompletion, TBooleanCompletion {
boolean value;
BooleanCompletion() { this = TBooleanCompletion(value) }
/** Gets the Boolean value of this completion. */
boolean getValue() { result = value }
override SuccessorType getAMatchingSuccessorType() {
result.(BooleanSuccessor).getValue() = value
}
override string toString() { result = "boolean(" + value + ")" }
}
/** A return completion. */
class ReturnCompletion extends Completion, TReturnCompletion {
override SuccessorType getAMatchingSuccessorType() { result instanceof ReturnSuccessor }
override string toString() { result = "return" }
}
/** A break completion. */
class BreakCompletion extends Completion, TBreakCompletion {
override SuccessorType getAMatchingSuccessorType() { result instanceof BreakSuccessor }
override string toString() { result = "break" }
}
/** A continue completion. */
class ContinueCompletion extends Completion, TContinueCompletion {
override SuccessorType getAMatchingSuccessorType() { result instanceof ContinueSuccessor }
override string toString() { result = "continue" }
}
/** A throw completion (exception). */
class ThrowCompletion extends Completion, TThrowCompletion {
override SuccessorType getAMatchingSuccessorType() { result instanceof ExceptionSuccessor }
override string toString() { result = "throw" }
}
/** An exit completion (die/exit). */
class ExitCompletion extends Completion, TExitCompletion {
override SuccessorType getAMatchingSuccessorType() { result instanceof ExitSuccessor }
override string toString() { result = "exit" }
}
/**
* A conditional completion, used for splitting.
*/
class ConditionalCompletion extends BooleanCompletion { }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,238 @@
/**
* Provides PHP-specific data flow dispatch logic.
*/
private import codeql.php.AST
private import DataFlowPrivate
newtype TReturnKind = TNormalReturnKind()
/**
* A return kind. A return kind describes how a value can be returned
* from a callable.
*/
abstract class ReturnKind extends TReturnKind {
abstract string toString();
}
/** A normal return (via `return` statement or expression body). */
class NormalReturnKind extends ReturnKind, TNormalReturnKind {
override string toString() { result = "return" }
}
/**
* Gets a node that can read the value returned from `call` with return kind `kind`.
*/
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) }
newtype TDataFlowCallable =
TCallable(Callable c) or
TProgram(Program p)
/** A callable (function, method, closure, arrow function, or file-level program). */
class DataFlowCallable extends TDataFlowCallable {
Callable asCallable() { this = TCallable(result) }
Program asProgram() { this = TProgram(result) }
string toString() {
result = this.asCallable().toString()
or
result = this.asProgram().toString()
}
Location getLocation() {
result = this.asCallable().getLocation()
or
result = this.asProgram().getLocation()
}
}
newtype TDataFlowCall = TNormalCall(Call call)
/** A data flow call. */
class DataFlowCall extends TDataFlowCall {
Call call;
DataFlowCall() { this = TNormalCall(call) }
Call asCall() { result = call }
DataFlowCallable getEnclosingCallable() {
result.asCallable() = call.getParent*().(Callable)
or
not call.getParent*() instanceof Callable and
result.asProgram() = call.getParent*().(Program)
}
string toString() { result = call.toString() }
Location getLocation() { result = call.getLocation() }
}
/**
* Gets a viable callable for the call `c`.
*
* Resolves function calls by name, method calls by class hierarchy analysis,
* and static calls by class scope.
*/
DataFlowCallable viableCallable(DataFlowCall c) {
// Function call: resolve by name
exists(FunctionCallExpr fce, FunctionDef fd |
fce = c.asCall() and
fd.getNameString() = fce.getFunctionName() and
result = TCallable(fd)
)
or
// Method call ($obj->method(...)): resolve by method name across all classes
exists(MethodCallExpr mce, MethodDecl md |
mce = c.asCall() and
md.getNameString() = mce.getMethodNameString() and
// If we can determine the class of the receiver, restrict to that class hierarchy
(
// $this->method(): resolve to methods in the enclosing class and its parents
mce.getObject().(VariableName).getValue() = "$this" and
exists(ClassDecl cd |
mce.getParent*() = cd and
md = getMethodInClassHierarchy(cd, mce.getMethodNameString())
)
or
// For other receivers, conservatively resolve by method name
not mce.getObject().(VariableName).getValue() = "$this" and
md.getNameString() = mce.getMethodNameString()
) and
result = TCallable(md)
)
or
// Nullsafe method call ($obj?->method(...)): same as method call
exists(NullsafeMethodCallExpr mce, MethodDecl md |
mce = c.asCall() and
md.getNameString() = mce.getMethodNameString() and
result = TCallable(md)
)
or
// Scoped (static) call (ClassName::method(...)): resolve by scope and name
exists(ScopedCallExpr sce, MethodDecl md |
sce = c.asCall() and
md.getNameString() = sce.getMethodNameString() and
(
// Direct class name resolution
exists(ClassDecl cd |
resolveClassName(sce.getScope()) = cd.getNameString() and
md = getMethodInClassHierarchy(cd, sce.getMethodNameString())
)
or
// self/static/parent - resolve from enclosing class
exists(ClassDecl enclosing, string scopeName |
sce.getParent*() = enclosing and
scopeName = resolveScopeName(sce.getScope()) and
(
scopeName = ["self", "static"] and
md = getMethodInClassHierarchy(enclosing, sce.getMethodNameString())
or
scopeName = "parent" and
exists(ClassDecl parent |
getBaseClassName(enclosing) = parent.getNameString() and
md = getMethodInClassHierarchy(parent, sce.getMethodNameString())
)
)
)
or
// Fallback: just match by method name
not exists(resolveClassName(sce.getScope())) and
not exists(resolveScopeName(sce.getScope())) and
md.getNameString() = sce.getMethodNameString()
) and
result = TCallable(md)
)
}
/**
* Gets the string class name from a scope expression, if it is a simple name.
*/
private string resolveClassName(AstNode scope) {
result = scope.(Name).getValue() and
not result = ["self", "static", "parent"]
or
result = scope.(QualifiedName).getValue() and
not result = ["self", "static", "parent"]
}
/**
* Gets a special scope keyword (self/static/parent) from a scope expression.
*/
private string resolveScopeName(AstNode scope) {
result = scope.(Name).getValue() and
result = ["self", "static", "parent"]
}
/**
* Gets the base class name for `cd` (the class it extends).
*/
private string getBaseClassName(ClassDecl cd) {
exists(BaseClause bc |
bc = cd.getBaseClause() and
result = bc.getChild(0).(Name).getValue()
or
bc = cd.getBaseClause() and
result = bc.getChild(0).(QualifiedName).getValue()
)
}
/**
* Gets a method named `methodName` that is declared in `cd` or one of its
* ancestor classes.
*/
private MethodDecl getMethodInClassHierarchy(ClassDecl cd, string methodName) {
// Direct declaration
exists(DeclarationList body |
body = cd.getBody() and
result = body.getAMember() and
result.getNameString() = methodName
)
or
// Inherited from parent
exists(ClassDecl parent |
getBaseClassName(cd) = parent.getNameString() and
result = getMethodInClassHierarchy(parent, methodName) and
// Only inherit if not overridden in cd
not exists(MethodDecl override |
override = cd.getBody().getAMember() and
override.getNameString() = methodName
)
)
}
predicate mayBenefitFromCallContext(DataFlowCall call) { none() }
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
newtype TParameterPosition = TPositionalParameterPosition(int i) { i in [0 .. 20] }
/** A parameter position. */
class ParameterPosition extends TParameterPosition {
int pos;
ParameterPosition() { this = TPositionalParameterPosition(pos) }
int asPositional() { result = pos }
string toString() { result = pos.toString() }
}
newtype TArgumentPosition = TPositionalArgumentPosition(int i) { i in [0 .. 20] }
/** An argument position. */
class ArgumentPosition extends TArgumentPosition {
int pos;
ArgumentPosition() { this = TPositionalArgumentPosition(pos) }
int asPositional() { result = pos }
string toString() { result = pos.toString() }
}
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
ppos.asPositional() = apos.asPositional()
}

View File

@@ -0,0 +1,28 @@
/**
* Provides PHP-specific definitions for use in the data flow library.
*/
private import codeql.Locations
private import codeql.dataflow.DataFlow
module Private {
import DataFlowPrivate
import DataFlowDispatch
}
module Public {
import DataFlowPublic
}
module PhpDataFlow implements InputSig<Location> {
import Private
import Public
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
predicate neverSkipInPathGraph = Private::neverSkipInPathGraph/1;
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
}

View File

@@ -0,0 +1,294 @@
/**
* Provides PHP-specific data flow implementation details.
*/
private import codeql.php.AST
private import DataFlowPublic
private import DataFlowDispatch
private import SsaImpl as Ssa
private import codeql.php.controlflow.ControlFlowGraph as Cfg
private import codeql.php.controlflow.BasicBlocks as BasicBlocks
private import codeql.php.controlflow.internal.ControlFlowGraphImpl as CfgImpl
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) {
result = TCallable(n.asExpr().getParent*().(Callable))
or
result = TCallable(n.asParameter().getParent*().(Callable))
or
// File-level code: node is inside a Program but not inside any Callable
not n.asExpr().getParent*() instanceof Callable and
result = TProgram(n.asExpr().getParent*().(Program))
or
// SSA definition node: use the scope of the SSA variable
exists(Ssa::Definition def, Ssa::SsaSourceVariable v |
n = TSsaDefinitionNode(def) and
def.definesAt(v, _, _)
|
result = TCallable(v.getScope().(Callable))
or
not v.getScope() instanceof Callable and
result = TProgram(v.getScope().(Program))
)
}
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
exists(Callable callable, int i |
callable = c.asCallable() and
callable.getParameter(i) = p.getParameter() and
pos = TPositionalParameterPosition(i)
)
}
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
exists(Call call, int i |
call = c.asCall() and
call.getArgument(i) = arg.asExpr() and
pos = TPositionalArgumentPosition(i)
)
}
newtype TNode =
TExprNode(Expr e) or
TParameterNode(Parameter p) or
TSsaDefinitionNode(Ssa::Definition def) or
TPostUpdateNode(Expr e) { isPostUpdateExpr(e) }
private predicate isPostUpdateExpr(Expr e) {
// Arguments of calls that may be modified
exists(Call c | c.getAnArgument() = e)
or
// Receiver of method calls
e = any(MethodCallExpr mc).getObject()
or
e = any(NullsafeMethodCallExpr mc).getObject()
or
e = any(MemberAccessExpr ma).getObject()
}
/** The data flow type. */
class DataFlowType extends string {
DataFlowType() { this = "" }
string toString() { result = this }
}
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() }
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
DataFlowType getNodeType(Node node) { exists(node) and result = "" }
predicate nodeIsHidden(Node node) { node instanceof SsaDefinitionNode }
/**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local step.
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
model = "" and
(
// Assignment: value flows from RHS to LHS
exists(AssignExpr assign |
nodeFrom.asExpr() = assign.getRightOperand() and
nodeTo.asExpr() = assign.getLeftOperand()
)
or
// SSA flow: from a variable write to the SSA definition
exists(Ssa::WriteDefinition def, BasicBlocks::BasicBlock bb, int i, VariableName vn |
def.definesAt(_, bb, i) and
bb.getNode(i).getAstNode() = vn and
nodeFrom.asExpr() = vn and
nodeTo = TSsaDefinitionNode(def) and
exists(AssignExpr assign | assign.getLeftOperand() = vn)
)
or
// SSA flow: from an SSA definition to each read of the same variable
exists(Ssa::Definition def, BasicBlocks::BasicBlock bb, int i, VariableName vn |
ssaDefReachesRead(def, bb, i) and
bb.getNode(i).getAstNode() = vn and
nodeFrom = TSsaDefinitionNode(def) and
nodeTo.asExpr() = vn
)
or
// SSA flow: phi node from input definitions
exists(Ssa::PhiNode phi, Ssa::Definition input |
input = Ssa::phiHasInputFromBlock(phi, _) and
nodeFrom = TSsaDefinitionNode(input) and
nodeTo = TSsaDefinitionNode(phi)
)
or
// Parenthesized expression: value flows through
exists(ParenExpr paren |
nodeFrom.asExpr() = paren.getExpr() and
nodeTo.asExpr() = paren
)
or
// Conditional expression: value flows from branches
exists(ConditionalExpr cond |
(
nodeFrom.asExpr() = cond.getConsequence() or
nodeFrom.asExpr() = cond.getAlternative()
) and
nodeTo.asExpr() = cond
)
)
}
/**
* Holds if SSA definition `def` reaches a read at position `i` in basic block `bb`.
*/
private predicate ssaDefReachesRead(
Ssa::Definition def, BasicBlocks::BasicBlock bb, int i
) {
exists(Ssa::SsaSourceVariable v |
def.definesAt(v, _, _) and
Ssa::SsaInput::variableRead(bb, i, v, _) and
Ssa::getARead(def) = bb.getNode(i)
)
}
/** A type of data-flow content. */
newtype TContent =
TArrayElementContent() or
TPropertyContent(string name) { exists(MemberAccessExpr ma | ma.getName().getValue() = name) }
/** Data flow content (field, array element, etc.). */
class Content extends TContent {
string toString() {
this = TArrayElementContent() and result = "ArrayElement"
or
exists(string name | this = TPropertyContent(name) and result = "Property[" + name + "]")
}
}
class ContentApprox extends TContent {
string toString() { result = this.(Content).toString() }
}
ContentApprox getContentApprox(Content c) { result = c }
predicate forceHighPrecision(Content c) { none() }
predicate readStep(Node node1, ContentSet c, Node node2) {
// Property read: $obj->prop
exists(MemberAccessExpr ma |
node1.asExpr() = ma.getObject() and
node2.asExpr() = ma and
c = TPropertyContent(ma.getName().getValue())
)
or
// Array read: $arr[idx]
exists(SubscriptExpr sub |
node1.asExpr() = sub.getObject() and
node2.asExpr() = sub and
c = TArrayElementContent()
)
}
predicate storeStep(Node node1, ContentSet c, Node node2) {
// Property write: $obj->prop = value
exists(AssignExpr assign, MemberAccessExpr ma |
ma = assign.getLeftOperand() and
node1.asExpr() = assign.getRightOperand() and
node2 = TPostUpdateNode(ma.getObject()) and
c = TPropertyContent(ma.getName().getValue())
)
or
// Array write: $arr[idx] = value
exists(AssignExpr assign, SubscriptExpr sub |
sub = assign.getLeftOperand() and
node1.asExpr() = assign.getRightOperand() and
node2 = TPostUpdateNode(sub.getObject()) and
c = TArrayElementContent()
)
}
predicate clearsContent(Node n, ContentSet c) { none() }
predicate expectsContent(Node n, ContentSet c) { none() }
predicate jumpStep(Node node1, Node node2) { none() }
class NodeRegion instanceof string {
NodeRegion() { this = "NodeRegion" }
predicate contains(Node n) { none() }
string toString() { result = this }
}
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() }
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
predicate localMustFlowStep(Node node1, Node node2) {
exists(AssignExpr assign |
node1.asExpr() = assign.getRightOperand() and
node2.asExpr() = assign.getLeftOperand()
)
}
class LambdaCallKind extends string {
LambdaCallKind() { this = "closure" }
}
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
predicate knownSourceModel(Node source, string model) { none() }
predicate knownSinkModel(Node sink, string model) { none() }
predicate neverSkipInPathGraph(Node n) { none() }
class DataFlowSecondLevelScope extends string {
DataFlowSecondLevelScope() { this = "" }
string toString() { result = this }
}
/** The type of data flow expressions. */
class DataFlowExpr = Expr;
/** An argument node. */
class ArgumentNode extends ExprNode {
private Call call;
ArgumentNode() { call.getAnArgument() = this.asExpr() }
predicate argumentOf(DataFlowCall c, ArgumentPosition pos) {
exists(int i |
call = c.asCall() and
call.getArgument(i) = this.getExpr() and
pos = TPositionalArgumentPosition(i)
)
}
}
/** A return node. */
class ReturnNode extends ExprNode {
ReturnStmt ret;
ReturnNode() { this.getExpr() = ret.getValue() }
ReturnKind getKind() { result instanceof NormalReturnKind }
}
/** An out node (at a call site, reading return values). */
class OutNode extends ExprNode {
OutNode() { this.getExpr() instanceof Call }
DataFlowCall getCall(ReturnKind kind) {
result.asCall() = this.getExpr() and
kind instanceof NormalReturnKind
}
}
class CastNode extends Node {
CastNode() { this.asExpr() instanceof CastExpr }
}

View File

@@ -0,0 +1,149 @@
/**
* Provides PHP-specific data flow public API.
*/
private import codeql.php.AST
private import DataFlowPrivate
private import SsaImpl as Ssa
/**
* An element, viewed as a node in a data flow graph. Either an expression
* (`ExprNode`) or a parameter (`ParameterNode`).
*/
class Node extends TNode {
/** Gets the expression corresponding to this node, if any. */
Expr asExpr() { this = TExprNode(result) }
/** Gets the parameter corresponding to this node, if any. */
Parameter asParameter() { this = TParameterNode(result) }
/** Gets a textual representation of this node. */
string toString() {
result = this.asExpr().toString()
or
result = this.asParameter().toString()
or
exists(Ssa::Definition def |
this = TSsaDefinitionNode(def) and result = "SSA def(" + def.toString() + ")"
)
or
this instanceof TPostUpdateNode and
result = "[post] " + this.(PostUpdateNode).getPreUpdateNode().toString()
}
/** Gets the location of this node. */
Location getLocation() {
result = this.asExpr().getLocation()
or
result = this.asParameter().getLocation()
or
exists(Expr e | this = TPostUpdateNode(e) | result = e.getLocation())
or
exists(Ssa::Definition def |
this = TSsaDefinitionNode(def) and result = def.getLocation()
)
}
/**
* Gets a local source node from which data may flow to this node in zero or
* more local data-flow steps.
*/
Node getALocalSource() { localFlowStep*(result, this) }
/**
* Gets a data flow node from which data may flow to this node in one local step.
*/
Node getAPredecessor() { simpleLocalFlowStep(result, this, _) }
/**
* Gets a data flow node to which data may flow from this node in one local step.
*/
Node getASuccessor() { simpleLocalFlowStep(this, result, _) }
}
/** A data flow node corresponding to an expression. */
class ExprNode extends Node, TExprNode {
Expr expr;
ExprNode() { this = TExprNode(expr) }
/** Gets the underlying expression. */
Expr getExpr() { result = expr }
}
/** A data flow node corresponding to a parameter. */
class ParameterNode extends Node, TParameterNode {
Parameter param;
ParameterNode() { this = TParameterNode(param) }
/** Gets the underlying parameter. */
Parameter getParameter() { result = param }
}
/**
* A node associated with an object after an operation that might have
* changed its state.
*/
class PostUpdateNode extends Node, TPostUpdateNode {
Expr expr;
PostUpdateNode() { this = TPostUpdateNode(expr) }
/** Gets the node before the state change. */
Node getPreUpdateNode() { result = TExprNode(expr) }
}
/** A data flow node corresponding to an SSA definition. */
class SsaDefinitionNode extends Node, TSsaDefinitionNode {
Ssa::Definition def;
SsaDefinitionNode() { this = TSsaDefinitionNode(def) }
/** Gets the underlying SSA definition. */
Ssa::Definition getDefinition() { result = def }
}
/** Gets the node corresponding to `e`. */
ExprNode exprNode(DataFlowExpr e) { result.getExpr() = e }
/** Gets the node corresponding to the value of parameter `p` at function entry. */
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
/**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo, _) }
/**
* Holds if data flows from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
/**
* A reference to a local source of data flow.
*/
class LocalSourceNode extends Node {
LocalSourceNode() {
not localFlowStep(_, this)
or
this instanceof ParameterNode
}
/** Holds if this `LocalSourceNode` flows to `sink` in zero or more local steps. */
predicate flowsTo(Node sink) { localFlow(this, sink) }
}
/** A content set for use in data flow. */
class ContentSet instanceof Content {
/** Gets a content that may be stored into when storing into this set. */
Content getAStoreContent() { result = this }
/** Gets a content that may be read from when reading from this set. */
Content getAReadContent() { result = this }
/** Gets a textual representation of this content set. */
string toString() { result = super.toString() }
}

View File

@@ -0,0 +1,172 @@
/**
* Provides an SSA (Static Single Assignment) implementation for PHP.
*/
private import codeql.ssa.Ssa as SsaImplCommon
private import codeql.php.AST
private import codeql.php.controlflow.ControlFlowGraph as Cfg
private import codeql.php.controlflow.BasicBlocks as BasicBlocks
private import codeql.php.controlflow.internal.ControlFlowGraphImpl as CfgImpl
private class BasicBlock = BasicBlocks::Cfg::BasicBlock;
/**
* A local variable, identified by name and scope. In PHP, variables within a function
* or program scope are local to that scope; this class provides the source variable
* for SSA analysis.
*/
class PhpLocalVariable extends VariableName {
Cfg::CfgScope scope;
PhpLocalVariable() {
scope = CfgImpl::getCfgScope(this)
}
/** Gets the name of this variable. */
string getVariableName() { result = this.getValue() }
/** Gets the scope of this variable. */
Cfg::CfgScope getScope() { result = scope }
/** Gets a textual representation. */
override string toString() { result = this.getValue() }
}
/**
* A source variable for SSA, identified by variable name and scope.
* Multiple `VariableName` AST nodes may refer to the same source variable
* if they have the same name and are in the same scope.
*/
class SsaSourceVariable extends string {
Cfg::CfgScope scope;
SsaSourceVariable() {
exists(VariableName vn |
this = vn.getValue() and
scope = CfgImpl::getCfgScope(vn)
)
}
/** Gets the variable name. */
string getVariableName() { result = this }
/** Gets the scope. */
Cfg::CfgScope getScope() { result = scope }
/** Gets a location for this source variable (the first occurrence). */
Location getLocation() {
result =
min(VariableName vn |
vn.getValue() = this and CfgImpl::getCfgScope(vn) = scope
|
vn.getLocation()
order by
vn.getLocation().getStartLine(), vn.getLocation().getStartColumn()
)
}
string toString() { result = this }
}
/** Gets the source variable for a `VariableName` AST node. */
SsaSourceVariable getSourceVariable(VariableName vn) {
result = vn.getValue() and
result.getScope() = CfgImpl::getCfgScope(vn)
}
module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
class SourceVariable = SsaSourceVariable;
/**
* Holds if the CFG node at index `i` of basic block `bb` writes to variable `v`.
*/
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(Cfg::CfgNode cfgNode, VariableName vn |
cfgNode = bb.getNode(i) and
vn = cfgNode.getAstNode() and
v = getSourceVariable(vn)
|
// Direct assignment: $x = ...
exists(AssignExpr assign | assign.getLeftOperand() = vn)
or
// Reference assignment: $x =& ...
exists(RefAssignExpr assign | assign.getLeftOperand() = vn)
or
// Augmented assignment: $x += ...
exists(AugmentedAssignExpr assign | assign.getLeftOperand() = vn)
or
// Update expression: $x++ / $x--
exists(UpdateExpr upd | upd.getArgument() = vn)
or
// Foreach value/key variable
exists(ForeachStmt foreach | foreach.getChild(_) = vn)
or
// Catch variable binding
exists(CatchClause cc | cc.getVariable() = vn)
or
// Global declaration
exists(GlobalDeclaration gd | gd.getAVariable() = vn)
) and
certain = true
or
// Parameter initialization at entry block
exists(Cfg::CfgNode cfgNode, VariableName vn, Parameter p |
cfgNode = bb.getNode(i) and
vn = cfgNode.getAstNode() and
v = getSourceVariable(vn) and
p.getChild(_) = vn and
p.getParent+() instanceof Callable
) and
certain = true
}
/**
* Holds if the CFG node at index `i` of basic block `bb` reads variable `v`.
*/
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(Cfg::CfgNode cfgNode, VariableName vn |
cfgNode = bb.getNode(i) and
vn = cfgNode.getAstNode() and
v = getSourceVariable(vn) and
// A read is a use that isn't a pure write target
not exists(AssignExpr assign | assign.getLeftOperand() = vn) and
not exists(RefAssignExpr assign | assign.getLeftOperand() = vn) and
not (
exists(AugmentedAssignExpr assign | assign.getLeftOperand() = vn)
) and
not exists(CatchClause cc | cc.getVariable() = vn) and
not exists(GlobalDeclaration gd | gd.getAVariable() = vn)
) and
certain = true
}
}
import SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput> as Impl
class Definition = Impl::Definition;
class WriteDefinition = Impl::WriteDefinition;
class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
class PhiNode = Impl::PhiNode;
module Consistency = Impl::Consistency;
/**
* Gets a CFG node that reads the variable defined by `def`.
*/
Cfg::CfgNode getARead(Definition def) {
exists(SsaSourceVariable v, BasicBlocks::BasicBlock bb, int i |
Impl::ssaDefReachesRead(v, def, bb, i) and
SsaInput::variableRead(bb, i, v, _) and
result = bb.getNode(i)
)
}
/**
* Gets an input definition to phi node `phi` from basic block `bb`.
*/
Definition phiHasInputFromBlock(PhiNode phi, BasicBlocks::BasicBlock bb) {
Impl::phiHasInputFromBlock(phi, result, bb)
}

View File

@@ -0,0 +1,11 @@
/**
* Provides PHP-specific definitions for use in the taint tracking library.
*/
private import codeql.Locations
private import codeql.dataflow.TaintTracking
private import DataFlowImplSpecific
module PhpTaintTracking implements InputSig<Location, PhpDataFlow> {
import TaintTrackingPrivate
}

View File

@@ -0,0 +1,62 @@
private import codeql.php.AST
private import DataFlowPrivate
private import codeql.php.DataFlow
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if default taint tracking configurations should allow implicit reads
* of `c` at sinks and inputs to additional taint steps.
*/
bindingset[node]
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
/**
* Holds if the additional step from `src` to `sink` should be considered
* as a taint-propagating step in all global taint flow configurations.
*/
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
model = "" and
(
// String concatenation propagates taint
exists(BinaryExpr binConcat |
binConcat.getOperator() = "." and
(src.asExpr() = binConcat.getLeftOperand() or src.asExpr() = binConcat.getRightOperand()) and
sink.asExpr() = binConcat
)
or
// Augmented string concatenation ($x .= $y) propagates taint
exists(AugmentedAssignExpr assign |
assign.getOperator() = ".=" and
src.asExpr() = assign.getRightOperand() and
sink.asExpr() = assign
)
or
// Array element access propagates taint
exists(SubscriptExpr sub |
src.asExpr() = sub.getObject() and
sink.asExpr() = sub
)
or
// Include/require propagates taint
exists(IncludeExpr inc |
src.asExpr() = inc.getArgument() and
sink.asExpr() = inc
)
or
// Encapsed (interpolated) strings propagate taint
exists(EncapsedString es |
src.asExpr() = es.getAnElement() and
sink.asExpr() = es
)
)
}
/**
* Holds if taint should propagate from `nodeFrom` to `nodeTo` speculatively.
*/
predicate speculativeTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }

View File

@@ -0,0 +1,23 @@
private import codeql.php.AST
private import DataFlowPrivate
private import TaintTrackingPrivate
private import codeql.php.DataFlow
/**
* Holds if taint propagates from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
pragma[inline]
predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { localTaintStep*(source, sink) }
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo`.
*/
predicate localTaintStep = localTaintStepCached/2;
cached
private predicate localTaintStepCached(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
DataFlow::localFlowStep(nodeFrom, nodeTo)
or
defaultAdditionalTaintStep(nodeFrom, nodeTo, _)
}

1822
php/ql/lib/php.dbscheme Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
<dbstats>
<typesizes></typesizes>
<stats></stats>
</dbstats>

7
php/ql/lib/php.qll Normal file
View File

@@ -0,0 +1,7 @@
/**
* Provides classes for working with PHP programs.
*/
import codeql.php.AST as Ast
import codeql.php.CFG as Cfg
import codeql.php.DataFlow

13
php/ql/lib/qlpack.yml Normal file
View File

@@ -0,0 +1,13 @@
name: codeql/php-all
version: 0.1.0-dev
groups: php
extractor: php
dbscheme: php.dbscheme
upgrades: upgrades
library: true
dependencies:
codeql/controlflow: ${workspace}
codeql/dataflow: ${workspace}
codeql/ssa: ${workspace}
codeql/util: ${workspace}
warnOnImplicitThis: true

View File

@@ -0,0 +1,4 @@
- description: Standard Code Scanning queries for PHP
- queries: .
- apply: code-scanning-selectors.yml
from: codeql/suite-helpers

View File

@@ -0,0 +1,4 @@
- description: Security-and-quality queries for PHP
- queries: .
- apply: security-and-frozen-quality-selectors.yml
from: codeql/suite-helpers

View File

@@ -0,0 +1,4 @@
- description: Security-extended queries for PHP
- queries: .
- apply: security-extended-selectors.yml
from: codeql/suite-helpers

12
php/ql/src/qlpack.yml Normal file
View File

@@ -0,0 +1,12 @@
name: codeql/php-queries
version: 0.1.0-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

View File

@@ -0,0 +1,51 @@
/**
* @name Print AST
* @description Outputs a representation of a file's Abstract Syntax Tree.
* @id php/print-ast
* @kind graph
*/
import codeql.php.AST
private predicate shouldPrint(AstNode node) { any() }
private predicate orderBy(
AstNode n, string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
shouldPrint(n) and
n.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
private int getOrder(AstNode node) {
node =
rank[result](AstNode n, string filepath, int startline, int startcolumn, int endline,
int endcolumn |
orderBy(n, filepath, startline, startcolumn, endline, endcolumn)
|
n order by filepath, startline, startcolumn, endline, endcolumn
)
}
query predicate nodes(AstNode node, string key, string value) {
shouldPrint(node) and
(
key = "semmle.label" and
value = "[" + node.getPrimaryQlClasses() + "] " + node.toString()
or
key = "semmle.order" and value = getOrder(node).toString()
)
}
query predicate edges(AstNode source, AstNode target, string key, string value) {
shouldPrint(source) and
shouldPrint(target) and
exists(int index | target = source.getChild(index) |
key = "semmle.label" and value = index.toString()
or
key = "semmle.order" and value = index.toString()
)
}
query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "tree"
}

View File

@@ -0,0 +1,14 @@
/**
* @name Lines of code in files
* @kind metric
* @description Measures the number of lines of code in each file,
* ignoring lines that contain only comments or whitespace.
* @metricType file
* @id php/lines-of-code-in-files
*/
import codeql.php.AST
from Program p, int n
where n = p.getLocation().getFile().getNumberOfLinesOfCode()
select p.getLocation().getFile(), n order by n desc

View File

@@ -0,0 +1,21 @@
/**
* @name Dangerous function calls
* @description Finds calls to dangerous PHP functions like eval, exec, system, etc.
* @kind problem
* @problem.severity error
* @id php/dangerous-function-calls
* @tags security
*/
import codeql.php.ast.internal.TreeSitter
from Php::FunctionCallExpression call, string name
where
name = call.getFunction().(Php::Token).getValue() and
name =
[
"eval", "exec", "system", "passthru", "shell_exec", "popen", "proc_open",
"assert", "preg_replace", "create_function", "call_user_func",
"call_user_func_array", "unserialize"
]
select call, "Call to dangerous function " + name + "()."

View File

@@ -0,0 +1,16 @@
/**
* @name Eval use (basic)
* @description Finds calls to eval() in PHP code.
* @kind problem
* @problem.severity warning
* @id php/eval-use-basic
* @tags security
*/
import codeql.php.ast.internal.TreeSitter
from Php::FunctionCallExpression call, Php::AstNode fn
where
fn = call.getFunction() and
fn.(Php::Token).getValue() = "eval"
select call, "Avoid using eval()."

View File

@@ -0,0 +1,92 @@
/**
* @name Path built from user-controlled sources
* @description Using user-controlled data to construct a file path may allow
* an attacker to access or modify unintended files.
* @kind path-problem
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @id php/path-injection
* @tags security
* external/cwe/cwe-022
* external/cwe/cwe-023
* external/cwe/cwe-036
* external/cwe/cwe-073
*/
import codeql.php.AST
import codeql.php.DataFlow
import codeql.php.TaintTracking
/**
* A source of user input from PHP superglobals.
*/
class UserInputSource extends DataFlow::ExprNode {
UserInputSource() {
exists(VariableName v | v = this.asExpr() |
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
or
exists(SubscriptExpr sub, VariableName v |
sub = this.asExpr() and
v = sub.getObject() and
(
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
)
}
}
/**
* A sink that uses a file path.
*/
class PathSink extends DataFlow::ExprNode {
PathSink() {
exists(FunctionCallExpr call |
call.getFunctionName() =
[
"fopen", "file_get_contents", "file_put_contents", "readfile", "file", "fread",
"fwrite", "unlink", "rename", "copy", "mkdir", "rmdir", "is_file", "is_dir",
"realpath", "glob", "move_uploaded_file"
] and
this.asExpr() = call.getArgument(0)
)
or
// include/require are language constructs, not function calls
exists(IncludeExpr inc | this.asExpr() = inc.getArgument())
or
exists(IncludeOnceExpr inc | this.asExpr() = inc.getArgument())
or
exists(RequireExpr req | this.asExpr() = req.getArgument())
or
exists(RequireOnceExpr req | this.asExpr() = req.getArgument())
}
}
module PathInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UserInputSource }
predicate isSink(DataFlow::Node sink) { sink instanceof PathSink }
predicate isBarrier(DataFlow::Node node) {
exists(FunctionCallExpr call |
call.getFunctionName() = ["basename", "realpath"] and
node.asExpr() = call
)
}
}
module PathInjectionFlow = TaintTracking::Global<PathInjectionConfig>;
import PathInjectionFlow::PathGraph
from PathInjectionFlow::PathNode source, PathInjectionFlow::PathNode sink
where PathInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -0,0 +1,83 @@
/**
* @name Uncontrolled command line
* @description Using externally controlled strings in a command line may allow
* a malicious user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
* @security-severity 9.8
* @precision medium
* @id php/command-line-injection
* @tags security
* external/cwe/cwe-078
* external/cwe/cwe-088
*/
import codeql.php.AST
import codeql.php.DataFlow
import codeql.php.TaintTracking
/**
* A source of user input from PHP superglobals.
*/
class UserInputSource extends DataFlow::ExprNode {
UserInputSource() {
exists(VariableName v | v = this.asExpr() |
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
or
exists(SubscriptExpr sub, VariableName v |
sub = this.asExpr() and
v = sub.getObject() and
(
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
)
}
}
/**
* A sink for command execution.
*/
class CommandSink extends DataFlow::ExprNode {
CommandSink() {
exists(FunctionCallExpr call |
call.getFunctionName() =
[
"exec", "system", "passthru", "shell_exec", "popen", "proc_open", "pcntl_exec",
"eval"
] and
this.asExpr() = call.getArgument(0)
)
or
// Backtick operator / shell_exec
exists(ShellCommandExpr shell | this.asExpr() = shell)
}
}
module CommandInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UserInputSource }
predicate isSink(DataFlow::Node sink) { sink instanceof CommandSink }
predicate isBarrier(DataFlow::Node node) {
exists(FunctionCallExpr call |
call.getFunctionName() = ["escapeshellarg", "escapeshellcmd"] and
node.asExpr() = call
)
}
}
module CommandInjectionFlow = TaintTracking::Global<CommandInjectionConfig>;
import CommandInjectionFlow::PathGraph
from CommandInjectionFlow::PathNode source, CommandInjectionFlow::PathNode sink
where CommandInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This command depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -0,0 +1,84 @@
/**
* @name Reflected cross-site scripting
* @description Writing user input directly to a web page allows for
* a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 6.1
* @precision medium
* @id php/reflected-xss
* @tags security
* external/cwe/cwe-079
* external/cwe/cwe-116
*/
import codeql.php.AST
import codeql.php.DataFlow
import codeql.php.TaintTracking
/**
* A source of user input from PHP superglobals.
*/
class UserInputSource extends DataFlow::ExprNode {
UserInputSource() {
exists(VariableName v | v = this.asExpr() |
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
or
exists(SubscriptExpr sub, VariableName v |
sub = this.asExpr() and
v = sub.getObject() and
(
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
)
}
}
/**
* An output sink that writes directly to the response (echo, print, etc).
*/
class XssSink extends DataFlow::ExprNode {
XssSink() {
// echo statement arguments
exists(EchoStmt echo | this.asExpr() = echo.getAnArgument())
or
// print expression
exists(PrintExpr print | this.asExpr() = print.getArgument())
or
// printf/vprintf calls
exists(FunctionCallExpr call |
call.getFunctionName() = ["printf", "vprintf"] and
this.asExpr() = call.getArgument(_)
)
}
}
module XssConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UserInputSource }
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
predicate isBarrier(DataFlow::Node node) {
// htmlspecialchars, htmlentities, strip_tags are sanitizers
exists(FunctionCallExpr call |
call.getFunctionName() = ["htmlspecialchars", "htmlentities", "strip_tags"] and
node.asExpr() = call
)
}
}
module XssFlow = TaintTracking::Global<XssConfig>;
import XssFlow::PathGraph
from XssFlow::PathNode source, XssFlow::PathNode sink
where XssFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to a $@.",
source.getNode(), "user-provided value"

View File

@@ -0,0 +1,77 @@
/**
* @name SQL query built from user-controlled sources
* @description Building a SQL query from user-controlled sources is vulnerable
* to insertion of malicious SQL code by the user.
* @kind path-problem
* @problem.severity error
* @security-severity 8.8
* @precision medium
* @id php/sql-injection
* @tags security
* external/cwe/cwe-089
*/
import codeql.php.AST
import codeql.php.DataFlow
import codeql.php.TaintTracking
/**
* A source of user input from PHP superglobals (`$_GET`, `$_POST`, `$_REQUEST`, `$_COOKIE`).
*/
class UserInputSource extends DataFlow::ExprNode {
UserInputSource() {
exists(VariableName v | v = this.asExpr() |
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
or
exists(SubscriptExpr sub, VariableName v |
sub = this.asExpr() and
v = sub.getObject() and
(
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
)
}
}
/**
* A call to a SQL execution function.
*/
class SqlSink extends DataFlow::ExprNode {
SqlSink() {
exists(FunctionCallExpr call |
call.getFunctionName() =
[
"mysql_query", "mysqli_query", "pg_query", "sqlite_query", "sqlite_exec",
"mssql_query"
] and
this.asExpr() = call.getArgument(_)
)
or
exists(MethodCallExpr call |
call.getMethodNameString() = ["query", "exec", "prepare", "execute"] and
this.asExpr() = call.getArgument(0)
)
}
}
module SqlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UserInputSource }
predicate isSink(DataFlow::Node sink) { sink instanceof SqlSink }
}
module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>;
import SqlInjectionFlow::PathGraph
from SqlInjectionFlow::PathNode source, SqlInjectionFlow::PathNode sink
where SqlInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This SQL query depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -0,0 +1,18 @@
/**
* @name Use of eval
* @description Using `eval()` to evaluate arbitrary strings as PHP code
* is a security risk and should be avoided.
* @kind problem
* @problem.severity warning
* @precision high
* @id php/eval-use
* @tags security
* maintainability
* external/cwe/cwe-095
*/
import codeql.php.AST
from FunctionCallExpr call
where call.getFunctionName() = "eval"
select call, "Avoid using eval()."

View File

@@ -0,0 +1,38 @@
/**
* @name Unrestricted file upload
* @description Allowing file uploads without proper validation of file type
* or content may allow an attacker to upload and execute
* malicious code.
* @kind problem
* @problem.severity error
* @security-severity 8.8
* @precision medium
* @id php/unrestricted-file-upload
* @tags security
* external/cwe/cwe-434
*/
import codeql.php.AST
from FunctionCallExpr move
where
move.getFunctionName() = "move_uploaded_file" and
not exists(FunctionCallExpr check |
check.getLocation().getFile() = move.getLocation().getFile() and
(
// Common file-type validation functions
check.getFunctionName() =
[
"getimagesize", "finfo_file", "mime_content_type", "pathinfo",
"exif_imagetype"
]
or
// Checking file extension via string functions
check.getFunctionName() = ["strtolower", "in_array"] and
exists(FunctionCallExpr inner |
inner.getFunctionName() = ["pathinfo", "substr", "strrpos"] and
inner.getLocation().getFile() = move.getLocation().getFile()
)
)
)
select move, "Unrestricted file upload without validation of file type or content."

View File

@@ -0,0 +1,68 @@
/**
* @name URL redirect from remote source
* @description Using user-controlled data in a redirect header may allow an
* attacker to redirect clients to a malicious URL.
* @kind path-problem
* @problem.severity error
* @security-severity 6.1
* @precision medium
* @id php/open-redirect
* @tags security
* external/cwe/cwe-601
*/
import codeql.php.AST
import codeql.php.DataFlow
import codeql.php.TaintTracking
/**
* A source of user input from PHP superglobals.
*/
class UserInputSource extends DataFlow::ExprNode {
UserInputSource() {
exists(VariableName v | v = this.asExpr() |
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
or
exists(SubscriptExpr sub, VariableName v |
sub = this.asExpr() and
v = sub.getObject() and
(
v.getValue() = "$_GET" or
v.getValue() = "$_POST" or
v.getValue() = "$_REQUEST" or
v.getValue() = "$_COOKIE"
)
)
}
}
/**
* A sink that redirects the user via `header()`.
*/
class RedirectSink extends DataFlow::ExprNode {
RedirectSink() {
exists(FunctionCallExpr call |
call.getFunctionName() = "header" and
this.asExpr() = call.getArgument(0)
)
}
}
module OpenRedirectConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UserInputSource }
predicate isSink(DataFlow::Node sink) { sink instanceof RedirectSink }
}
module OpenRedirectFlow = TaintTracking::Global<OpenRedirectConfig>;
import OpenRedirectFlow::PathGraph
from OpenRedirectFlow::PathNode source, OpenRedirectFlow::PathNode sink
where OpenRedirectFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "This redirect URL depends on a $@.", source.getNode(),
"user-provided value"

8
php/ql/test/qlpack.yml Normal file
View File

@@ -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

11
php/tools/BUILD.bazel Normal file
View File

@@ -0,0 +1,11 @@
load("//misc/bazel:pkg.bzl", "codeql_pkg_files")
codeql_pkg_files(
name = "tools",
excludes = [
"BUILD.bazel",
],
exes = glob(["**/*"]),
prefix = "tools",
visibility = ["//php:__pkg__"],
)

5
php/tools/autobuild.cmd Normal file
View File

@@ -0,0 +1,5 @@
@echo off
type NUL && "%CODEQL_EXTRACTOR_PHP_ROOT%\tools\%CODEQL_PLATFORM%\extractor" autobuild
exit /b %ERRORLEVEL%

3
php/tools/autobuild.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec "${CODEQL_EXTRACTOR_PHP_ROOT}/tools/${CODEQL_PLATFORM}/extractor" autobuild

View File

@@ -0,0 +1,9 @@
@echo off
type NUL && "%CODEQL_EXTRACTOR_PHP_ROOT%\tools\win64\extractor.exe" ^
extract ^
--file-list "%1" ^
--source-archive-dir "%CODEQL_EXTRACTOR_PHP_SOURCE_ARCHIVE_DIR%" ^
--output-dir "%CODEQL_EXTRACTOR_PHP_TRAP_DIR%"
exit /b %ERRORLEVEL%

9
php/tools/index-files.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
set -eu
exec "${CODEQL_EXTRACTOR_PHP_ROOT}/tools/${CODEQL_PLATFORM}/extractor" \
extract \
--file-list "$1" \
--source-archive-dir "$CODEQL_EXTRACTOR_PHP_SOURCE_ARCHIVE_DIR" \
--output-dir "$CODEQL_EXTRACTOR_PHP_TRAP_DIR"

BIN
php/tools/osx64/extractor Executable file

Binary file not shown.

13
php/tools/qltest.cmd Normal file
View File

@@ -0,0 +1,13 @@
@echo off
type NUL && "%CODEQL_DIST%\codeql.exe" database index-files ^
--prune=**/*.testproj ^
--include-extension=.php ^
--include-extension=.phtml ^
--include-extension=.inc ^
--size-limit=5m ^
--language=php ^
--working-dir=. ^
"%CODEQL_EXTRACTOR_PHP_WIP_DATABASE%"
exit /b %ERRORLEVEL%

13
php/tools/qltest.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
set -eu
exec "${CODEQL_DIST}/codeql" database index-files \
--prune="**/*.testproj" \
--include-extension=.php \
--include-extension=.phtml \
--include-extension=.inc \
--size-limit=5m \
--language=php \
--working-dir=.\
"$CODEQL_EXTRACTOR_PHP_WIP_DATABASE"