Summary: Update the docs, which contained a SSR-based linter, to use the new trait.
Reviewed By: TD5
Differential Revision: D80527631
fbshipit-source-id: 9a0258b11818f005ebf3f2013b3ebd515512d592
Summary: One of the two tasks is completed, so update the comment.
Reviewed By: TD5
Differential Revision: D80527750
fbshipit-source-id: 4e1a7575229f65f24a074b47c333a4672342e86d
Summary: Convert the `unnecessary_map_to_list_in_comprehension` linter to use the new trait.
Reviewed By: TD5
Differential Revision: D80521249
fbshipit-source-id: ed4323548de50d7fe2bcad53a168a8d6f7906182
Summary:
Convert the `binary_to_sigil` linter to use the new `SsrPatternsLinter` trait.
This makes the linter code a lot more readable, decoupling the generic logic from the specific parts.
Reviewed By: TD5
Differential Revision: D80518920
fbshipit-source-id: 420a9aa073a41c2767a8d8158fdfe9e31d59888e
Summary:
Similar to the `FunctionCallLinter` introduced in D80341881, this introduces a `SsrPatternsLinter` trait which abstracts away a lot of the implementation details for Ssr-based linters, allowing the ELP developer to focus on the more important callback functions.
We convert the `UnnecessaryFoldToBuildMap` linter to showcase how the linter can be used in practice.
In the process, fix a few minor bugs in the linter, which emerged from the conversion.
Reviewed By: TD5
Differential Revision: D80462420
fbshipit-source-id: c3d047ff6a020e17194f7a93a0df85775cda6260
Summary: In preparation for introducing a new category of SSR-based linters.
Reviewed By: TD5
Differential Revision: D80462418
fbshipit-source-id: f86fcdc6e39a27f5b5175db6047ab4e511fd27d1
Summary: In preparation for a `SsrLinter` trait, split the `FunctionCallLinter` into a generic and a specific part, so that the generic part can be used for `SsrLinter`.
Reviewed By: TD5
Differential Revision: D80451562
fbshipit-source-id: 916026c4955ef78d466a568ae9ce51d886c50534
Summary:
Convert the `no_eval` linter to use the new trait, to remove duplication.
The linter had some custom filtering logic, so extend the trait to allow an optional `should_process_file_id` callback.
Reviewed By: TD5
Differential Revision: D80443713
fbshipit-source-id: 1e971e1e6de1215a1771542a42b829c58ccb7279
Summary: Convert the `no_error_logger` linter to use the new trait, to showcase the amount of boilerplate removed.
Reviewed By: TD5
Differential Revision: D80347608
fbshipit-source-id: 990ec52b486d2d88b98f81878a70af7eca43f970
Summary: Convert the `no_size` linter to use the new trait, to showcase the amount of boilerplate removed.
Reviewed By: TD5
Differential Revision: D80346647
fbshipit-source-id: 201901a737a16740c0a2c3504e65a2cb84b2a1c6
Summary: Convert the `no_garbage_collect` linter to use the new trait, to showcase the amount of boilerplate removed.
Reviewed By: TD5
Differential Revision: D80344745
fbshipit-source-id: a8f42a2c844ba65d52e8ac89fcdd69f3172342d5
Summary:
# Context
Diagnostics are calculated for every `file_id` (i.e. module) in the system, causing multiple calls to extract the function matches. To avoid the overhead, the `lazy_static` macro is usually used.
# Problem
The code required to specify matches is quite verbose.
# Solution
Create a helper macro that minimizes the amount of code written by the lint author.
Note: ideally, we'd get rid of the multiple calls in the first place. That could be done as a next step.
Reviewed By: TD5
Differential Revision: D80342732
fbshipit-source-id: 4cd2f8635b12e083feb37c369f0703cace9b7c56
Summary:
# Context
Today, adding a linter to ELP today relies on [quite a bit of non-obvious boilerplate](https://whatsapp.github.io/erlang-language-platform/docs/contributing/linters/). Furthermore, each linter performs its own logical traversal of an Erlang module.
# Problem
Some time ago, a somewhat experimental [`DiagnosticTemplate`](https://www.internalfb.com/code/fbsource/[bc7dd2289948f9c9c392c27c6c8db79cf81421b1]/fbcode/whatsapp/elp/crates/ide/src/diagnostics/helpers.rs?lines=28) mechanism was introduced, to reduce the amount of boilerplate required, but the approach has certain limitations:
* It still requires specifying a number of details even when default behaviours are good enough
* It still requires the developer to traverse the module, assuming knowledge about `def_map` and `find_call_in_function`
# Solution
By leveraging a trait, we can limit the amount of boilerplate (and knowledge!) required by an ELP developer to add a new linter.
Given that a good number of the existing linters detect function call applications, I am starting here by factoring out the common code into a `FunctionCallLinter`, which can eventually be generalized further, to allow additional types of linters.
This diff introduces the new linter, and converts a first linter (`sets_version_v2`) to use the new trait.
To keep the changes minimal, I am copying the logic from `diagnostics_from_descriptors` to `diagnostics_from_linters`. Specifically, the extraction of the `is_generated` and `is_test`, populating the same `Descriptor` as before (just, in a transparent way to the user).
The extra filtering which was present in `diagnostics_from_linters` is not necessary in the new version, where we can assume a 1:1 relation between a linter and a code.
Finally, the `find_call_in_function` API is only called once, at the top level, once all the linter "specifications" are extracted.
Reviewed By: TD5
Differential Revision: D80341881
fbshipit-source-id: 68b972f32202309f28f7bcdaddd641513ac90d9f
Summary:
The helper function is used in a number of `DiagnosticTemplate` linters (`no_size`, `no_error_logger`, etc) to detect function calls matching a given spec.
By using the extended `def_map`, we also include calls in included file (via `-include` or `-include_lib`). This is most likely a non-desired behaviour, since we'd end up returning diagnostics for included files, too, with incorrect ranges.
This also makes the linters behaviour consistent with the other linters (e.g. `debugging_function`, `atoms_exhaustion`, etc) which use a local `def_map_local`.
This is a step in preparation of the factoring out of the linters boilerplate code into a single method.
Reviewed By: TD5
Differential Revision: D80243757
fbshipit-source-id: a0d4145639fc10179b6e53ce88c3e18bdd101015
Summary: Small quality of life, so that users of the ELP CLI can auto-complete diagnostic codes. Both codes and labels are presented. We could perform some fuzzy matching, but for now let's keep things simple and match on the prefix provided.
Reviewed By: TD5
Differential Revision: D80093860
fbshipit-source-id: d2a97409c8f6f1e9cf548b47cd0c276d85b513e0
Summary: No need to have "Applying fix(es)" in our output when we know whether there's one or more elements. Instead, we can just pick the correct form.
Reviewed By: robertoaloi
Differential Revision: D79890374
fbshipit-source-id: f9604db74004619703c801c28477fb17b6b0015a
Summary: I noticed CI was broken on GitHub.
Reviewed By: jcpetruzza
Differential Revision: D80002359
fbshipit-source-id: 06db89f7a7b70116203ef98eb1c761ca401989a5
Summary: Raises a warning if a compile directive of type `nowarn_*` is used.
Reviewed By: TD5
Differential Revision: D79635553
fbshipit-source-id: 369c38f5b80bfa7cd3830cbef22da59aa8eed380
Summary:
This makes it compile on Windows and work from the command line, but still can't get it to work properly with Windows VS Code extension.
```shell
[2025-07-17T18:47:44.619Z] [ERROR elp_ide_db::docs] Unknown application - could not load app_data to determine whether file is on OTP
[2025-07-17T18:47:44.619Z] [ERROR elp_ide_db::docs] No corresponding appdata found for file, so no docs can be loaded
[Error - 9:47:44 PM] [elp_ide_db::docs] Unknown application - could not load app_data to determine whether file is on OTP
[Error - 9:47:44 PM] [elp_ide_db::docs] No corresponding appdata found for file, so no docs can be loaded
[2025-07-17T19:06:47.466Z] [ERROR elp_ide_db::docs] Unknown application - could not load app_data to determine whether file is on OTP
[2025-07-17T19:06:47.466Z] [ERROR elp_ide_db::docs] No corresponding appdata found for file, so no docs can be loaded
[Error - 10:06:47 PM] [elp_ide_db::docs] Unknown application - could not load app_data to determine whether file is on OTP
[Error - 10:06:47 PM] [elp_ide_db::docs] No corresponding appdata found for file, so no docs can be loaded
```
~~and when running `elp shell`~~ Turns out `watchman` was not installed. Haven't seen it in setup docs.
```shell
Could not find project. Are you in an Erlang project directory, or is one specified using --project?
```
[build_info.json](https://github.com/user-attachments/files/21303371/build_info.json) and [project_imfo.json](https://github.com/user-attachments/files/21303726/project_imfo.json) for the newly generated rebar3 project
https://github.com/WhatsApp/erlang-language-platform/issues/26
Pull Request resolved: https://github.com/WhatsApp/erlang-language-platform/pull/111
Reviewed By: TheGeorge
Differential Revision: D78658932
Pulled By: alanz
fbshipit-source-id: 0477ad649a6dc4542d5494360d9c8c0a8374a0ba
Summary:
`elp shell` relies on watchman to monitor for changes.
Document this fact in the web site
Reviewed By: Balajiganapathi
Differential Revision: D78660276
fbshipit-source-id: 03e8b5fdc8b5cbb8fca0b8b008a8003d221b7c2b
Summary: Explicitly check if watchman is available when starting up, and bail if not.
Reviewed By: michalmuskala
Differential Revision: D78662213
fbshipit-source-id: 0d648e0f5f6d84c8f275c067f4c25a0790e61956
Summary:
We have added Index impl for FoldBody with and without using references.
This diff adds unit tests for both the implementations.
Reviewed By: alanz
Differential Revision: D78659116
fbshipit-source-id: 404144735399c82a8a2d265298ff35ac9bd0a672
Summary:
The Erlang local include processing is intended to search in the include path of the initial application, then the include paths of all dependencies.
This is also how it works in buck2.
This diff aligns ELP with this by
- Include the app name in the local include key for the include mapping
- If the initial lookup fails, walk the tree of dependencies looking for a result
Reviewed By: TD5
Differential Revision: D78488506
fbshipit-source-id: 5ec98a0ecde04883db480b9adecae19ea0e784c6
Summary:
The `buck::IncludeMapping` keeps a map from the include(_lib) directive to the appropriate file path for all buck targets in the project.
This does not, however include the ones from OTP.
This diff remedies that.
Reviewed By: TheGeorge
Differential Revision: D78487455
fbshipit-source-id: 4d69541133fc3b0afd6b1afa07db80c13f61c5eb
Summary:
It is time to explicitly check that the application referred to in an `include_lib` directive is part of the (transitive) dependencies of the originating file application (== buck target).
This processing is currently only applied to buck projects, so the `basedb::include` processing is updated to distinguish between the case where there is a mapping, and where there is not. Prior to this it tried the include mapping and fell back to more lax processing. This is no longer valid, as we may explicitly decide that an `include_lib` should **not** be resolved, in which case there should be no fallback processing.
We also need to clearly distinguish between a local lookup and an `include_lib` lookup in the `IncludeMapping`. We do so by encoding the key into the hashmap of include strings to paths with an `L:` or 'R:` for the two cases.
An alternative would be to store a tuple of `(IncludeMappingScope, <lookup_path>)`.
Reviewed By: TheGeorge
Differential Revision: D77937818
fbshipit-source-id: bb3827b0ead94103025f784c4ff713991418f944
Summary: It is only used in one place. This prepares for changes to the calculation in the next diff.
Reviewed By: TheGeorge
Differential Revision: D78486961
fbshipit-source-id: c01cb401a3eb6bb36c8b55e75b02ce04a8309928
Summary:
As title. It is now a struct, this is the natural home.
And it will simplify adding OTP paths in a later diff.
Reviewed By: TheGeorge
Differential Revision: D78486867
fbshipit-source-id: ce012c07ae13ab0276a00f0dcd69d589c73d811c
Summary:
When `erlc` resolves an `-include_lib(..)` directive it does so with the search path of the original file.
Up to now ELP has been taking a lenient approach to include file resolution, and has not precisely resolved according to the explicit dependencies of a given application. The application is determined from the originating `FileId`.
This diff keeps track of the originating `FileId`, so it can be used for more precise tracking in a later diff
Reviewed By: TD5
Differential Revision: D78165061
fbshipit-source-id: 225c1af47abea00616fc2763a26c6c89ae2db55f
Summary:
As the title says and as proposed in https://github.com/WhatsApp/erlang-language-platform/issues/67, this adds a config option that allows ignoring specific modules for `eqwalize-all`.
I think it would be nice to also allow some form of patterns (regex or shell-style globs) in addition to plain module names, e.g.
```
[eqwalizer]
ignore_modules = ["some_module", "some_app_*_pb"]
```
Q: Would patterns also be acceptable or does that violate some project rules or conventions?
Closes https://github.com/WhatsApp/erlang-language-platform/issues/67
Pull Request resolved: https://github.com/WhatsApp/erlang-language-platform/pull/108
Reviewed By: TheGeorge
Differential Revision: D77657335
Pulled By: alanz
fbshipit-source-id: 74b8e37e998d436485137c978758793bfe805334
Summary:
Some new modules were added to the buck2 directory, they affect expected results for one of the ELP tests.
Fix them
Reviewed By: mapoulin
Differential Revision: D78558795
fbshipit-source-id: 3e3b0b9b7c8c70699e91735fa0baa349ebf6c01a
Summary:
- Add some metadata indicating the files it applies to
- Fix the formatting
Reviewed By: TD5
Differential Revision: D78276191
fbshipit-source-id: f8c47162dea2dd97574fb34de9ba436496aef9fb
Summary:
We have moved to `cargo 1.88.0 (873a06493 2025-05-10)` internally. This has enabled a check for `uninlined_format_args`.
Update the local clippy.toml to match this, and run
```
cargo clippy --workspace --tests --fix
```
to generate this diff
This may be related to https://github.com/rust-lang/rust-clippy/issues/14694
Reviewed By: TD5
Differential Revision: D78345648
fbshipit-source-id: a218be720e34b06ed08c52b5f7db936940bc2c37
Summary:
When we process a `DidCloseTextDocument` we sent a `PublishDocuments` notification with empty diagnostics to the server, to clear its diagnostic store.
But if at the time of closing the file we are calculating diagnostics for it, these will be sent when the diagnostic calculation ends.
This diff ensures we clear all current diagnostics (except eqwalizer project ones, if enabled) when we close the file, and does not send diagnostics for unopened files.
Reviewed By: TD5
Differential Revision: D78275536
fbshipit-source-id: f4d380e0022102dcb74151f027df4d5b0cdd58c5
Summary:
We use `AppData` as our general representation of an Erlang application in ELP, originally in the rebar3 sense.
The ELP design standardises on this information, whatever the origin of the project data in an ELP Project.
For a buck2 project, we use the last part of a buck2 target as the `AppData::name`.
So the buck target `cell/path/to/app:app_name` would give rise to "app_name".
In some circumstances involving test fixtures we cannot guarantee that the derived "app_name" is unique.
This diff adds the original full buck target name to `AppData`, so this can be used as needed. It is used in a later diff, still unpublished.
Reviewed By: TD5
Differential Revision: D78160505
fbshipit-source-id: 3b14d50709328b53079d648c5eb2ae6a86311d6d
Summary:
Migrate ELP to Salsa 0.19, featuring a completely new API. Overall, the migration follows closely the one of [rust-analyzer](74620e64ec (diff-5828430af308cfce455219d40dac23f272baf89378ada6febee5d6a186ffe0fb))
Major changes:
- Bump `rust-analyzer` to 2025-03-17
- Use `ra_ap_query-group-macro` to emulate the old `query_group` macro.
- `SourceDatabase` is split into two, `RootQueryDb` containing queries inside a `query_group` and `SourceDatabase` which deals with salsa inputs only.
- All parameterized inputs (`FileText`, `SourceRoot`, ...) are extracted as structs, and a read/write API is provided according to Salsa 0.19 principles. This API was previously automatically derived by Salsa.
- Cycle handling functions signatures are modified.
- Create structs for all interned values, also following Salsa 0.19 guidelines.
Reviewed By: alanz
Differential Revision: D75066592
fbshipit-source-id: 233e626ca3c3c9004241e2064d2bcf7e2d0106ed
Summary:
As title.
Since we currently can have multiple macro definitions, we put candidates in a set to filter them out.
Reviewed By: michalmuskala
Differential Revision: D78087578
fbshipit-source-id: 084db136f7842185cd840c1d13a00cb75d2e8e00
Summary:
Because ELP does not (yet) properly process conditional macros, a macro defined with conditional alternatives will show up multiple times.
Add a test to demonstrate this case, which will be fixed in the next diff.
Reviewed By: michalmuskala
Differential Revision: D78087402
fbshipit-source-id: e450a3d8f1cbd08b3040a5b70f114bafd8227800