This is a somewhat informal list that might aid others.
Type inference is one of the big things Psalm does. It tries to figure out what different PHP elements (function calls, if/for/foreach statements etc.) mean for the data in your code.
Within type inference there are a number of tricky areas:
Loops are hard to reason about - break and continue are a pain. This analysis mainly takes place in LoopAnalyzer
There are lots of edge-cases when combining types together, given the many types Psalm supports. Type combining occurs in TypeCombiner
.
What effect do different PHP elements have on user-asserted logic in if conditionals, ternarys etc. This logic is spread between a number of different classes.
Figuring out how templated code should work (@template
tags) and how much it should work like it does in other languages (Hack, TypeScript etc.) is tricky. Psalm also supports things like nested templates (@template T1 of T2
) which makes things trickier
Detecting unused variables requires some fun data-flow analysis.
Detecting unused classes and methods between different runs requires maintaining references to those classes in cache (see below).
- Supporting formal PHPDoc annotations
- Supporting informal PHPDoc annotations
e.g.
ArrayIterator|string[]
to denote anArrayIterator
over strings - non-Composer projects e.g. WordPress
Requires scanning everything necessary for analysis
Mostly handled by code borrowed from Phan, but can introduce subtle issues, also requires to think about how to make work happen in processes
see below
Requires tracking what methods/properties are used in what other files, and invalidating those results when linked methods change
Reparsing bits of files that have changed, which is hard
When files change Psalm figures out what's changed within them to avoid re-analysing things unnecessarily
When people write code, it's not always pretty as they write it. A language server needs to deal with that bad code somehow
Figuring out what changed, making edits that could have been made by a human
hard to change more than you need