Dead Guard Detection
Homeboy audit flags function_exists('…'), class_exists('…'), and defined('…') guards whose
checked symbol is guaranteed to exist at runtime. Such guards are reachable-but-dead: the else
branch can never fire, the code becomes harder to read, and refactors keep carrying forward stale
defensive scaffolding.
How the detector decides a symbol is guaranteed
A symbol is considered guaranteed when any of the following hold:
- The plugin declares
Requires at least: X.Yin its main-file header and the symbol shipped in Core at or before that version (table covers common symbols such asWP_Ability@ 6.9,wp_generate_uuid4@ 4.7,wp_timezone@ 5.3). - The plugin’s main file contains an unconditional
require/require_onceof a well-known vendor bootstrap (e.g.vendor/woocommerce/action-scheduler/action-scheduler.php). Requires inside anif ( ! class_exists(…) ) { … }block are ignored. composer.jsonlists a known package underrequireorrequire-devwhose symbols the detector recognizes (e.g.woocommerce/action-scheduler).
Both direct and negated guards are reported:
if ( ! class_exists( 'WP_Ability' ) ) { return; } // flagged
if ( function_exists( 'as_schedule_single_action' ) ) { … } // flagged when AS is bootstrappedFinding output
convention:dead_guardkind:dead_guardseverity:warning
Dead-guard findings participate in baseline comparisons like any other audit finding.
Extending the symbol table
The WP-core symbol table lives in src/core/code_audit/requirements.rs. Add new rows as
(symbol_name, introduced_in_encoded_version, kind) — kind is 'f' for functions, 'c' for
classes, 'k' for constants. Version is encoded as major * 100 + minor (e.g. 6.9 → 609).
Vendor packages are seeded via seed_vendor_symbols_from_path (bootstrap-require match) and
apply_composer_requires (composer.json match). Add new packages there.