Repository navigation
Add Template::FindUndeclaredVariables (0236) - #603
Conversation
jinja2.meta.find_undeclared_variables for Jinja2C++: the source is parsed again and the parse's NameResolver reports the names read or stored in a branch that no store, frame around them or binder declares, without the environment's globals. Trans variables and message names are now reads of the resolver too, a set block in a loop's else stores in the else's frame, and imported names besides their alias get a store kind of their own. Template.module is filed as 0284. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XALEgQvXdN6pfE79XkgggV
|
@codex review Generated by Claude Code |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5a0c9e095c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex review of #603: replace per-read scans of a frame's stores with an index of each name's first store per frame and of the frames that read a macro's special names, so the check is linear (5,000 sets: 0.5 s -> 29 ms in Debug). A set block's filters now read in the block's frame, so a later store in it hides the outer name as in Jinja2. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XALEgQvXdN6pfE79XkgggV
|
@codex review @codex security review a54c8a4 addresses both earlier findings: declaration lookup is now indexed (linear), and set-block filters read in the block's frame. The diff touches the template parser. Generated by Claude Code |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex security review Generated by Claude Code |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Requested by Ruslan · project thread
Before: a host could not ask a loaded template which variables it needs;
jinja2.meta.find_undeclared_variableshad no counterpart (parity.md ❌), andGetMetadataonly reads the C++-specific{% meta %}block. Trans blocks' message names ({% trans %}{{ user }}{% endtrans %}) and bare trans variables ({% trans user %}) were also invisible to the name resolver, so they could render from the wrong scope when the same name was a loop target or macro argument elsewhere.After:
Template::FindUndeclaredVariables()/TemplateW::...returnsResult<std::vector<std::string>, CharT>with the sorted names Jinja2'smeta.find_undeclared_variablesreports, without the built-in and environment globals;TemplateNotParsedbefore a successful Load. Trans names render from the right scope (the verifier's differential fuzz against Python: 0 differences on 12k trans-heavy templates, where master differed on ~110).How: the call parses the kept source again into an arena of its own and asks that parse's
NameResolver(newUndeclaredNames/IsDeclared/DeclaresAtEntryover aDeclarationIndexof each name's first store per frame and the frames that read a macro's special names, so the check is linear), whose frames already mirror Jinja2's idtracking (0117, 0168), soLoadpays nothing (instruction gate: max +1.3%, Load only). A name counts when it is read, or stored in anifbranch, with no earlier store in its frame, no store in an enclosing frame (a block sees only its own), and no binder (loop targets andloop, macro/call-block arguments withcaller/varargs/kwargs, a default's own macro arguments, and the specials only when the body reads them,self, a block'ssuper). Parser changes: trans message names and bare trans variables areAddUsereads; a set block in a loop'selsestores like a plainsetthere; a set block's filters read in the block's frame, as in Jinja2; imported names besides their alias use a newStoreKind::Hidden(render-neutral). Includes, imports andextendsparents are not followed, as in Jinja2.Divergences (in docs/tasks/0236):
gettext/ngettextare never reported (they are globals whenever the i18n extension is on, as with Jinja2's installed callables);{% autoescape e %}readsein the enclosing frame; Jinja2's synthetic_transis not reported;{% set x | f(a) %}with no later store ofarenders and reportsa, where Jinja2 3.1's compiler raises an AssertionError.Template.moduleis filed as task 0284.Tests: test/undeclared_variables_test.cpp, 81 templates checked against Jinja2 3.1 (do, loopcontrols, i18n with null translations), narrow and wide, plus globals, not-loaded, trans and set-block-filter render rows.
Roles: main session; verifier (3 rounds: round 1 found a trans render regression for bare variables and a loop-else set-block false positive, round 2 a wrong rule for special names in macro defaults, round 3 one block-scoping edge; all fixed, with differential fuzz against Python and asan+ubsan clean). Codex: 2 findings, 2 fixed (the filter-block half of one declined: Jinja2 reads filter-block arguments in the enclosing frame). Red pushes: none so far.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XALEgQvXdN6pfE79XkgggV