diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 209ac110a..63a749bf1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,11 +11,6 @@ You can create an issue [here](https://github.com/vimeo/psalm/issues/new), but b * Make sure that you are using the latest version (`master`). * It’s by no means a requirement, but if it's a bug, and you provide demonstration code that can be pasted into https://psalm.dev, it will likely get fixed faster. -## Pull Requests +## Contributing code and documentation -[Here’s a guide to the codebase you may find useful](docs/how_psalm_works.md). - -Before you send a pull request, make sure you follow these guidelines: - -* Make sure to run `composer tests` and `./psalm` to ensure that Travis builds will pass -* Don’t forget to add tests! +Have a look at the [contributing documentation](docs/contributing/index.md) which is [mirrored on Psalm’s website](https://psalm.dev/docs/contributing). diff --git a/docs/how_psalm_works.md b/docs/contributing/how_psalm_works.md similarity index 100% rename from docs/how_psalm_works.md rename to docs/contributing/how_psalm_works.md diff --git a/docs/contributing/index.md b/docs/contributing/index.md new file mode 100644 index 000000000..d2c241438 --- /dev/null +++ b/docs/contributing/index.md @@ -0,0 +1,24 @@ +# Contributing to Psalm + +Psalm is made possible through the contributions of almost 200 developers. + +Hopefully you can be one of them? + +## Getting started + +[Here’s a rough guide to the codebase](how_psalm_works.md). + +I've also put together [a list of Psalm’s complexities](what_makes_psalm_complicated.md). + + +## Pull Requests + +Before you send a pull request, make sure you follow these guidelines: + +Run integration checks locally: + +- `composer phpcs` - checks the code is properly linted +- `vendor/bin/paratest` - runs PHPUnit tests in parallel +- `./psalm` - runs Psalm on itself + +If you're adding new features or fixing bugs, don’t forget to add tests! diff --git a/docs/contributing/what_makes_psalm_complicated.md b/docs/contributing/what_makes_psalm_complicated.md new file mode 100644 index 000000000..5f9415516 --- /dev/null +++ b/docs/contributing/what_makes_psalm_complicated.md @@ -0,0 +1,82 @@ +# Things that make developing Psalm complicated + +This is a somewhat informal list that might aid others. + +## Type inference + +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 + +Loops are hard to reason about - break and continue are a pain. This analysis mainly takes place in `LoopAnalyzer` + +#### Combining types + +There are lots of edge-cases when combining types together, given the many types Psalm supports. Type combining occurs in `TypeCombiner`. + +#### Logical assertions + +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. + +#### Generics & Templated code + +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 dead code + +Detecting unused variables requires some fun [data-flow analysis](https://psalm.dev/articles/better-unused-variable-detection). + +Detecting unused classes and methods between different runs requires maintaining references to those classes in cache (see below). + +## Supporting the community +- **Supporting formal PHPDoc annotations** +- **Supporting informal PHPDoc annotations** + e.g. `ArrayIterator|string[]` to denote an `ArrayIterator` over strings +- **non-Composer projects** + e.g. WordPress + +## Making Psalm fast + +#### Parser-based reflection + +Requires scanning everything necessary for analysis + +#### Forking processes** (non-windows) + +Mostly handled by code borrowed from Phan, but can introduce subtle issues, also requires to think about how to make work happen in processes + +#### Caching thing + +see below + +## Cache invalidation + +#### Invalidating analysis results + +Requires tracking what methods/properties are used in what other files, and invalidating those results when linked methods change + +#### Partial parsing + +Reparsing bits of files that have changed, which is hard + +## Language Server Support + +#### Handling temporary file changes + +When files change Psalm figures out what's changed within them to avoid re-analysing things unnecessarily + +#### Dealing with malformed PHP code + +When people write code, it's not always pretty as they write it. A language server needs to deal with that bad code somehow + +## Fixing code with Psalter + +#### Adding/replacing code + +Figuring out what changed, making edits that could have been made by a human + +#### Minimal diffs + +hard to change more than you need diff --git a/docs/what_makes_psalm_complicated.md b/docs/what_makes_psalm_complicated.md deleted file mode 100644 index 550fb3fd1..000000000 --- a/docs/what_makes_psalm_complicated.md +++ /dev/null @@ -1,50 +0,0 @@ -# Things that make developing Psalm complicated - -This is a somewhat informal list that might aid others. - -## Statement analysis -- **Type inference** - what effect do different PHP elements (function calls, if/for/foreach statements etc.) have on the types of things -- **Especially loops** - loops are hard to reason about - break and continue are a pain -- **Also dealing with literal strings/ints/floats** -- **Code liveness detection** - what effect do different PHP elements have on whether code is in scope, whether code is redundant -- **Logical assertions** - what effect do different PHP elements have on user-asserted logic in if conditionals, ternarys etc. -- **Generics & Templated code** - Figuring out how templated code should work (`@template` tags), how much it should work like it does in other languages (Hack, TypeScript etc.) - -## Supporting the community -- **Supporting formal PHPDoc annotations** -- **Supporting informal PHPDoc annotations** - e.g. `ArrayIterator|string[]` to denote an `ArrayIterator` over strings -- **non-Composer projects** - e.g. WordPress - -## Making Psalm fast -- **Parser-based reflection** - requires scanning everything necessary for analysis -- **Forking processes** (non-windows) - mostly handled by code borrowed from Phan, but can introduce subtle issues, also requires to think about how to make work happen in processes -- **Caching things** - see below - -## Cache invalidation -- **Invalidating analysis results** - requires tracking what methods/properties are used in what other files, and invalidating those results when linked methods change -- **Partial parsing** - Reparsing bits of files that have changed, which is hard - -## Language Server Support -- **Making Psalm fast** - see above -- **Handling temporary file changes** -- **Dealing with malformed PHP code** - When people write code, it's not always pretty as they write it. A language server needs to deal with that bad code somehow - -## Fixing code with Psalter -- **Adding/replacing code** - Figuring out what changed, making edits that could have been made by a human -- **Minimal diffs** - hard to change more than you need