refactor(dynamic): replace reflective invocation with route replay logic for Micronaut and Quarkus, remove annotation stubs, and enhance runtime path binding

This commit is contained in:
elipeter 2026-05-26 11:38:12 -05:00
parent 61bfc0cf96
commit 41c7b73575
26 changed files with 1256 additions and 224 deletions

View file

@ -1018,10 +1018,10 @@ pub(crate) fn collect_idents(n: Node, code: &[u8], out: &mut Vec<String>) {
/// AST kind names for subscript / index expressions
/// across the languages whose container-element flow we model.
///
/// JS/TS use `subscript_expression`; Python uses `subscript`; Go uses
/// `index_expression`. Other languages either lower indexing through
/// method calls (Rust slice indexing) or are out of scope for the
/// initial W5 rollout (Java/Ruby/PHP/C/C++).
/// JS/TS and C/C++ use `subscript_expression`; Python uses `subscript`;
/// Go uses `index_expression`. Other languages either lower indexing
/// through method calls (Rust slice indexing) or are out of scope for
/// the initial W5 rollout (Java/Ruby/PHP).
#[inline]
pub(crate) fn is_subscript_kind(kind: &str) -> bool {
matches!(
@ -1086,7 +1086,8 @@ pub(crate) fn subscript_components<'a>(n: Node<'a>, code: &'a [u8]) -> Option<(S
return None;
}
let arr_text = text_of(arr, code)?;
// PHP-style `$x` strip not needed here, Go/JS/Python don't use it.
// PHP-style `$x` strip not needed here; the supported languages
// don't use it for local array identifiers.
let idx_text = text_of(idx, code)?;
Some((arr_text, idx_text))
}

View file

@ -2507,6 +2507,23 @@ pub(super) fn push_node<'a>(
}
}
// Conditions can contain source/sink calls whose argument side effects are
// load-bearing for taint, e.g. C `if (!fgets(buf, n, stdin)) return;`.
// Classify the condition call so output-parameter sources still lower as
// SSA calls while the CFG node keeps its branch shape.
if labels.is_empty()
&& matches!(lookup(lang, ast.kind()), Kind::If | Kind::While)
&& let Some(cond) = ast.child_by_field_name("condition")
&& let Some((ident, ident_span)) = first_call_ident_with_span(cond, lang, code)
&& let Some(l) = classify(lang, &ident, extra)
{
labels.push(l);
text = ident;
if inner_text_span.is_none() {
inner_text_span = Some(ident_span);
}
}
// For `if let` / `while let` patterns: try to classify the value expression
// in the let-condition as a source/sink. E.g. `if let Ok(cmd) = env::var("CMD")`
// should recognise `env::var` as a taint source and label this node accordingly.
@ -3143,11 +3160,12 @@ pub(super) fn push_node<'a>(
};
// Extract condition metadata for If nodes.
let (condition_text, condition_vars, condition_negated) = if kind == StmtKind::If {
extract_condition_raw(ast, lang, code)
} else {
(None, Vec::new(), false)
};
let (condition_text, condition_vars, condition_negated) =
if matches!(lookup(lang, ast.kind()), Kind::If) {
extract_condition_raw(ast, lang, code)
} else {
(None, Vec::new(), false)
};
// Extract per-argument identifiers for Call nodes.
// Also extract for gated-sink nodes so payload-arg filtering works.