Skip to content

Support Psalm 7 - #389

Merged
danog merged 3 commits into
psalm:5.xfrom
danog:psalm-7
Oct 5, 2026
Merged

danog merged 3 commits into
psalm:5.xfrom
danog:psalm-7

Conversation

@danog

@danog danog commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

The plugin requires vimeo/psalm: ^6 || dev-master, and with minimum-stability: beta composer resolves dev-master, which is now Psalm 7. Psalm 7 changed the internals the Twig tainting uses, so the plugin no longer works with it:

  • every Twig taint analysis crashed: data flow nodes can only be built through DataFlowNode's factories (its constructor is private), and DataFlowNode::getForMethodArgument() / getForMethodReturn() take a function's storage instead of labels and locations;
  • HeaderBagHandler called Codebase::addTaintSource() with the Psalm 6 arguments (taints before the location, taints as a list of names), a TypeError on Psalm 7 as soon as the taint analysis met $request->headers->get('user-agent'). It also dropped the type addTaintSource() returns, which is the only way the source reaches the value (on Psalm 6 too), so the user-agent source never tainted anything.

This drops Psalm 6 support, requires vimeo/psalm: ^7 || dev-master, and requires psalm/psalm-plugin-api: ^0.3, the plugin API this is written for:

  • Twig tainting: template variables and the template's output are location-less nodes (DataFlowNode::getForPropertyFetch(), the factory of a node with only an id), the nodes inside a template are assignment nodes at their location in the template, and the argument of render() is resolved with DataFlowNode::getForMethodArgumentById().
  • HeaderBagHandler: addTaintSource() is called with the Psalm 7 signature (TaintKind::ALL_INPUT), and its result is used.
  • Psalm 7 purity analysis: the plugin's own code now has the purity annotations Psalm 7 asks for (MissingPureAnnotation, MissingImmutableAnnotation), added with psalm --alter. The @psalm-suppress UnusedClass of TemplateFileAnalyzer, which Psalm 7 reports as unused, is removed. psalm --find-dead-code --find-unused-psalm-suppress reports no errors.
  • Tests: Psalm 7 also suggests purity annotations for the code under test, which the tests aren't about. The test module sets those suggestions to info, as it already does for UnusedVariable; the Twig tainting feature, which has its own configuration, annotates its stub function instead. The unit test building a StatementsAnalyzer passes the new $root_scope argument and initialises the project files that reporting an issue now reads.

phpunit (45 tests) and codecept run -g symfony-common (96 tests) pass with Psalm dev-master. Dropping Psalm 6 is a breaking change, so this probably calls for a new major version.

@danog
danog merged commit 7565b3b into psalm:5.x Oct 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant