Summary:
We may want to disable a linter for a certain set of applications. This diff introduces such a mechanism:
```
[linters.my_linter]
exclude_apps = ["app_a", "app_2"]
```
Reviewed By: alanz
Differential Revision: D89658976
fbshipit-source-id: 78e1cf13ec22f1bf7ed1b6df6892cdad5ca2dfe5
Summary: Missed during the original rename.
Reviewed By: alanz
Differential Revision: D89460380
fbshipit-source-id: 60446aa3f505d635ad5ddc842b2d420c24f0a9d2
Summary: So that version control systems do not try to publish the directory.
Reviewed By: alanz
Differential Revision: D89550389
fbshipit-source-id: d60646ddd4e8f0ae443673dac3c49efbac60dba7
Summary:
We already have a feature to understand if Buck2 is enabled or not. Let's use that one instead of a constant.
This change has no effect anyway since the only two use cases are currently marked as "ignored".
Also remove the extra check inside the helper (we already do it in both tests).
Reviewed By: alanz
Differential Revision: D89549782
fbshipit-source-id: 82e5bbf00c463dca3f4937d2d2a12d16aebc3c19
Summary:
The test projects are now standalone, so the Buck2 tests can be enabled in CI.
Two major fixes to the tests:
* Use the project directory to calculate the project root (there's no `.buckconfig` for the ELP crate as a whole in OSS)
* Fix expectations for the Buck2 errors (no URL in OSS)
Reviewed By: alanz
Differential Revision: D89547047
fbshipit-source-id: 76fa8bcc1fadabbeb9ea59245d36d2aacd98a023
The internal and external repositories are out of sync. This Pull Request attempts to brings them back in sync by patching the GitHub repository. Please carefully review this patch. You must disable ShipIt for your project in order to merge this pull request. DO NOT IMPORT this pull request. Instead, merge it directly on GitHub using the MERGE BUTTON. Re-enable ShipIt after merging.
fbshipit-source-id: 39bc64c1a96888b1034f7807ced9b7b2365df04e
Summary:
Convert old EDoc style syntax (%%% doc, end) in test suite to plain
comments. EDoc documentation is unnecessary in test suites.
Differential Revision: D89526339
fbshipit-source-id: 0111f2ded79a7e802d29b95d6b79889e0a55af32
Summary: We want to enable Buck2 tests on GitHub. This requires a bit of groundwork.
Reviewed By: michalmuskala
Differential Revision: D88959148
fbshipit-source-id: e5f88f561e061635aae05c4e3bc22382771a8908
Summary:
In non-test Erlang code, the following is almost always intended as assignment of a value to the LHS variable
```
Var = expr()
```
It is actually a match, and may fail if `Var` is already bound, and the new value differs from the old.
This diff introduces a diagnostic to warn of this case.
Reviewed By: robertoaloi
Differential Revision: D89374198
fbshipit-source-id: 19dcee50ad6e71d0a606a0eb6cf548b7194d61e6
Summary:
The linter is enabled by default in ELP, and warnings appear in the IDE.
But the same linter is not explicitly added to the CI configuration, so warnings are not reported on diffs or in Contlint.
This diff enables the linter, aligning the IDE and the CI experience. It also makes it possible to track violations via ContLint.
We exclude known false positives via config.
Ideally, we would like to report undefined functions in all files, but there are too many false positives in test files to do so.
This is often due to mocked modules and test suite cleverness. We can revisit this decision in the future. See T249044930 for details.
We disable the linter for tests both in the default value (for the future) and the config (so we don't need to wait for a ELP release to land this change).
Reviewed By: alanz
Differential Revision: D89393641
fbshipit-source-id: bfb9ac760ba79566301087033af95bb805fdeaa0
Summary: The old name was too generic, and could be mis-interepreted as an EDoc linter (a linter that verifies EDoc syntax). By aligning the name of the linter with the actual diagnostic code, we make the intention more clear. No functional change.
Reviewed By: alanz
Differential Revision: D89374941
fbshipit-source-id: bf8518ed9602bdceca2fcbf3ddb00990f56af529
Summary:
Documentation is generally not produced for test files, so do not run the `old_edoc_syntax` linter for tests. If not, edoc references in tests should be converted to plain comments, not to `-moduledoc` or `-doc` attributes.
This behaviour can always be overwritten by setting the `severity` or the `include_tests` properties of the linter via config.
Reviewed By: alanz
Differential Revision: D89374552
fbshipit-source-id: 8a4299fcbd16a82f62efbc14f47fef46cd08fbc0
Summary:
Some clients, such as emacs eglot, do their own project discovery when a new file is opened, even from the target of a go to definition.
They then launch a fresh ELP server if they determine a different project root.
In the ELP server setup we preconfigure the OTP project root as known, but with a project manifest of None. This means go to def into an OTP file ends up with an uninitialized project in the new server.
This diff makes it so that if the project root is known, but has no project manifest, we do discovery on that root.
Pull Request resolved: https://github.com/whatsapp/erlang-language-platform/pull/141
Reviewed By: robertoaloi
Differential Revision: D89169465
Pulled By: alanz
fbshipit-source-id: db180d67df98fd1f1fd61a53a93f9adfa9e93ebd
Summary:
Remove the tag `OTPVersionDependent` which created one expected result per OTP version per snapshot.
Instead, use `OTPXXOnly` (where `XX` is a version number), that skips checks for OTP versions that are not `XX`.
In practice, it's used as `OTP27Only` for now.
Reviewed By: michalmuskala, TD5
Differential Revision: D89378687
fbshipit-source-id: 0421622d825ac4e8f393d32529c01eb17577b5e5
Summary:
Fix two bugs for `--no-stream` for `elp lint`
1. args.skip_stream_print() now skips if either the flag is set, or `--apply-fixes` is set
2. When we are not streaming, and also not applyiing fixes, print the diagnostics
Reviewed By: robertoaloi
Differential Revision: D89369072
fbshipit-source-id: 2279aca861fb09c5b33adb0000e3a58821026064
Summary: Add a test demonstrating that the module rename happens in `.hrl` files too
Reviewed By: TheGeorge
Differential Revision: D89053579
fbshipit-source-id: f999484c08a5c33c76986156c10a2f6a7d34fc52
Summary:
Simplify the rename module logic to use the standard approach, find usages, rename each of them.
And in the process ensure that remote calls in the module being renamed are also renamed.
Reviewed By: robertoaloi
Differential Revision: D88947976
fbshipit-source-id: c703be8392b7ac634ced2c45d8553d33882d460b
Summary:
Certain functions are known to take a module name as an argument. We already have a list of those that correspond to referencing a function as an MFA, in `to_def.rs`. We extend this with some other examples, and check for renaming them too as part of the module rename.
The list is currently incommplete, and can be filled out based on usage. A future diff may look at ways of generating it from `-spec` information.
Reviewed By: robertoaloi
Differential Revision: D88943301
fbshipit-source-id: 05c67a108b1dc5b64f4353872427361fd039171f
Summary:
When identifying a call from a reference, we start from the ast token for the module name, and ascend the ast until we find a call.
But up to now we have not checked that the module we started from is the module part of the call MFA.
This diff adds that check.
Reviewed By: robertoaloi
Differential Revision: D88934411
fbshipit-source-id: 81a57520ec834210fcea8fd6920653cc45f9890c
Summary: A module name can occur in an external fun. Rename it too.
Reviewed By: robertoaloi
Differential Revision: D88849514
fbshipit-source-id: e715628a6fbfe419cd56761fe62b43d3b68ecde4
Summary:
The final step in renaming a module. Move the old file, and apply the needed edits to it.
This diff also simplifies the mechanics of the rename, to be more general and in line with other renames, by iterating over usages of the module, rather than ad-hoc checks for things that may be needed.
It is still ad-hoc, in the sense that it only looks for call-like things at the moment (fully qualified calls and types). Other usages will come in later diffs
Reviewed By: robertoaloi
Differential Revision: D87861050
fbshipit-source-id: d393638b310a257f51151fc3caf1b1445c856700
Summary: When renaming a module, rename all references to types within it
Reviewed By: robertoaloi
Differential Revision: D87860496
fbshipit-source-id: 2ac6bc52cecaef6802fcf9f181b638f81c556d67
Summary:
Rename references to functions exported from a module when the module is renamed.
This requires fleshing out the infrastructure to deal with deleting files too.
Reviewed By: robertoaloi
Differential Revision: D87860436
fbshipit-source-id: b4d04eb0cfc6448a407fa8c3202ef3e4e088b7e8
Summary: First case, just rename the module
Reviewed By: robertoaloi
Differential Revision: D87860412
fbshipit-source-id: 0427f09bd2176778e0280b0f45f9331fa279f778
Summary:
This diff stack introduces rename for a module. As this is a complex operation, it will be done in steps.
The first one is to put the basics in place
- check the new name is valid
- Improve rename test fixture to cope with added and renamed files
Reviewed By: robertoaloi
Differential Revision: D87860388
fbshipit-source-id: 1a240a5e0e5e61d5c128bca0423744f001b7b68d
Summary:
The `mutable_variable` diagnostic processed bound variables organised by function.
We intend doing the same for more bound variable diagnostics, so as a precursor extract this a method we can call on `Semantic`
Reviewed By: TD5
Differential Revision: D89270590
fbshipit-source-id: 95a520d45e900c0a5c97fd8163cbaedbc15ca840
Summary:
When folding with visible macros, we keep track of a macro stack, so we can decide how to process diagnostics within the body of a macro expansion.
To date we have simply stored the `HirIdx` of the macro call, so it can be retrieved and examined by anything that needs it.
But the thing we need when processing a macro is in fact what definition was expanded. This diff adds it to the information stored for easy access.
It will be used in a subsequent diff.
Reviewed By: TD5
Differential Revision: D89269840
fbshipit-source-id: 7ed6212b658de91cdd3e20701edb51161966e8fa
The internal and external repositories are out of sync. This Pull Request attempts to brings them back in sync by patching the GitHub repository. Please carefully review this patch. You must disable ShipIt for your project in order to merge this pull request. DO NOT IMPORT this pull request. Instead, merge it directly on GitHub using the MERGE BUTTON. Re-enable ShipIt after merging.
fbshipit-source-id: a4e36831ac3939cb9a4881ca077b5f8c0d421104
Summary:
ELP using buck is able to trigger rules that generate code, and load this generated code as part of the project.
This diff brings in a test project with an example of this process, for ensuring our support is sold.
Reviewed By: robertoaloi
Differential Revision: D88953198
fbshipit-source-id: b92cf86b556f5465b2a528895b4e56852630f82e
Summary:
Remove all logic related to `--include-tests` in ELP for eqWAlizer.
Enable eqWAlizer on tests by default.
Reviewed By: michalmuskala
Differential Revision: D89049936
fbshipit-source-id: b3702ddcc8cdb9a3ced65ec6855918ea37b2a072
Summary: It is common for the `fixes` callback to act on the original match range. By making the matched range available to the callback, we avoid manually including the range in the linter-specific context.
Reviewed By: alanz
Differential Revision: D89048282
fbshipit-source-id: 01faa9842f04c34efb14a7d803cf5317794ea321
Summary:
Use new error message generation for callback type errors, add corresponding test
Cleanup old error message generation
Reviewed By: TD5
Differential Revision: D88941623
fbshipit-source-id: 262c2031c7d19ad2528ef63a5d73d146fd84d408
Summary: In preparation for enabling Buck2 tests on GitHub, we install the Buck2 binary.
Reviewed By: michalmuskala
Differential Revision: D89038926
fbshipit-source-id: 7e37c7e9ec143391e10eba8597df2b2aa9d55d0f
Summary:
Apply the severity filter to the results before printing any information about them.
This prevents printing a module name that has no errors in it, and gives a correct count in the module diagnostic summary
Reviewed By: TD5
Differential Revision: D89043311
fbshipit-source-id: aa0c813314f32ca9c23d753c598974a1eb605390
Summary:
Due to some [most likely transient infra issues](2013794095), the latest release was only partially published.
Bump the extension to trigger a new release.
Reviewed By: alanz
Differential Revision: D89024759
fbshipit-source-id: fce412fee451eb72246c121706108af3ac34d414
Summary: Add a stanza to set the config so we get semantic highlighting of `dynamic()`, and types on hover.
Reviewed By: michalmuskala
Differential Revision: D88957646
fbshipit-source-id: 5be4d69fdcf02999b840081baae076b85f9a9260
Summary: Occurrence typing doesn't take place in `maps:foreach` (and several other custom functions). Repro.
Reviewed By: michalmuskala
Differential Revision: D88949717
fbshipit-source-id: d6225a708f0c632d914c4ca38b1d789a3b077311
Summary:
The test is supposed to panic (and does so) when run with both Buck2 and rebar3.
Unfortunately, we are currently disabling the Buck2 tests on GitHub, which has the unfortunate consequence of not letting the test fail as expected, effectively breaking CI.
Temporarily ignore the test.
Reviewed By: alanz
Differential Revision: D88950046
fbshipit-source-id: edabc83ce2b533fa95075078feac624343c198ad
Summary:
The previous diff added the ability to validate a test fixture for parse errors, with an override mechanism if they are expected.
This diff enables the validation for all fixture parsing, and fixes all the resulting errors.
Reviewed By: TD5
Differential Revision: D88948727
fbshipit-source-id: c7e584f3e63c5ad095b9602eed56b469a73392d2
Summary:
A common mistake when writing a declarative test fixture is to have a syntax error in it.
This diff adds `ChangeFixture::validate` to check for these, and panic if found, e.g.
```
thread 'tests::validate_fixture_with_parse_error' panicked at crates/ide_db/src/lib.rs:462:17:
Fixture validation failed: syntax errors found in test fixture
File: /src/test.erl
Errors: [Missing(")", 19..19)]
Content:
-module(test).
foo( -> ok.
Parse Tree:
SourceFile {
syntax: SOURCE_FILE@0..27
MODULE_ATTRIBUTE@0..14
ANON_DASH@0..1 "-"
ANON_MODULE@1..7 "module"
ANON_LPAREN@7..8 "("
ATOM@8..12
ATOM@8..12 "test"
ANON_RPAREN@12..13 ")"
ANON_DOT@13..14 "."
WHITESPACE@14..15 "\n"
FUN_DECL@15..26
FUNCTION_CLAUSE@15..25
ATOM@15..18
ATOM@15..18 "foo"
EXPR_ARGS@18..19
ANON_LPAREN@18..19 "("
WHITESPACE@19..20 " "
CLAUSE_BODY@20..25
ANON_DASH_GT@20..22 "->"
WHITESPACE@22..23 " "
ATOM@23..25
ATOM@23..25 "ok"
ANON_DOT@25..26 "."
WHITESPACE@26..27 "\n"
,
}
---
If this is expected, add `//- expect_parse_errors` to the start of the fixture
```
A subsequent diff will apply it to the code base
Reviewed By: TD5
Differential Revision: D88948352
fbshipit-source-id: 532275075bb338191594966bb3292986442cead6
Summary:
A declarative test fixture can have multiple files in it, in which case each has a metadata line giving the file name. But we have not been checking if it is omitted from the first file, leading to confusing behaviour when writing tests.
This diff updates test fixture parsing to panic in that case, with an appropriate message.
Reviewed By: TD5
Differential Revision: D88947477
fbshipit-source-id: 7ef7151fafb44d087b1da25c55454f20899ca67f
Summary:
As title.
Note that this is still failing on GH.
Reviewed By: robertoaloi
Differential Revision: D88751685
fbshipit-source-id: 4050a9f2094ac7c46395f0f05a7f77dfad9a583b
Summary:
The Mac OS 13 Ventura runner images are [deprecated](https://github.com/actions/runner-images/issues/13046).
This results in a [CI error](2009932825).
This applies the recommended remediation.
Reviewed By: alanz
Differential Revision: D88848551
fbshipit-source-id: 201fa45e4834b082e84a150343042ae5a6104189
Summary:
Several issues were affecting GitHub CI, preventing the extension to be correctly published to the marketplace.
A new release will therefore be necessary, hence the new bump.
Reviewed By: alanz
Differential Revision: D88848737
fbshipit-source-id: f4c31f1bbc5bb3aeec7359c8c8a5d1faeb0c2f9e
Summary:
Mac users can now install ELP using the dedicated Homebrew formula at https://formulae.brew.sh/formula/erlang-language-platform. This provides a simpler installation method compared to downloading binaries manually or building from source.
Updated the installation documentation to highlight Homebrew as the easiest installation method for Mac users, placing it before the binary installation instructions.
Reviewed By: TheGeorge
Differential Revision: D88836106
fbshipit-source-id: 4df1340e7fe29e56e29e089d840f56092864b503
Summary: Move the decision-making logic for choosing to output color in CLI usage into a single place.
Reviewed By: TD5
Differential Revision: D88377007
fbshipit-source-id: 398552dba1547a9e9c0b5e6cd38808316280dd7a
Summary:
Measurements show it makes no difference to the run-time of `elp eqwalize-all`, and it is an impediment to providing streaming output.
Without this, parsing happens on-demand as files are processed by eqwalizer, so we can generate output as each is processed.
Reviewed By: robertoaloi
Differential Revision: D88379872
fbshipit-source-id: 5110788ac5a7ef471038db9de0abfa00bbe7312f
Summary:
At the moment the `elp lint` command processes all the files, and then renders the diagnostics at the end. This can be annoying if you are wanting to just check for occurrences of a diagnostic.
This diff changes the behaviour to stream the results instead as they arrive.
This behaviour is turned off if
- the new `--no-stream` argument is given
- `elp lint` emits json formatted diagnostics
- `elp lint` applies fixes
Reviewed By: TheGeorge
Differential Revision: D88010824
fbshipit-source-id: dc725c1d503f56da6bb1c392cd88f635832320dc
Summary: As title. Remove the "detailed message" part, which is too verbose and mostly useless now.
Reviewed By: TD5
Differential Revision: D88633277
fbshipit-source-id: 092691c2520983148fa0ef8d61a62bd1149a1231
Summary: Mechanical conversion. I also removed the "related info" since they did not seem to provide any additional benefit.
Reviewed By: TD5
Differential Revision: D88379801
fbshipit-source-id: 10926fdc31b88b5755ff346f97948cf83569f71e
Summary: By using a trait we not only make the code more modular and readable, but we also have the ability to enable/disable the linter via config (without running it).
Reviewed By: michalmuskala
Differential Revision: D88351141
fbshipit-source-id: 7bcb3b2f72b1eb119f83b1784982d32867f9c486
Summary:
The diagnostic was computed in the `diagnostics.rs` module. By using a trait we ensure the code is more readable and the intention is clear.
We also modularize the code in `diagnostics.rs`.
Reviewed By: alanz
Differential Revision: D88349260
fbshipit-source-id: f761a9c9b0da188643b6e5eae35b30a74cb5d262
Summary:
It can happen that, when looking for undefined functions, we could not resolve the module name at compile-time.
With the old logic, we would incorrectly flag the case as an "invalid function".
With the improved version, we do not flag the case if we are not sure, avoiding a number of false positives.
A test case highlighting the issue is added as a unit test.
Reviewed By: TD5
Differential Revision: D88474342
fbshipit-source-id: f0f5ae1272f8264c5e11c6e8a7855e75a2832841
Summary:
Rust 1.91 introduced `Duration::from_mins`.
This diff replaces some instances of `Duration::from_secs` with the corresponding `Duration::from_mins`.
Reviewed By: dtolnay
Differential Revision: D88441014
fbshipit-source-id: 88d368316aeb6e4deb328e2052c105d70da9be06
Summary:
The buck2 tests seem to rely on a global state, which is only set for some of the test cases.
As a consequence, running all tests together works, but running some of them in isolation fails.
Consistently set the global state in all tests. As a follow-up, we could refactor this in a helper function.
Reviewed By: alanz
Differential Revision: D88274947
fbshipit-source-id: 5f22894e74bd41458139a93cd063647d95b86296
Summary:
# Context
We want ELP to support hierarchical linter configurations. This means that, by placing a `.elp_lint.toml` file inside an OTP application dir it should be possible to specialize a more generic project-level linter configuration.
# This diff
Introduce the concept of "merging" two linter configurations. This mechanism, currently unused, will then be used when resolving the linter configuration for a given application.
Reviewed By: alanz
Differential Revision: D85573621
fbshipit-source-id: f52a9ed100be794be23c97174b12ce36c3ca7aba
Summary:
# Context
We want ELP to support hierarchical linter configurations. This means that, by placing a `.elp_lint.toml` file inside an OTP application dir it should be possible to specialize a more generic project-level linter configuration.
# This diff
This diff introduces a new test project, named "hierarchical_config" to showcase the most basic form of the goal: the project is composed by two OTP applications (`app_a` and `app_b`). After applying the generic lint configuration, both applications should have two lint issues: an unused macro and an unused function. By placing an additional `.elp_lint.toml` file inside `app_a` to disable the unused macro linter, the unused macro lint issue should only be reported for `app_b`.
Since the feature is not implemented yet and the unused macro linter will be reported for both applications, the test is marked as "should panic". This will change at the end of the stack.
Reviewed By: alanz
Differential Revision: D85569527
fbshipit-source-id: 0772e3a84a25f23c3d6b7ae6c0c955f1206e2c6a
Summary: Add a hook to automatically enable it in erlang-mode, and add the missing closing parens.
Reviewed By: lisztspace
Differential Revision: D88264639
fbshipit-source-id: d3d8166dd233ddc59ff6bb082f3c022851aec5dc
Summary:
It can happen that an included file has errors in it.
ELP is supposed to notice this, and report it with an L0000 (issue_in_included_file) diagnostic.
Unfortunately the logic for reporting this in the erlang service did not properly account for the exact location information reported in the `file` attribute, so this always fell back to a location of 0,0 in the including file. As a result, the diagnostic did not show up properly.
## This diff
We fix it by reporting the location according to the representation used in the erlang service, and making sure we choose the correct include location.
We also add the diagnostic found in the included file as related information, so it is available in the original file
Reviewed By: robertoaloi
Differential Revision: D88010399
fbshipit-source-id: 4a1d2d76a809c104db059e9433200e1bfcf2ac59
Summary:
An ELP Diagnostic can have related information in it, which provide additional context to the reported Diagnostic.
Although these are shown in the IDE when running as a server, they are not currently shown from the command line.
This diff updates the `elp lint` command to display them, when not emitting JSON.
There are 3 variations, depending on where the related information is
- same file: just show the range
- some erlang module: show the module name and range
- an erlang include file: show the full path and range
Reviewed By: robertoaloi
Differential Revision: D88010319
fbshipit-source-id: 26748ec7183a139a57ae97b75a9a61f62da27000
Summary:
As per title.
We use tree_print as a development diagnostic tool.
The test runner for tree_print itself had code to tree_print an entire module via its forms.
This diff extracts this code and makes it available for use elsewhere.
Reviewed By: TD5
Differential Revision: D88159685
fbshipit-source-id: daf1bd1c25d22b9d9f48863b428538efe37a267c
Summary: This should no longer be needed, remove it to reduce code complexity
Reviewed By: jcpetruzza
Differential Revision: D87929715
fbshipit-source-id: c62a6e07084d555bba12dafb96fb893e33f6dc9f
Summary:
# Context
A number of `rebar3` users reported false positive diagnostics, including `duplicated module` when using ELP in combination with a basic rebar3 umbrella project. The problem only appears after the project is compiled.
# Problem
The issue is caused by a bug in the project discovery for rebar3. The project is not correctly recognized as a `rebar3` project, but as a `No manifest` one. This causes ELP to recursively look for Erlang applications within the project directory, discarding the rebar3 structure.
Since rebar3 projects populate a `_build` directory with symlinks to the project applications, each application is found twice, leading to "duplicated module" diagnostics. This is also behind a number of related issues, since paths (e.g. `extra_src_dirs`) are not correctly discovered.
# Solution
The `path` argument for the `discover_in_place` function contains the path to the `.elp.toml` configuration file. When looking for rebar3 projects, we are passing the path as-is, which is why discovery fails. Instead, we should be passing the base directory for the file, where the `rebar.config` resides.
Reviewed By: alanz
Differential Revision: D88071314
fbshipit-source-id: d79edbcdf7a01512f753db668606cb798e65b74b
Summary:
The normal case for the ELP executable is to have a copy of eqwalizer as a Graalvm exe embedded inside ELP. At startup, this is unpacked to a temporary directory, so we can run it.
In the past we had issues where external processes would clean up the temporary directory, and so it would disappear. To mitigate this, we check if the file still exists before running it, and recreate it if not.
BUT, if we are running with ELP_EQWALIZER_PATH pointing to the eqwalizer jar file, as per the OSS local build instructions, then we do not unpack it to a temporary directory, *and* the command name is set to simply "java", which is not a file, as it should be resolved from the path. As a result the current existence check fails, and we continuously report that eqwalizer has disappeared.
This diff changes the check to only be made if we have in fact unpacked eqwalizer to a temporary directory.
Reviewed By: TD5
Differential Revision: D88071028
fbshipit-source-id: 21e7c4897dd6a8f6ae6fe137c413b2fab094d936
Summary: Make it possible to customize the set of labels that in a Buck2 `erlang_application` target can identify a "test" application. Make it default to "test application".
Reviewed By: alanz, michalmuskala
Differential Revision: D88005051
fbshipit-source-id: d5a7cbb89373def5796420fa178c0a86fd72e3ed
Summary:
Simplify the classification of test applications, by removing support for the obsolete "test_utils" and "elp_enabled" labels.
A subsequent diff will make it possible to customize the labels via the `.elp.toml` configuration file.
Reviewed By: michalmuskala, alanz
Differential Revision: D88004904
fbshipit-source-id: fde38e8ce5a4f5c742c647a63ef736d3bbc84f51
Summary:
# Context
W0050 asks users to prefer the more efficient `tuple_size/1` and `byte_size/1`, instead of `size/1`.
# Problem
The explanation is muddled by some advice to always guard the usages of `byte_size/1` with `is_binary/1`. This doesn't make intuitive sense and there's nothing in the docs of `byte_size/1` that suggests this is advisable in any way.
# This diff
Remove this part. I'm also removing the part that rewrites `size/1` in terms of `byte_size/1` and `tuple_size/1` as it doesn't seem to be adding anything.
Reviewed By: TD5
Differential Revision: D87986348
fbshipit-source-id: dbd6aeec71989bc367f3d22b58a71d893b7fff76
Summary:
The ELP main loop is a message pump. It calls `next_message` and processes it, until done.
There are multiple message sources, and the current code takes one at random from all available sources.
This diff changes this to an ordered selection, giving explicit priority when more than one source is ready at the same time.
This is motivated by
1. Make sure the messages we send go out as soon as possible (progress, telemetry)
2. Now that the vfs loader uses all available cores to speed up loading, make sure the loader progress messages do not drown out all others.
Reviewed By: michalmuskala
Differential Revision: D87984388
fbshipit-source-id: 3b8cc5f6614bdf9699e805b03da6b5696829d280
Summary:
As title.
Note that for a buck project using quick start, we will get two values per project startup, the first smaller value is from processing the result of `buck2 targets`, the second includes any generated files from running `elp.bxl`
Reviewed By: jcpetruzza
Differential Revision: D87923914
fbshipit-source-id: 8b10cb1ef685250f022cf360e1b2d5f621c17407
Summary: Also respond to the `NO_COLOR` environment variable, as per [no-color.org](no-color.org).
Reviewed By: jcpetruzza
Differential Revision: D77446683
fbshipit-source-id: c7b14c64813ca98a1163fb2f9e651ea304e5757d
Summary: Long awaited feature: the ability to rename types. Take the opportunity to fix the range of the type name not to include arguments.
Reviewed By: alanz
Differential Revision: D87643493
fbshipit-source-id: e7fd3d13ff71ef5a3049aae3a242606899e582be
Summary: Add our nightly rustfmt binary to PATH for elp cargo shell script. This keeps the formatting consistent between `arc f` and `cargo.sh fmt` by using the same rustfmt.toml and rustfmt binary.
Reviewed By: alanz
Differential Revision: D87853695
fbshipit-source-id: dbb378acb8e48f5910187d32757d5f5597305df7
Summary:
As title.
In future we may remove `elp ssr`.
Reviewed By: TD5
Differential Revision: D87766502
fbshipit-source-id: c9742292afe35984002d02b20ec0e051cfee125f
Summary:
It is annoying to wait for the entire body of code to be processed before seing results. Since the ssr search is based purely on the ast of a module, the search is embarrasingle trivial.
So report the results as they are found.
This does mean the summary statistic has to come at the end.
Reviewed By: TD5
Differential Revision: D87651432
fbshipit-source-id: b51b7bd94f8069113154adac9b1bf68f9b7351b3
Summary:
Inside ELP an SSR match is exposed as a diagnostic. So the way it is output to the command line is as a diagnostic, giving location and the pattern that matched.
This is not very useful when exploring a code base from the command line.
This diff brings the ability to show the source for a matching diagnostic. The command line interface is modeled on the one for grep, so it should be familiar to users.
It will automatically use colour if in a TTY context, but this can be controlled via CLI or environment variable.
Reviewed By: TD5
Differential Revision: D87634862
fbshipit-source-id: 52604d21100274b2abba9e364acbb972914aa4ac
Summary:
As requested by several users:
https://github.com/WhatsApp/erlang-language-platform/issues/127
We can publish the extension to the open-vsx.org marketplace, in addition to the Microsoft one.
This enables using ELP in VSCodium.
Reviewed By: alanz
Differential Revision: D87625612
fbshipit-source-id: 8ee143cc3853b7ded04193802d32e164602be8d0
Summary:
# Context
We want to convert the `edoc` linter to use a trait.
# Problem
The `edoc` linter has a different `Severity` for source code and test files.
# Solution
We can extend the `severity` and `cli_severity` methods to accept `sema` and `file_id`. This way, we can customize the severity based on the file. The new arguments will be used by the edoc linter in a subsequent diff.
Reviewed By: alanz
Differential Revision: D87545262
fbshipit-source-id: d7546d7d77ec019c2a2edc846e69134e93a6fe90
Summary:
The `text_edit` crate contains a single file. Move it to the `ide_db` crate, and remove the whole `text_edit` crate.
This is in line with Rust Analyzer.
Reviewed By: alanz
Differential Revision: D87539326
fbshipit-source-id: cdc8f71902bc084eca79ae54ca71584ac48ed637
Summary:
# Context
The `text_edit` crate contains a single file, `lib.rs`. We can remove the entire crate by moving the functionality into a `text_edit.rs` in the `ide_db` crate. This is in line with Rust Analyzer.
# Problem
The move would eventually create a circular dependency between `syntax` and `ide_db`.
# Solution
To untangle the circular dependency, we can move the `tree-diff` functionality to the `ide_db` crate. Again, this is in line with Rust Analyzer.
Reviewed By: alanz
Differential Revision: D87524148
fbshipit-source-id: 90b1df3d4191a63c0d74c49af9fafec6578f530c
Summary:
We already have a `editors` directory with editor-specific packages and configurations. Move the Emacs sample there.
Also reference it from the Emacs installation docs, to make it simpler to find.
Reviewed By: alanz
Differential Revision: D87517087
fbshipit-source-id: 754324de280ec094d6756d8702738d16fbdf268b
Summary:
When running any elp CLI command that produces diagnostics, the locations are incorrect, as they use the internal coordinate frame rather than the usual one for IDEs and other tools.
This means each line and col location is one less than it should be.
This diff fixes that, so the locations make sense to users.
Note: it does not affect output using `--format json`, which already does this.
Reviewed By: TD5
Differential Revision: D87539540
fbshipit-source-id: 27abd4ac5fb9e5056fc9e3397257d9e5cb9e678d
Summary: Simple conversion to use the new trait.
Reviewed By: jcpetruzza
Differential Revision: D87516327
fbshipit-source-id: 8a6669c4c337a54ecf0a65c864df8be40d82e720
Summary: Simple conversion to use the new trait.
Reviewed By: jcpetruzza
Differential Revision: D87447644
fbshipit-source-id: 74e0caf1fc8fd289013af2fc69839b25f0b9bdc4
Summary: Simple conversion to use the new trait.
Reviewed By: TD5
Differential Revision: D87445553
fbshipit-source-id: 8b45cea1dcefe71b0cd573aa4529433974943d3f
Summary: Simple conversion to use the new trait.
Reviewed By: TD5
Differential Revision: D87079003
fbshipit-source-id: 7caaf84bf43882045637fe870046537e5eb82a5f
Summary: Take into account type references from record definitions when computing the `unavailable_type` diagnostic.
Reviewed By: TD5
Differential Revision: D87442698
fbshipit-source-id: 982a5e815877147d17e1d472230f06859263d343
Summary:
It is counterintuitive that, if a linter is disabled, it does not run when `--diagnostic-code` explicitly selects it.
This diff solves the issue.
Reviewed By: alanz
Differential Revision: D87434612
fbshipit-source-id: 7cc19544602f77e086919f0094b64120120fa7d4
Summary:
Introduce a new `unavailable_type` diagnostic, which warns about types which are correctly defined, but referenced from a module which does not have the application where the type is defined as a dependency.
The diagnostic, which is complementary to eqWAlizer's [unknown_id](https://github.com/WhatsApp/eqwalizer/blob/main/docs/reference/errors.md#unknown_id) (for remote types) and Erlang/OTP's L1295/undefined_type (for local types), can be seen a step towards a ELP-powered XRef.
The diagnostic works by scanning the `-spec`, `-type`, `-opaque` and `-callback` attributes. If a type is referenced, we verify whether the OTP application where the type is defined is a (recursive) dependency for the application where the type usage occurs.
The diagnostic is currently disabled by default.
Reviewed By: alanz
Differential Revision: D87341709
fbshipit-source-id: a7729de093f50ae2bdc0c2138019e4a5503e7359
Summary:
Our declarative tests allow us to add annotations for expected diagnostics, so we can clearly see and check what is generated.
But at present there is no way to check any related information for a diagnostic.
This diff adds that capability, showing related information together with the FileId and range each refers to.
Reviewed By: robertoaloi
Differential Revision: D87316965
fbshipit-source-id: ea7db2980b11950c3552befec7b666665ceef84b
Summary:
A given diagnostic can have related information in it, which carries relevant context to the provided diagnostic.
For example, for a head mismatch diagnostic, it reports the specific head location(s) that do not match.
The LSP spec uses a `Location` for these, which includes a file URL, meaning the related info can be in a different file from where the diagnostic is reported.
In ELP, we currently do not provide a way of populating this information, so can only refer to related information within the same file. Thic can result in erroneous outcomes.
## This diff
We include a `FileId` in our internal `RelatedInformation` structure, and map it to a URL when serializing for transmission to the LSP client
Reviewed By: robertoaloi
Differential Revision: D87316542
fbshipit-source-id: 5f94eb4fe5bb73e7bf1fff7cad458231c51bd6f0
Summary: Simple conversion to use the new trait.
Reviewed By: TD5
Differential Revision: D87078566
fbshipit-source-id: 5e019d3b968a78997d1ebe24f5b168cf8fce4b1f
Summary:
Even if the `undocumented_function` is supposed to be disabled by default, it still runs. This is due to a flawed logic in `diagnostics.rs`, originally introduced in D59272525.
This is problematic, since open-source projects such as OTP see a huge number of errors when running the `elp lint` command without specifying a custom configuration.
By converting the linter to use the new trait, we incidentally fix the bug.
This was the last linter using the `default_disabled: true` logic. At this point the enabled/disabled logic can be simplified.
Reviewed By: alanz
Differential Revision: D87060203
fbshipit-source-id: 1121d286c766fb461420e3268aca817169020d7d
Summary:
Even if the `undocumented_module` is supposed to be disabled by default, it still runs. This is due to a flawed logic in `diagnostics.rs`, originally introduced in D59272525.
This is problematic, since open-source projects such as OTP see a huge number of errors when running the `elp lint` command without specifying a custom configuration.
By converting the linter to use the new trait, we incidentally fix the bug.
One more linters uses a `default_disabled: true` property in its descriptor: `undocumented_function`. It will be converted next, and the logic to handle the `default_disabled` will eventually be removed.
Reviewed By: alanz
Differential Revision: D87059857
fbshipit-source-id: 7fb6eff8773c786c6894548c914b8e3c78c38745
Summary:
Even if the `missing_compile_warn_missing_spec` is supposed to be disabled by default, it still runs. This is due to a flawed logic in `diagnostics.rs`, originally introduced in D59272525.
This is problematic, since open-source projects such as OTP see a huge number of errors when running the `elp lint` command without specifying a custom configuration.
By converting the linter to use the new trait, we incidentally fix the bug.
Two more linters use a `default_disabled: true` property in their descriptors: `undocumented_module` and `undocumented_function`. They will be converted next, and the logic to handle the `default_disabled` will eventually be removed.
Reviewed By: alanz
Differential Revision: D86978483
fbshipit-source-id: 5a89ff0fd1297a1e75db9d4b60d75b70f98d1e0c
Summary:
In a properly configured buck2 project, W0058 and E1516 will always be reported at the same time.
So do not report W0058 if there is already a E1516.
Reviewed By: TD5
Differential Revision: D86963330
fbshipit-source-id: fe1aaaa71330da059ed697d187542e3cb470e965
Summary:
For a buck project, if the dependencies are not set up properly for ELP use, it may compile but ELP is unable to resolve a nested include file when processing the middle ones in a chain.
This diff adds a check for the HIR include file resolution so this can be detected.
For a properly configured buck project this is redundant, because the Erlang service already reports `E1516` for this.
The next diff filters out occurrences generated here in that case.
Reviewed By: TD5
Differential Revision: D86963331
fbshipit-source-id: 356cefeba61e306fb3541a21ba16c189aa8c8faa
Summary:
Create a new diagnostic W0057 (hir_unresolved_macro) to report macros not resolved during HIR lowering.
For a properly configured buck2 project this simply shadows the existing Erlang service `E1507` / `E1508` diagnostics, but for an incorrectly configured one they show up alone.
The next diff filters them out if they are already reported.
It also ensures it does not report on usages of `?FUNCTION_NAME` or ?FUNCTION_ARITY` in the replacement part of a `-define()` attribute.
Reviewed By: TD5
Differential Revision: D86963336
fbshipit-source-id: 08f8d1b6c58dde6ee0a106f9151b237709dc56e0
Summary:
Record failed macro expansions when lowering to HIR.
We track them in the `BodySourceMap`, as we need to report based on `ast` locations.
Later diffs in this stack will turn them into ide Diagnostics, but that type is not available here because HIR is a leaf in the crate graph.
Reviewed By: TD5
Differential Revision: D86963333
fbshipit-source-id: 6f9afecbb10f6a2c999689e007f735f0bafbdf43
Summary:
This diff sets up a test case to demonstrate a problem which will be fixed by this stack, as it is currently silently ignored.
As such, there is no failure reported in the test. That will change later in the stack.
It is possible to configure a buck2 project with nested include files so that it compiles with buck2, and also with our erlang_service, but that we are unable to properly lower it into HIR and so do not resolve macros in ELP.
This occurs when we have three buck2 targets, A,B,C each in a separate directory.
- A has both B and C as dependencies, but
- B does not have C as one.
Then
- target A contains a .erl file that includes a .hrl from target B
- the .hrl in target B includes a .hrl from target C
So from A we can resolve the entire chain of includes via dependencies, but from B we cannot.
And ELP lowers the file into HIR for B in the context of B, so does not resolve the include at C, and silently fails to do so, entering a `Expr::Missing` value instead.
Reviewed By: TD5
Differential Revision: D86963334
fbshipit-source-id: 57b51714513fc78cd21083adea6abd12a9350571
Summary:
Fixes a query as to why we report on `hd(lists:reverse(L))`, but not `lists:nth(1, lists:reverse(L))`.
For the purposes of this diagnostic, `lists:nth(1, lists:reverse(L))` is equivalent to `hd(lists:reverse(L))`, so we trigger on that too.
Reviewed By: alanz
Differential Revision: D86969766
fbshipit-source-id: e6a022a10267d04c6700b3ee5fc9fa31a02b75ac
Summary:
Introduce a new linter which identifies usages of the following pattern:
```
lists:reverse(List) ++ Tail
```
Suggesting to replace them with the more performing:
```
lists:reverse(List, Tail)
```
Reviewed By: michalmuskala, alanz
Differential Revision: D86967410
fbshipit-source-id: cc5142aa9548a69792bb5ba9ff6698afbd38227c
Summary: Clarify tool usage for building and testing the project in elp_development.md
Reviewed By: TD5
Differential Revision: D86951935
fbshipit-source-id: 972aea59d3050c258270bbb1694b968d83655858
Summary: The temp directory location is not the same on all platforms.
Reviewed By: jcpetruzza
Differential Revision: D86679320
fbshipit-source-id: 39db19df4377798348ae81c87ffb9599e6f87334
The internal and external repositories are out of sync. This Pull Request attempts to brings them back in sync by patching the GitHub repository. Please carefully review this patch. You must disable ShipIt for your project in order to merge this pull request. DO NOT IMPORT this pull request. Instead, merge it directly on GitHub using the MERGE BUTTON. Re-enable ShipIt after merging.
Summary:
We already have local logging of changes we receive related to file watching, both from VFS and the LSP client.
To contextualise these, include logging of the decisions made at key points in the project loading lifecyle when ELP is running as an LSP server.
Reviewed By: jcpetruzza
Differential Revision: D86679575
fbshipit-source-id: dc4fb2bdab5b489757a618aefee33f544bce4767
Summary:
As title.
It does not make sense to have at least info severity in the IDE, otherwise the squiggles do not show up.
Reviewed By: jcpetruzza
Differential Revision: D86774246
fbshipit-source-id: 0db22ecf1b90c7e7a2d2037c0c45cc8619928c44
Summary: We now include the diagnostic code in the expected diagnostic.
Reviewed By: RobinMorisset
Differential Revision: D86658752
fbshipit-source-id: 43f835633a0c81c15d7f43cfcdfde967db9a3178
Summary:
When ELP is loading a buck project it does queries using buck.
Sometimes these fail, because the current state of the buck configuration files is invalid.
In that case, we show a pop-up suggesting that the user examine the buck dashboard, and provide a URL for this.
It is not always clear to the user that this is related to a malformed buck project, rather than a bug in ELP.
This diff tries to make it clearer.
Note that we unfortunately do not have the ability to use any kind of formatting in the displayed message.
Reviewed By: TD5
Differential Revision: D86510447
fbshipit-source-id: 57a93f829d37a8a4d7c8be88d6cf68adcf41c859
Summary:
We can use the command line `elp ssr` command to search through files in a project for matches, but it is also convenient to be able to examine them in an IDE context.
This diff adds this capability, with two new command line options
- `--info` upgrades the reported diagnostic from weak warning to info
- `--dump-config` emits a toml snippet suitable for placement at the end of an `.elp_lint.toml` file.
```bash
elp ssr --parens --dump-config --info "(3)" "{_A}"
# Add this to your .elp_lint.toml
[[ad_hoc_lints.lints]]
type = "LintMatchSsr"
ssr_pattern = "ssr: (3)."
severity = "info"
macro_strategy = "expand"
paren_strategy = "visible"
[[ad_hoc_lints.lints]]
type = "LintMatchSsr"
ssr_pattern = "ssr: {_A}."
severity = "info"
macro_strategy = "expand"
paren_strategy = "visible"
```
The edit to `.elp_lint.toml` will be immediately picked up, and you will see the matches as normal diagnostics with a blue squiggle for info.
Reviewed By: TD5
Differential Revision: D85960380
fbshipit-source-id: 803c19f1917d939d13e6406e440057632b489ea6
Summary:
Our declarative test fixtures allow us to annotate the fixture with the epxected diagnostics to be produced by the test.
Up to now, this has included the severity and text only.
This (massive but regular) diff updates this to include the diagnostic code too.
This makes it clearer that the code is correct, and makes it easier to search for examples of its usage in the test code.
Reviewed By: robertoaloi, TD5
Differential Revision: D86103082
fbshipit-source-id: 6e4ede050350cc90aa437f68da0900a66b7d0625
Summary: As title. Also tweak the comment on extract annotations to match current usage.
Reviewed By: robertoaloi, TD5
Differential Revision: D85962544
fbshipit-source-id: ec68698a90ea34373b2845339c634986fb921b06
Summary:
> Note: This diff is part of hackathon to clean up ELP backlogs using devmate. It is authored by Devmate, so kindly review it carefully!
Fixes T233431969
When the `no_calls_in_ct_all_groups` linter was migrated from erlint to ELP, a bug
was introduced where multiple violations on the same line would each generate their own
ignore fix, resulting in duplicate ignore comments.
**Problem:**
When two or more function calls on the same line both violated the diagnostic (e.g.,
`list_to_atom()` and `atom_to_list()` on line 123), each diagnostic independently
called `.with_ignore_fix()`. Since ignore fixes are inserted at the **start of the line**
(not at each diagnostic's position), this resulted in duplicate annotations:
```erlang
% elp:ignore WA024 (no_calls_in_ct_all_groups)
% elp:ignore WA024 (no_calls_in_ct_all_groups)
list_to_atom(?SRPROXY_TEST_PREFIX ++ atom_to_list(GroupName)),
```
**Root Cause:** The initial implementation grouped diagnostics by their start position, but this was incorrect because `with_ignore_fix()` computes the line start offset using `start_of_line()` and inserts the comment there. Multiple diagnostics at different column positions on the same line all target the same insertion point.
**Solution:** Modified `check_function()` in `no_calls_in_ct_all_groups.rs` to:
1. Parse the file to access the syntax tree
2. Compute the line start offset for each diagnostic using the same `start_of_line()` function that `with_ignore_fix()` uses internally
3. Group diagnostics by line start offset (not by diagnostic position)
4. Add the ignore fix only to the first diagnostic in each group
5. Extend all diagnostics (with or without ignore fixes) to the result vector
This ensures that when multiple violations occur on the same line, only one ignore comment is generated while all diagnostics are still reported to the user.
Reviewed By: alanz
Differential Revision: D85856981
fbshipit-source-id: 5b829e8191cdf5b84de6d12e9e5b974e6246a2da
Summary: We can use slices - no need to allocate new vecs and reallocate args on every iteration
Reviewed By: TD5
Differential Revision: D85989035
fbshipit-source-id: 6116dd9da0067b6b541031e18a1ed618631c7726
Summary:
Infinity sleeps are usually done to keep some auxiliary process alive. They also never slow down test - if they were actually blocking for the test, the test would be broken.
There's little value in flagging and linting those.
Reviewed By: ilya-klyuchnikov
Differential Revision: D85987359
fbshipit-source-id: 3691d9c4bae56e93dfc9a526c73136364a75dc70
Summary:
ELP as an LSP server operates in a dyamic environment, by design. The key thing ts must deal with is changes to files. A given project loaded into ELP has to process file-changes from two primarily different sources.
The first is open files in the LSP client (VS Code), and these are sent via LSP protocol as they happen, as well as generating a `DidSaveTextDocument` notification when saved.
The other is changes that happen on the filesystem directly, from any source, such as an external editor, version countrol operation, build, or the like. These are monitored via a file watcher, and the watching is also delegated to the LSP client.
There are some wrinkles to this. We send a registration message to the client to watch all files of interest in a project, both source and configuration. So of necessity this will overlap with any files that are also open in the IDE. To avoid double processing these, we only process open files in the `DidSaveTextDocument` notification, and do not process open files in the `DidChangeWatchedFiles` notification.
This is all very well, but at some point there was a rationalisation of change processing, with the realisation that we only care about `DidSaveTextDocument` notifications for triggering diagnostic requests for open files for diagnostic sources not providing on-change diagnostics. Which is now most of them.
So we modified the registered scope for `DidSaveTextDocument` to only be `.erl`/`.hrl` files.
This meant that we no longer processed changes to configuration files that are open in the IDE, which is the main way they pick up changes.
## This diff
We restore the desired immediate reaction to changed files by never doing the check in the `DidSaveTextDocument` notification processing, since it never applied anyway, and so always doing it in `DidChangeWatchedFiles`.
We also tidy up the registering of watched files by first unregistering, otherwise the client accumulates multiple watches for the same files, and sends a change notification for each registration it has. Even with this removal, we still get 2 notifications per file change, so add logic to de-dupe them while processing, as updating config can be an expensive operation.
Reviewed By: jcpetruzza
Differential Revision: D85956439
fbshipit-source-id: 961618711347d173596f69f5fd94a435b3fd45b1
Summary:
> Note: This diff is part of hackathon to clean up ELP backlogs using devmate. It is authored by Devmate, so kindly review it carefully!
Implements support for recording parentheses in HIR `TypeExpr`, bringing it to parity with how `Expr` and `Pat` handle parentheses in the ELP (Erlang Language Platform) HIR (High-level Intermediate Representation).
## Problem Statement
The `TypeExpr::Paren` variant already existed in the HIR enum definition (in `/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/expr.rs` at lines 911-917) but was not being instantiated during AST-to-HIR lowering. This meant that parentheses in type expressions like `((integer()))` or `{((atom())), (integer() | (binary()))}` were being silently discarded, making it impossible to:
1. Analyze parenthesis usage patterns for assist decisions
2. Maintain source fidelity for type expressions
3. Support tools that need to understand the exact structure of type expressions as written
## Implementation Details
### 1. AST Lowering (`/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/body/lower.rs`)
**Lines 2191-2198**: Updated `lower_type_expr` to properly allocate `TypeExpr::Paren` nodes when encountering parenthesized type expressions:
```rust
ast::ExprMax::ParenExpr(paren_expr) => {
if let Some(inner_expr) = paren_expr.expr() {
let type_expr_id = self.lower_type_expr(&inner_expr);
self.alloc_type_expr(TypeExpr::Paren { ty: type_expr_id }, Some(expr))
} else {
self.alloc_type_expr(TypeExpr::Missing, Some(expr))
}
}
```
This mirrors the pattern used for `Expr::Paren` (lines 1485-1492), ensuring consistency across expression types.
### 2. Fold Traversal (`/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/fold.rs`)
**Line 1183**: Added `TypeExpr::Paren` case to `do_fold_type_expr` to recursively traverse through parenthesized type expressions:
```rust
TypeExpr::Paren { ty } => self.do_fold_type_expr(*ty, acc),
```
**Lines 2655-2703**: Added two comprehensive test functions that verify the fold behavior:
- `parens_in_type_expr`: Tests simple nested parentheses `((integer()))`
- `parens_in_type_expr_complex`: Tests complex nested parentheses in a tuple/union type `{((atom())), (integer() | (binary()))}`
- Helper functions `count_parens_in_type_expr` and `do_count_parens_in_type_expr` to verify ParenStrategy behavior
### 3. FoldBody Index Implementation (`/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/body.rs`)
**Lines 1069-1072**: Added `ParenStrategy` handling to the `Index<TypeExprId>` implementation:
```rust
TypeExpr::Paren { ty } => match self.parens {
ParenStrategy::VisibleParens => &self.body.type_exprs[index],
ParenStrategy::InvisibleParens => self.index(*ty),
},
```
This allows callers to control whether parentheses are transparent during traversal:
- `VisibleParens`: Returns the Paren node itself, making parentheses observable
- `InvisibleParens`: Recursively indexes through to the inner type, making parentheses transparent
**Line 1067**: Updated comment from "Do not look through macro expansion" to "Apply the visibility strategies to macros and parens" to accurately reflect that the function now handles two visibility strategies (macros and parentheses), not just one.
### 4. Pretty Printing (`/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/body/pretty.rs`)
**Line 779**: Added `TypeExpr::Paren` case to `print_type` method:
```rust
TypeExpr::Paren { ty } => self.print_type(&self.body[*ty]),
```
This ensures parenthesized types are printed correctly by recursively printing the inner type.
### 5. Tree Printing (`/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/body/tree_print.rs`)
**Lines 1191-1195**: Added `TypeExpr::Paren` case for debug tree printing:
```rust
TypeExpr::Paren { ty } => {
self.print_herald("TypeExpr::Paren", &mut |this| {
this.print_type(ty);
});
}
```
This provides diagnostic output showing the Paren node in tree representations.
### 6. Updated TypeExpr name method (`/data/sandcastle/boxes/fbsource/fbcode/whatsapp/elp/crates/hir/src/expr.rs`)
**Line 945**: Added name case for `TypeExpr::Paren` to return `"TypeExpr::Paren"` for diagnostic purposes.
## Architecture Pattern
This implementation follows the established architectural pattern used for `Expr::Paren` and `Pat::Paren` throughout the HIR:
1. **Lowering**: Create Paren nodes during AST→HIR conversion
2. **Folding**: Recursively traverse through Paren nodes
3. **FoldBody**: Respect ParenStrategy configuration (visible vs invisible)
4. **Printing**: Handle Paren nodes in both pretty printing and tree printing
This consistency ensures that type expressions have the same level of structural fidelity as regular expressions and patterns, enabling future IDE features and assists that need to understand parenthesis usage.
Reviewed By: alanz
Differential Revision: D85948216
fbshipit-source-id: 42c59c4598f376670eaf568326e59d38aa1139d2
Summary:
Structural Search (SSR) matches the syntax tree used internally in ELP, called HIR. This is conceptually similar to Erlang Abstract Forms.
When we lower the surface Erlang language into this, we expand macros and strip of parentheses, as the precedence of items is captured in the actual HIR representation.
But sometimes when we are searching over Erlang code we want to explicitly match parentheses, e.g. if we want to find all instances of redundant duplicate ones.
This diff allows you to do this by issue the command
```
elp ssr --parens "((_A))"
```
Likewise, sometimes you are interested in occurrences of macros. This can now be provided using a match like
```
elp ssr --macros no-expand "?BAR(_X)"
```
Reviewed By: TD5
Differential Revision: D85876784
fbshipit-source-id: ba62d83ed8ea9c7ac30cceda2cac446ecdeefb06
Summary:
Elab the lambda in `maps:map/2` once for every key/value pair of the given map type, so as to keep the precise association between key and result.
This effectively makes the complexity O(map_fields * clauses) instead of just O(clauses).
However, this shows no noticeable performance impact in production.
Reviewed By: TD5
Differential Revision: D85590251
fbshipit-source-id: 266a4d3f4f5b71ab738ee9c799dda7e30161560a
Summary: A snapshot test for more precise support of `maps:map/2`
Reviewed By: RobinMorisset
Differential Revision: D85677708
fbshipit-source-id: 1520e78419c51ae26604768fd78d787e06301a61
Summary:
The heuristic uses a score of 50 as the limit for a partial match in a union, but partial matches on maps can go as low as 40.
Change the limit to be 40 for both, so that a candidate map is always selected.
Reviewed By: TD5
Differential Revision: D85868725
fbshipit-source-id: 60b1bfda0f58642bda144ac1e3bf2389523101e7
Summary: Some error messages with unions of maps are useless. Add repros.
Reviewed By: TD5
Differential Revision: D85868726
fbshipit-source-id: c726054b934690f30bc3e5c190d55e9dd25e361f
Summary:
Since project loading and traversal takes some time, allow matching more than one SSR pattern at the same time.
The CLI arg now accepts multiple patterns, e.g.
```
elp ssr "3" "{4}"
```
Reviewed By: TD5
Differential Revision: D85870548
fbshipit-source-id: d768fbbebb2f74e3cedd4528b2c4831cc1c9f3e7
Summary:
There is an error in tracking the source location in the `BodySourceMap` when lowering into `Expr::Paren` and `Pat::Paren`.
This diff fixes those.
Reviewed By: TD5
Differential Revision: D85866708
fbshipit-source-id: 8a2aa8b55e2981dd4c212114daf5bed15573cfa4
Summary:
When developing a feature in ELP it is often useful to tree print a body, to see clearly what the HIR representation is in it.
This is disconnected from the original source, however, as we have no indication of precisely where each part originates.
This diff updates tree print to optionally take a `BodySourceMap`, and if present it prints the range of the item when introducing the constructor.
It is use to add a test showing that the lowering of Expr::Paren is incorrect.
Reviewed By: TD5
Differential Revision: D85866631
fbshipit-source-id: 866eeba845f396ba51fcfd01e92d9c264e450534
Summary: Fix overlap calculation between record types and tuple types by adding an arity check.
Reviewed By: TD5
Differential Revision: D85806277
fbshipit-source-id: ae17d5c157a1519994da1924542879c37566645a
Summary: A bug in occurrence typing where overlap between tuple types and records is not properly computed.
Reviewed By: TD5
Differential Revision: D85806276
fbshipit-source-id: 96330f16d452ebde1f0fffefd1b70c4a12cbd0c2
Summary:
This changes local debug builds (linux only) to use a `jar` rather than building the native image for eqwalizer. This speeds up iteration significantly.
We had this before, but struggled with java versions. In this iteration we just use tha java from graalvm that we would use to build the native image - that way we have a consistent java version that we fully control and don't depend on the OS.
Reviewed By: TD5
Differential Revision: D85784216
fbshipit-source-id: 188dd7207865fda770bf2e154e18049030acdc29
Summary: As title. The opaque type tests are cumbersome to maintain since their results change with OTP changes.
Reviewed By: TD5
Differential Revision: D85772507
fbshipit-source-id: c2dd37965e57eed59a4fe2c7674941ded35f7afe
Summary:
This changes how unions are flattened, to also eagerly flatten remote unions. This already was done for local unions, but remote unions weren't considered, making the operation inconsistent
This impacts 2 places:
* How "unit" lists are typed - this allows `[X]` where `X :: boolean()` to typecheck with `[true] | [false]`.
* How some errors with unions are reported - as you can see in changed tests
While the error reporting with expanded unions for types like boolean looks a bit silly, in general I think it's more useful since you don't need to go look up type alias definitions when debugging the errors.
We also simplify the flatten operation - since D85340363, by construction, unions can't contain `NoneType` and they won't ever be empty.
Reviewed By: TD5
Differential Revision: D85669551
fbshipit-source-id: 4f88ae72dc8746c6cac8558e59c265378f647ab3
Summary:
As title.
Attempts to group the available options
Reviewed By: jcpetruzza
Differential Revision: D85767261
fbshipit-source-id: c5ae95b6fa45a1637666804c77c587b30dd4abc8
Summary:
The `elp ssr` feature was initially landed as a quick proof of concept.
In paractice, it runs much slower than it should, because it is delegating to the machinery that runs `elp lint`, which does a lot more work than is needed.
This diff makes `elp ssr` a completely standalone command, which only calls the specific diagnostic checker for an ad hoc SSR diagnostic.
Reviewed By: jcpetruzza
Differential Revision: D85760580
fbshipit-source-id: 5bd38f78b08614be99c4a7d4cc69ebed8832fc70
Summary:
This diff operated in the context of the buck project model.
Up to now, the buck erlang prelude files had not been updated to be eqwalizer error-free.
They are now fully eqwalized. Part of the internal usage is to tweak both the common test prelude files and our internal source, and so it is convenient to report eqwalizer diagnostics, via `elp eqwalize-all` for these as well.
The buck project model has historically classified the prelude files as third-party, which maps them to a `TargetType::Dep`, and so eqwalizer does not process them.
This diff changes the logic, so that if any of the `.elp.toml` included targets for a project include a buck prelude target, then it will classify all prelude target files as `TargetType::App` instead.
This has the result of ensuring that they are processed for `elp eqwalize-all` of that project.
Reviewed By: jcpetruzza
Differential Revision: D85761256
fbshipit-source-id: 39a8a56870662d8c148f5a646c7ae63a262693a4
Summary:
We now have the ability to provide telemetry for command line usage of ELP. The initial version did not include for the `elp lint` command.
This diff adds that.
Reviewed By: jcpetruzza
Differential Revision: D85756130
fbshipit-source-id: c52da5864e12290857fc12e05edc097309b94de5
Summary: As title (adding back auto-trimmed whitespace)
Reviewed By: michalmuskala
Differential Revision: D85690173
fbshipit-source-id: 39c3ac7494eb31f778d7bec41c0dd3ed35b06d31
Summary:
A buck project puts its artefacts into a directory called `buck-out`, with a hash as part of the file name. When buck is used to generate `.erl` or `.hrl` files, they will end up there.
This means we have no way of knowing what project a given file in `buck-out` belongs to.
When we do load the owning project, it explicitly enumerates all the files belonging to the project in the `applicable_files` part of the `AppData`, and we can then correctly process files in `buck-out`.
The ELP LSP project discovery process starts at the given open file in the IDE, and keeps looking in parent directories until it finds something that identifies an erlang project, such as a `.elp.toml` file. Even if we have one at the root of the repo, `buck-out` is shared across all projects within the repo, so we do not necessarily know which one the file belongs to.
To prevent loading a fallback project and then not correctly reesolving the file in its correct project when it is opened, we do not initiate project discovery on files withing the `buck-out` directory.
Reviewed By: TD5, TheGeorge
Differential Revision: D85577495
fbshipit-source-id: 58e1ad4ab25e1278493ac4a620119ece6d8971e8
Summary:
Diff D85429234 titled `[ELP] Fix incorrect project load on go to def in thrift file` checks when a new file is opened in the LSP client if its canonical path is in the list of applicable files for a given project, and of so does not attempt to load a new project for it.
But for historical reasons the list of applicable files did not include `.hrl` ones. This diff fixes that, together with the change in `elp.bxl` introduced in D85573080 `[buck/prelude] elp.bxl keep full include file name` which returns the actual applicable files rather than just the directory containing them.
Reviewed By: TheGeorge
Differential Revision: D85573144
fbshipit-source-id: da3eb35f1d80e2107ce4ec9eb9585db710aec7ac
Summary: Snapshot `callbacks3_neg` is also OTP version dependent, fix it.
Reviewed By: michalmuskala
Differential Revision: D85675523
fbshipit-source-id: dfabda187190b669ef509c967fe3723de25d2890
Summary:
We have the ability to specifiy an AdHoc diagnostic in a config file, from the diff titled `[ELP] Specify SSR match as Ad-Hoc diagnostic`.
We now simplify usage by allowing it to be given on the command line too, so a simple
```
elp ssr "{_A, _B}"
```
will find and report all 2 element tuples in the project.
Note: the full syntax for ssr can also be used if guards are required, e.g.
```
elp ssr "ssr: {_X = _Y} when _X == foo."
```
Reviewed By: michalmuskala
Differential Revision: D85443930
fbshipit-source-id: 108e2a583437fb3a6e702c21aef874395b376e7b
Summary:
The `test_lifecycle` test is intended to confirm that we do get multiple segments.
On a lightly loaded machine, the timing should be zero. This is not always the case, so to avoid flakiness we manually zero out the timing, so the essence of the test is not flaky
Reviewed By: jcpetruzza
Differential Revision: D85661410
fbshipit-source-id: b7d1130929692360a1284c78787f89f4e537cd88
Summary:
We can now specifiy a `buck_quick_start` config item and have ELP in server mode start up using a 2-step process, first doing a quick `buck targets` query and then the full `elp.bxl` one that includes generating some files, and is slower.
In order to understand the impact of these, we update the existing telemetry that reports the time from the server main loop starting to going operational (able to process client requests).
We now report as follows
- `buck_quick_start` not enabled
Normal operational telemetry using title "ELP operational"
- `buck_quick_start` enabled
"ELP operational (quick start)" for the first load
"ELP operational (full)" for the second
Both of these report the time from the initial main loop startup.
Reviewed By: robertoaloi
Differential Revision: D84343885
fbshipit-source-id: 1883fcdeabf1ba0cccb248d81a0b10fc6b6befb8
Summary:
This diff stack is about improving the initial IDE start experience when using a buck project that uses buck rules to generate some files, and for which that step takes a long time.
It does so by initially using a much faster buck command that does not do any code generation, but does expand all buck macros, `buck targets`. Based on this result, configures the ELP project model and goes operational with the given project file set.
While loading these files, it also does the normal full `elp.bxl` query to generate the additional required files. Once this is done, the project and its files are reloaded. This is basically a no-op except for adding in the newly generated files.
## This diff
This diff makes the changes to ELP in server mode to enact the process outlined above.
Reviewed By: robertoaloi
Differential Revision: D84343272
fbshipit-source-id: 8944767241f6f2ecb6c076e8c11a1a8c80057570
Summary:
Add an item to the config to enable/disable the buck quick query.
It is not used yet, that happens later in the stack
Reviewed By: robertoaloi
Differential Revision: D83662866
fbshipit-source-id: f2a04e9b73b47ae23f02edcb063d31a4a01d3974
Summary:
Add a test facility to `elp project-info` to be able to compare the target set arising from the `buck2 targets` call vs using `elp.bxl`.
This explicitly excludes any targets marked as generated by `elp.bxl`, as these will not appear in the bare `buck targets`.
It sorts the output according to whether it is an `App` or `Dep`, the app name and then the original buck target name, for investigation and confirmation.
Reviewed By: TheGeorge
Differential Revision: D83829236
fbshipit-source-id: be27273fdaf6d095b59eccda0cf74165510fe0b2
Summary: When we load a project using buck via elp.bxl, propagate the state of the "generated" label to the `ProjectAppData`. This allows the next diff in the stack to filter these apps out when generating a list of targets processed, for comparison with the quick-start targets.
Reviewed By: robertoaloi
Differential Revision: D83827651
fbshipit-source-id: ac7e4cf99c403e2fa26a1464fb290e9f789b8564
Summary:
A buck target is classified as an `App` or a `Dep`, according to whether it is part of the project being loaded or is one of its dependencies.
The `elp.bxl` script [provides this information](db5bf933af/prelude/erlang/elp.bxl (L94-L96)) by filtering the included targets for erlang_app/erlang_dep only, and marking these as apps.
It then generates the full configured graph from this set of targets, and the additional targets (erlang_apps only, no tests) are marked as deps. This is the step that takes a long time, and which we are avoiding in the initial step.
To achieve the same for the first step we also do two `buck targets` queries, one for the included targets as used in `elp.bxl`, the second for the buck config `deps_targets`, which are not used in `elp.bxl` as they are computed from the dependencies in the configured graph for the included targets.
Reviewed By: robertoaloi
Differential Revision: D83758970
fbshipit-source-id: ea84c51e76a63a1418cbbdd72718bdca076f4808
Summary:
We want to be able to compare the targets generated via `buck targets` with the ones generated via `elp.bxl`.
Each of these emits the targets in their own essentially random order.
This diff tweaks the processing of the `elp project-info` command so we can more easily compare the results with and without the new `--buck-quick-start` flag.
Reviewed By: robertoaloi
Differential Revision: D83662426
fbshipit-source-id: df15ba80a397f9b7b0614d045cb1d53c2f98f66a
Summary:
Create a structure for the output of the `buck2 targets` command, and deserialize it.
It is not being used yet, this will come later in the stack.
Reviewed By: robertoaloi
Differential Revision: D83660316
fbshipit-source-id: e27a4d30d2d5b36560d58912f974909a902164e4
Summary:
## Context
ELP with buck2 via elp.bxl has a slow startup time. This time is driven primarily by how long it takes the buck2 daemon to simply load the various BUCK files.
Given that the buck targets may generate code, which is triggered in elp.bxl, this is unavoidable for full-fidelity project loading.
There is a much quicker command, `buck2 targets`, which does not do any build steps for code generation, but does run all the buck2 macros. This gives us an accurate project representation for that portion of the project that is not generated.
Our ELP internal project model has the same representation for the initial subset query as for the full one, so we can do the quick query followed by the slow one without having to discard the work already done. In particular, it means simply adding source files to existing targets.
## This diff stack
This diff stack brings in this two step process, so that in IDE mode we first do a quick query and start file loading. As soon as the initial file loading is complete, we can go operational.
At the same time as we start file loading, we initiate the slower `elp.bxl` query which also triggers code generation. When that completes, we update the internal model and load the missing files.
The result is a quicker initial operation, albeit without access to any generated files, which are loaded when ready.
## This diff
This diff makes a start, by bringing in a command line argument to select the new behaviour. This defaults to off.
Reviewed By: TheGeorge
Differential Revision: D83660182
fbshipit-source-id: 9aea01d68fbacde5fb5fc032a6adbb522207741f
Summary:
**The core change is in `main.rs`**
There is no need for most snapshots to be generated for 3 different OTP versions. Only `custom.erl` needs it.
Add support for tag `OTPVersionDependent`, similarly to `generated`, to toggle this behaviour.
Add tag to `custom.erl` (on an existing line so as to not change the lines of error messages).
Reviewed By: michalmuskala
Differential Revision: D85602616
fbshipit-source-id: 4c85ecb3e2337d60cf83d13b7449e1b20246d9ed
Summary:
Structured Search (and not yet Replace) SSR is a way of specifying a "semantic grep", which searches by comparing the AST rather than text. We use it as a building block for diagnostics.
But often we want to just do a quick search for a pattern in a file or code base.
This diff allows us to do this, by specifying it in a config file.
Reviewed By: TD5
Differential Revision: D85340131
fbshipit-source-id: f1e4ce515a535cc6032483dc39297eab4e6eecd5
Summary: Take the patterns as a (mutable) input.
Reviewed By: alanz
Differential Revision: D85553374
fbshipit-source-id: a3185c3d0ffabc5af042fe88324cec6f79860462
Summary:
This is an eyesore when looking at type hints. We can get rid of them by a smart `apply` on `UnionType` that just removes `NoneType` - they're not meaningful.
This also removes single-element unions - they were also causing some poor error messages with superfluous explanations stating same facts twice.
There's no measurable change in time when running across the whole codebase.
Reviewed By: TheGeorge, ilya-klyuchnikov
Differential Revision: D85340363
fbshipit-source-id: 84759dcac6368c83624c7bd7f377273bb8151c37
Summary:
For a buck project having code generation, the `elp.bxl` script returns the various generated source paths in the `buck-out` directory. But the paths it returns include symlinks.
VS Code resolves symlinks when a file is opened, and all the communication with ELP as an LSP server is done using the canonical (no-symlinks) path.
When we go to a definition, we provide a path that may have a symlink.
We recently landed a diff titled `[ELP] check if a file is in a project when it opens` which checks if a file outside the project root in fact belongs to a project, via the list of `applicable_files` for a buck project.
For a symlinked file opened in VS Code and returned as canonical, this lookup fails. The failure also shows up another bug, in that the check to see if the file belongs to a project uses function `file_app_data` which falls back to checking for a `SourceRoot`, and panics for a file outside the root.
## This diff
This diff fixes both problems.
- It canonicalizes (without symlinks) the `applicable_files` for buck projects
- It rather uses `app_data_id_by_file` which does a simple loookup to check if the file belongs to a known project.
Reviewed By: jcpetruzza
Differential Revision: D85429234
fbshipit-source-id: e1f4867f8c66e69e219defd3ea742f431b994a21
Summary:
The actual top type for a function of arity `n` is `FunType(Nil, List.fill(n)(NoneType), AnyType)`, not `FunType(Nil, List.fill(n)(AnyType), AnyType)`, which means the negation of the predicate is not properly computed.
However, due to how intersection is computed (and particularly when it involves dynamic types), using this as a top type for the positive refinement leads to confusing signal, producing `none()` as domain. So this diff only uses it for the negative part.
Reviewed By: michalmuskala
Differential Revision: D85336038
fbshipit-source-id: 663393fe5919274c945435e764132faa4b0e7221
Summary: We have a currently failing buck test, fix it.
Reviewed By: jcpetruzza
Differential Revision: D85331710
fbshipit-source-id: a4e50354ec3553643d4283c58f4a283c3320ff2c
Summary: Add tip for ELP developers, to avoid slow compilation times during develoment.
Reviewed By: jcpetruzza
Differential Revision: D85240198
fbshipit-source-id: 93db3cc8646ff3d954fb2fe7af33963755727274
Summary: Simpler installation since the user does not have to clone a separate repository.
Reviewed By: jcpetruzza, alanz
Differential Revision: D85143542
fbshipit-source-id: 1302240a59c3c84b309cbfd2db00a52356160b10
Summary:
ELP has an assumption that all the files belonging to a given project have some common root directory, and when using buck this is marked by an `.elp.toml` file.
Now that we are using buck to generate some files as part of the build process, this assumption is no longer valid, as the generated files end up in the `buck out` directory, which is outside the normal project.
Further, ELP can handle more than one project at a time. So when a new file is opened in the client, we check if it belongs to one of the existing projects, and if not we configure a new project for it.
This leads to a situation where if we open one of the generated files, ELP will try to make a new project for it. This causes the ELP project-wide information to become invalid, as it is now spread over more than one. In particular this shows up as generated include files no longer being resolved.
## This diff
This diff addresses the issue by making use of the fact that every file in a buck project is explicitly enumerated, precisely because there it no simple directory enclosure mechanism to determine project owner.
So when a new file is opened, provided ELP is already in `Running` state and thus the internal database is valid, we check if the file is already known. If so we do not check for a possible new project.
Reviewed By: robertoaloi
Differential Revision: D85234832
fbshipit-source-id: 4858bbfa2d51d1e3f030f666f706a2ffb155e0f1
Summary:
Often when devmate wants to run a test if first uses the directory name, then looks up the crate name and uses that.
Hopefully this helps
Reviewed By: TheGeorge
Differential Revision: D85059984
fbshipit-source-id: f560f4f920545611a9a2738140688db3c6f58551
Summary:
Many applications are included in the Erlang/OTP release, but they are not used by a project. Processing them leads to unnecessary work and memory consumption. This diff adds a new `otp` configuration section to the `.elp.toml` file, allowing users to customize a list of OTP applications to exclude from the analysis.
* Add new `OTP` section to ELP Config
* Pass reference to the whole ELP configuration to the project loading function
* Forward OTP config section to OTP discovery function
* Perform filtering
* Add documentation on how to use the new feature
Reviewed By: TheGeorge
Differential Revision: D83974071
fbshipit-source-id: eae11cd06eca9380d00ca5f7a3a70bb659d6ab71
Summary:
At the moment these rustfmt.toml files are ignored. Our formatting tool has an explicit rustfmt.toml passed to it that overrides anything set by the code owners.
This diff updates the project's rustfmt.toml to match the one we explicitly set.
This diff also copies our explicit config in `tools/rust/ossconfigs/rustfmt.toml` to `fbsource/.rustfmt.toml`.
Reviewed By: dtolnay
Differential Revision: D84118394
fbshipit-source-id: bbc931ffd89798d5b519a1b600f11a977ac55fc8
Summary:
Instead of fetching eqwalizer during CI via a GitHub action, include it as a submodule.
This allows us to have reproducible builds.
Pull Request resolved: https://github.com/whatsapp/erlang-language-platform/pull/120
Reviewed By: jcpetruzza
Differential Revision: D85077705
Pulled By: robertoaloi
fbshipit-source-id: f771f604978db69dc5afcad955315a7eb59912d3
Summary: Introduce a helper to create a "rename" fix, that can be used when implementing linters.
Reviewed By: alanz
Differential Revision: D85067389
fbshipit-source-id: 887f393f32003996254a2a374fb671a496de2c55
Summary: Introduce a method to simplify the extraction of the module name range from a call target (MFA).
Reviewed By: alanz
Differential Revision: D85046064
fbshipit-source-id: 06eacdd4911169e8ea1821d2ad30f1e7ea8f9f2a
Summary:
These tests are [failing](5279163353) on GitHub pipelines using OTP 26.
The tests only make sense for OTP 27+, so do not run them on older versions.
Reviewed By: TheGeorge
Differential Revision: D85071954
fbshipit-source-id: fa8c665cc11e191ae7c4e073f844a8eb0c60c66b
Summary:
# Context
For linters based on [traits](https://whatsapp.github.io/erlang-language-platform/docs/contributing/linters/linter-traits/) we can customize their behaviour via config. Here we extend the configuration mechanism we already use for `severity` and other properties to the `is_enabled` flag. This mechanism will eventually supersede the `enabled_lints` and `disabled_lints` [configuration properties](https://whatsapp.github.io/erlang-language-platform/docs/get-started/configure-project/elp-lint-toml/#enabled_lints).
# Why having a new way to enable and disable linters?
Currently, the `.elp_lint.toml` allows users to specify which linters are enabled or disabled. But the configuration file works in a very counter-intuitive way: say a linter is "disabled by default". To enable it, a user cannot simply add it to the `enabled_list`, since that would cause **only that linter** to run. A user would need to add all available linters to the config, which is clearly not a maintainable solution.
By supporting an override mechanism, it will be possible to - for example - have the following configuration:
```
[linters.my_linter]
enabled = true
```
Which would keep the *enabled* status for all other linters to their default value, ensuring `my_linter` is enabled.
# This diff
This diff introduces the new overriding mechanism. We still keep it undocumented, until all linters are migrated to use a trait.
Reviewed By: TheGeorge
Differential Revision: D85055745
fbshipit-source-id: f84d203c380a45dcbafae5d09dc9141d42a12e91
Summary:
Basically a revert of D84170122, clarified in comments.
When using `--include-tests`, diagnostics for non-opted-in test suites will be output as `Severity::Disabled`, so as to be registered in contlint but to not appear in CI.
Reviewed By: michalmuskala, jcpetruzza
Differential Revision: D84914421
fbshipit-source-id: e428de9b0e55c8dda2040f4e030cac32a3201fcd
Summary: Support typing of `Pat = Var = Expr` following a simple commutativity rule (since `=` is right-associative).
Reviewed By: ilya-klyuchnikov
Differential Revision: D78550714
fbshipit-source-id: 97dda4ea82f15eafc5cad3a094da5835729f0b01
Summary: Snapshot tests for exprs of the form `Pat = Var = Expr`.
Reviewed By: michalmuskala
Differential Revision: D84819136
fbshipit-source-id: a229e453ea48d2bb6b0b45ad430d362b765f58ee
Summary:
Small follow-up from D44162698.
Define the `is_in_otp` helper as part of `File`, to make it more discoverable.
Reviewed By: jcpetruzza
Differential Revision: D84890853
fbshipit-source-id: 7e57f58c75a6db506196318f9e93afdefc03fd1d
Summary: Counterpart of the previous fix. Do not report potentially false positives in case a function is a variable.
Reviewed By: alanz
Differential Revision: D84832054
fbshipit-source-id: 4a0b2fde715da4bfcab83f802d95da1a31a797ff
Summary: Even if the `deprecated_functions` linter is not experimental, the produced diagnostics were incorrectly tagged as experimental. This caused them not to be seen.
Reviewed By: alanz
Differential Revision: D84829863
fbshipit-source-id: 374389a764cb13dd792ea5dbee37dd3b79b2e9e8
Summary:
The `deprecated_function` linter reports diagnostics covering the whole range of the function call, including arguments. This makes the code really hard to read. Only cover the function name.
This will be simplified once the linter is converted to use a trait.
Reviewed By: alanz
Differential Revision: D84829846
fbshipit-source-id: a8d0b5a0e52e222bce6464209063cc79b3bda74a
Summary: If the module is a variable, we can't determine at compile time whether the function is defined or not, so don't report it.
Reviewed By: alanz
Differential Revision: D84827250
fbshipit-source-id: ec0c5c4238e8e4952b5fdf8a871326461ade7e25
Summary:
Since OTP 27, [it's possible to use `-doc` attributes for user defined types](https://www.erlang.org/doc/system/documentation.html).
This diff enables extraction of type documentation for both local and remote types, ensuring documentation is visible on hover.
Since no test cases were covering documentation extraction, I also added a couple of them for functions.
Reviewed By: alanz
Differential Revision: D84680999
fbshipit-source-id: 120dbfab0e046e34363563c7139369cb36de202b
Summary:
Users prefer to be able to more quicly select the extract variable than extract function in the VS Code UI.
Change the order these are presented to enable this.
Reviewed By: michalmuskala
Differential Revision: D84612436
fbshipit-source-id: 8a0f7c21568248137f07337ec0256d4ed8d811ea
Summary:
`include` will only treat the given string as a path while `include_lib` parses out `app_a` and looks in the library directory of that application
Pull Request resolved: https://github.com/whatsapp/erlang-language-platform/pull/118
Reviewed By: alanz
Differential Revision: D84483303
Pulled By: robertoaloi
fbshipit-source-id: eeb6a7956045ea6ef15398672bffee80a845694c
Summary:
The testcase was not using the `simple_*` helpers, causing it to run with a buck2 config on GitHub. Buck2 is not yet configured there, causing the test to fail.
Introduce a new helper that a testcase to match on the output, rather than having a completely deterministic output (memory can vary). By using the helper, apply the same filtering on the buck feature as in the other tests.
Reviewed By: alanz
Differential Revision: D84498544
fbshipit-source-id: 6cd58f05914cfa218496280c0e4331c2f162980a
Summary:
Move the `print_memory_usage` function to the `reporting` module and use it from the `lint` command.
This represents the first step towards a generic argument that can be used by various commands and will be merged with similar options existing for other commands.
Reviewed By: alanz
Differential Revision: D84347271
fbshipit-source-id: 3c19b87e3c48bc8e790e1a96eb40014deddd87ac
Summary:
The conditional in `Cargo.toml` is problematic, since it produces a different lock file if compilation happens on GitHub via Cargo. Apart from polluting the workspace with a change, it also makes it hard to use the `--locked` option when building (e.g. part of the standard cargo options in Homebrew).
Simply point to crate and leave a comment explaining how to modify the `Cargo.toml` locally for easier development.
Reviewed By: alanz
Differential Revision: D84346947
fbshipit-source-id: 25fe550e0feec7c2a2567debfaecf8318a0c523a
Summary:
Inspired by the [Rust Analyzer version of it](90d2e1ce4d/crates/ide-db/src/apply_change.rs (L47)), include per-query memory stats when asking for `--report-system-stats`.
For now the logic is limited to `parse-elp` (since the argument was added there), but it should be easily generalizable for the other ELP commands. That will be done as a follow-up.
Reviewed By: alanz
Differential Revision: D83324535
fbshipit-source-id: a076c2001da4e05649816d05729658515757c323
Summary:
When running in LSP mode, we do not immediately advertise all the ELP cababilities to client, holding back outline support.
This is because while we are doing our initial loading we do not process request messages from the client, and the VS Code one only asks for the outline once, when a file is first opened.
So we register dynamic capabilities once, when ELP switches to `Running` state after completing the initial file loading.
The current implementation registers the dynamic capabilities when loading is complete, which means that if the project model changes and we reload it will register again. This results in a fresh outline request, and the VS Code client then presents two outlines for the same file.
## This diff
So in this diff we add a flag in the server state and only register the dynamic capabilities once.
Reviewed By: robertoaloi
Differential Revision: D84244032
fbshipit-source-id: b1b9b2a5ddd935a58659ff13b92407a265cee34a
Summary:
Do not cut off check for extract variable anchor just because it is inside a macro call.
Also add a companion test to extract function, and rename its `FunctionBody` to `FunctionBodyToExtract`, as we now have another `FunctionBody` in `sema`, and it is confusing.
Reviewed By: TheGeorge
Differential Revision: D84165349
fbshipit-source-id: e771e2aec74d02e18d8679ace2ebc1e59ee9cf66
Summary:
A project can have thousands of files. We report loader progress as the VFS loader loads these, presented on the VS Code status bar as a percentage figure.
This means that we send multiple duplicate messages while loading, as the percentage number changes relatively slowly compared to the number of files loaded.
This onslaught of messages can however overload the LSP client, resulting in a status bar that does not accurately reflect the current ELP loading state as it updates from the backlog in a received queue of messages.
## This diff
This diff reduces the number of messages sent, without losing any information, by keeping track of the current percentage value, and only sending a progress message when it changes.
Reviewed By: TheGeorge
Differential Revision: D84140378
fbshipit-source-id: 13fd4e39b87010c70b692abd7aeb15beddef2dbd
Summary:
The logic to filter and output diagnostics only for opted-in modules is now redundant since we only eqWAlize opted-in modules. This is an artifact left from when we advised to opt-in errorless modules.
Remove it since it conflicts with reporting errors in tests with arc lint.
Reviewed By: RobinMorisset
Differential Revision: D84170122
fbshipit-source-id: caa84b4cabd9edc75482d826acd2bcc5aed723e8
Summary:
Fix some issues in WhatsApp ELP Glean:
- Set exdoc_link to None on GitHub to avoid breaking CI tests.
- Replaced the actual file path with a fake one in serialization_test.out.
- Replaced the actual module behaviours with fake ones in unit tests.
- Enhanced serialization_test_v1 to cover the module fact.
Reviewed By: robertoaloi
Differential Revision: D84062457
fbshipit-source-id: 4b369b9eb9164af2463639eec80f41ff19b49e5e
Summary:
* Restructure the linter tutorial into multiple pages to improve readability
* Add docs for the other types of linters
* Show line numbers and highlight affected lines in code snippets
Reviewed By: alanz
Differential Revision: D83986965
fbshipit-source-id: db7b31c23a8f86961895ee154b15321280ec984b
Summary:
We want to clearly track the time from ELP starting up to when it can be used.
To this end we introduce a new telemetry item, with a title of "ELP operational". This is currently defined as the first point when the status changes to `Running`.
Reviewed By: robertoaloi
Differential Revision: D83977797
fbshipit-source-id: eb95a6d7b3c6ef7b1ea7ddae99e4ebe6e5bb318c
Summary: Add a testcase that showcases an existing bug in ELP.
Reviewed By: alanz
Differential Revision: D83968438
fbshipit-source-id: 6fdb5d98fb0634b9c5de16c8f35c0489cecb3915
Summary:
In D41220041 (Nov 2022), we started reporting only direct references for the "find references" functionality. The idea was to filter out references such as the entry in the export list, which were adding noise in the UI, making it harder to find actual references.
Dynamic calls were incorrectly classified as "other", causing dynamic calls not be returned as references (but still working in rename operations, since they applied to *all* references).
Reviewed By: alanz
Differential Revision: D83967812
fbshipit-source-id: bd89c247e89f5823f542c8598b7a28d05b87c9b5
Summary:
Now that the list of patterns has a certain size, use a hash-map, combined with `lazy_static`.
Also, introduce a macro to make the definitions less verbose.
Reviewed By: jcpetruzza
Differential Revision: D83843586
fbshipit-source-id: 2a9b0f7ace4e285c7d08737400859618404938fb
Summary:
Extend detection for dynamic calls to the most common ones from the `erpc` module.
Later in the stack we will use a more performant data structure and a macro to reduce verbosity.
Reviewed By: jcpetruzza
Differential Revision: D83843587
fbshipit-source-id: 0c0172266e1c6dc382b46ada20faca84c0022b3a
Summary:
Extend detection for dynamic calls to the most common ones from the `erlang` module. Given that some of these calls refer to functions by arity, extend the original mechanism to support both variants.
Later in the stack we will use a more performant data structure and a macro to reduce verbosity.
Reviewed By: jcpetruzza
Differential Revision: D83840802
fbshipit-source-id: 1fc91f1b368cda4fb3b12ee5fb934871ee672cad
Summary:
Extend detection for dynamic calls to the most common ones from the `rpc` module.
Later in the stack we will use a more performant data structure and a macro to reduce verbosity.
Reviewed By: jcpetruzza
Differential Revision: D83840542
fbshipit-source-id: 165c400c9a5c9cd092957460fca06a99d2ff6846
Summary:
In addition to `erlang:apply/2,3` we want to include other dynamic calls via the find-references / go-to-definition / rename mechanism.
This diff prepares the territory by generalizing the matching, which will then be extended with additional calls.
Reviewed By: jcpetruzza
Differential Revision: D83746070
fbshipit-source-id: 06bd2eb47362be6d1a14084adf53442741487d9c
Summary:
Starting in September 2025, GitHub moved the `latest` Windows label from 2022 to 2025. See the [announcement](https://github.com/actions/runner-images/issues/12677). This is the most likely cause behind the error:
```
Error: Tried to map a target OS from env. variable 'ImageOS' (got win25), but failed. If you're using a self-hosted runner, you should set 'env': 'ImageOS': ... to one of the following: ['ubuntu22', 'ubuntu24', 'win19', 'win22', 'macos13', 'macos14', 'macos15']
```
While this could be, in turn, caused by an issue with the `erlef/setup-beam` action, for the time being pin the version to 2022.
Reviewed By: jcpetruzza
Differential Revision: D83565904
fbshipit-source-id: 3bf7b8d6839c320fd017faa1f4597525009d747e
Summary:
In D82544032 ELP was modified to only return doc links for functions containing an actual documentation.
While there may be other issues affecting the VSCodeErlangOpenDocs E2E test, this is a requirement for the test to pass.
Reviewed By: TheGeorge
Differential Revision: D83559010
fbshipit-source-id: 2cda6051d38a486ef9854a992877e7113bbe6370
Summary: The ELP OSS CI started to fail on certain platform due to a missing `erlfmt` component. Unsure what changed, but explicitly setting the components during the setup process ensures the formatter can be run all problematic platforms.
Reviewed By: jcpetruzza
Differential Revision: D83474194
fbshipit-source-id: d205361d61f9219b584844b4722e417af7b204c8
Summary:
We now have buck2 cell information, which is cached in a mutex variable as it should not change for the life of a project.
But in tests we set it to fixed values, and check the result. When tests are run in parallel, this can cause flakiness as values from one test are seen in another.
Add a global mutex around the test setup to prevent this.
Reviewed By: robertoaloi
Differential Revision: D83479480
fbshipit-source-id: efdeaf3c1f7f2c7b3cee6ec5f0ac0e4e90edcece
Summary:
## Context
We are now watching for changes to the inputs of targets that are generated by buck2.
But our existing logic to detect if a project needs reloading is based on hierarchical containment of the changed file inside the project somewhere.
For generated targets this is not always the case, so we need some additional logic.
# This diff
We now keep a map for each generated target input to the application and this project it belongs to, via an `AppDataId`.
This allows us to replace the watched path with one inside a project, and use the normal project reload determination logic.
Reviewed By: TheGeorge
Differential Revision: D83257306
fbshipit-source-id: 1e251d594e37c8c7edc08859722614b66a7f5ba3
Summary:
We now have the inputs in our project model, add them to the file watching spec.
Note that we add the specific files, rather than using a glob spec based on the parent directory. The upstream target landscape is too complex to try and track more than this.
Reviewed By: robertoaloi
Differential Revision: D83256350
fbshipit-source-id: 608a1e71aff3afa130d2b7132a515aaf39689d2e
Summary:
## Context
Our generated targets have output in the `buck-out` directory, which is isolated from the normal buck2 build because we use an isolation directory when we run `elp.bxl`. This means we cannot watch these files for changes when doing a buck2 build, and must monitor the inputs from the targets instead.
D83155666 extends `elp.bxl` to provide this information.
## This diff
Capture this information in the buck project model when running `elp.bxl`. This sets the stage for using it higher up in the stack.
Reviewed By: robertoaloi
Differential Revision: D83255606
fbshipit-source-id: 9cf4cbee34a1f5ec0a0a5da7ace5d95de0de8adf
Summary:
## Context
We have been assuming that the buck2 targets we care about are all in the same buck2 cell, corresponding to the buck root.
This is not always the case, and we are starting to use targets from diverse locations.
## This diff
Update the target to absolute directory processing to use the buck2 target cell information for the given project.
Reviewed By: TheGeorge
Differential Revision: D83245484
fbshipit-source-id: 8410ba36992d6369dccf09a85ffc780d40e33500
Summary: In D83100279 we noticed a massive memory usage provoked by the `elp parse-elp` command. To ease this type of investigations, add a `--report-memory-stats` flag to the command, that can be used to dump memory usage.
Reviewed By: TD5
Differential Revision: D83167289
fbshipit-source-id: a6b059ea45e2db19d674dd4107bafc437fee3dd4
Summary: To do so, we need to extend the SsrLinter trait to support two more optional callbacks: `scope` and `range`.
Reviewed By: alanz
Differential Revision: D83152114
fbshipit-source-id: 5e950d47e0787721360f90c5cb14248944822514
Summary: Track the file, position and duration of processing a references request
Reviewed By: michalmuskala
Differential Revision: D83053371
fbshipit-source-id: 84261b4c8a9d13c89458c33a76aa8e13b54d4d71
Summary:
The API to extract documentation currently takes a *position* as the input and returns an `Option<Doc>`. This is not ideal, since it collapses two cases into one: `None` can be returned if no meaningful token is identified or if no documentation is available for it.
As a first step towards introducing telemetry for hover operations, have a clearer distinction between the two cases.
Here we:
* Split token extraction and fetching documentation
* Introduce a `DocResult` struct which stores additional information about the input token
* Introduce basic telemetry for the *hover* operation
This will expanded in a subsequent diff to include more information about the actual documentation.
Reviewed By: alanz
Differential Revision: D82948615
fbshipit-source-id: c0dbc2bb99519ef5522288ed5bc910f34105bc54
Summary:
Define a new `GenericLinter` trait for linters which do not use either the `find_call_in_function` helper or SSR patterns.
As an example, convert the `unused_macro` linter to the new trait.
Apart from simplifying the way linters are written, the big advantage is that linters using the trait can leverage common infrastructure (e.g. including an ignore fix) and they can now be configured / enabled via config.
Note: the `None` variant for the `DiagnosticTag` was eliminated in favour of the standard `Option` type, which allowed some code simplifications.
Reviewed By: alanz
Differential Revision: D82638562
fbshipit-source-id: 25c63591f4ae60ea4e89cbbd79e91e9b95d404ed
Summary:
The ELP telemetry currently includes a start time, as a struct having seconds since the Unix epoch and nanoseconds.
This gives us an accurate start time, as we cannot rely on the SCUBA logged time, as it is the time the message is received, which is after many unpredictable events through the middleware.
It also includes a duration in milliseconds.
It is hard to work with these in SCUBA, especially for casual comparisons.
This diff introduces a string representation of the start time as a time stamp to millisecond resolution, as well as an end time stamp, computed from the start time and duration.
Reviewed By: robertoaloi
Differential Revision: D82956324
fbshipit-source-id: 8201875d320cca23358bd1c6d780d4c536e1c557
Summary:
There is chronicle logging of the state change notification we send, but this is marked against the time-stamp when it is received in SCUBA, and this is often inaccurate.
Provide an explicit telemetry item for it, including the current time as seen by ELP
Reviewed By: robertoaloi
Differential Revision: D82954038
fbshipit-source-id: e048b8ace05d5169f7333f17961a0b9112cbf7d4
Summary:
We currently send a summary telemetry message when a progress bar ends, with each of the steps included in it.
This is currently stored in rust as a `FxHashMap` of segment title and time taken. This does not keep the relative ordering of the segments, so detailed knowledge of the originating code is needed to understand the order.
Simplify this by using a `Vec<(name,time)>` instead.
Reviewed By: robertoaloi
Differential Revision: D82953458
fbshipit-source-id: 8f37e3135d5781505c60c3f30556273859eec7f9
Summary: By using the local def_map, we avoid external file ids altogether.
Reviewed By: alanz
Differential Revision: D82636531
fbshipit-source-id: d0015a6002b14c237b2be5722deffa194543a5a1
Summary: Convert the `cross_node_eval` linter to use the `FunctionCallLinter` trait.
Reviewed By: alanz
Differential Revision: D82633601
fbshipit-source-id: 131c5cfb09b5747813ee0e551bf20c4324b4d79b
Summary:
The apply lint process can error. Make sure we check in our tests that it does not.
This makes it easier to catch regressions.
Reviewed By: TD5
Differential Revision: D82713866
fbshipit-source-id: dac9e83f392d5e47a46aa4ffb81d8f2ddd5c79f7
Summary:
An Erlang project can be compiled with the [`warnings_as_errors`](https://www.erlang.org/doc/apps/compiler/compile.html#file/2) option, which causes warnings to be treated as errors.
ELP does not respect this option when it comes to diagnostics produced by the Erlang Service (the Erlang sidecar running next to ELP), which can create confusion in the user: if `warnings_as_errors` is specified, ELP would only raise a warning (both in the IDE and in the CLI), but the project would fail compilation.
Here we add a new configuration section for the `[erlang_service]`, where the option can be explicitly passed. Later on, we could automatically expand this mechanism to auto-extract the option from either a rebar3 or a buck2 project. For now, that's considered out of scope.
Since the Erlang Service validates Erlang modules using a fork of the [`erl_lint`](https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_lint.erl) linter, which does not respect the `warnings_as_errors` option, we tweak the result on ELP side.
We also document the new config section.
Reviewed By: alanz
Differential Revision: D82628908
fbshipit-source-id: f3ced1cf333b463657cbc13113129bb15533a9d6
Summary: [elp.bxl](https://fburl.com/code/euy3qis2) no longer reports an origin of type "prelude", so remove it with ELP.
Reviewed By: TD5
Differential Revision: D82548892
fbshipit-source-id: 5d69942503faefd530d34d0c4b3591a671f10e56
Summary:
The `--deps_targets` CLI argument is no longer used in [`elp.bxl`](https://fburl.com/code/8fbkds7w).
We remove it in ELP, so it can later be removed from `elp.bxl`
Reviewed By: TD5
Differential Revision: D82547631
fbshipit-source-id: c59400bd8ff126871031729bf9a59fcd4854dd3e
Summary: There is no point in showing a link if we know the pointed module/function has no docs.
Reviewed By: alanz
Differential Revision: D82544032
fbshipit-source-id: 27f5bf58c18afb44d57b6a1628e3a6383f77483e
Summary:
Add an `exclude` config option for linters implementing the `FunctionCallLinter` trait, allowing to exclude matches via config.
Since the implementation uses `lazy_static` behind the scenes, this is only applied after a server restart.
This will later be used to avoid hard-coding the exclusion list for the `undefined_functions` linter.
For the time being, I'm using the default deserialization, so that one can write:
```
[linters.undefined_function]
exclude = [
{type = "MFA", mfa = "my:function/2"}
]
```
This can be later refined not to require the boilerplate from users, but auto-detect the M, F or MFA.
Reviewed By: alanz
Differential Revision: D82535853
fbshipit-source-id: fe7bd54c0f1e6c803a6bca16b8951e27ac4dcc58
Summary:
Expand the `find_call_in_function` capabilities to allow excluding specific functions by using a vector of *FunctionMatch*.
Then, add an optional `excludes_functions` method to the `FunctionCallLinter` trait.
Use the new method to simplify the code in `undefined_function` to specify the exclusion list at a higher level.
This is in preparation of making the list of exclusions configurable via the TOML file, which will happen next.
Reviewed By: TD5
Differential Revision: D82526373
fbshipit-source-id: 1f07c8495655103d479dc76b6837b3968edb7dba
Summary:
The previous version of the linter was conflating two distinct diagnostic codes into one. While this was more efficient in the sense that we would iterate once, the logic was quite hairy.
This diff splits the old linter into two, making the logic and the intent more clear.
Reviewed By: TD5
Differential Revision: D82443533
fbshipit-source-id: d4684c49fecbedace31e0a00b83b87da6aabf7fc
Summary: Avoid the `is_*` pattern, given the function does not return a boolean (or optional boolean).
Reviewed By: alanz
Differential Revision: D82433078
fbshipit-source-id: d418c7c5e0c5f18d7de8403864d4b27f021c367d
Summary: Convert the `no_forgets_api` linter to the new trait. To enable the migration, ensure the `file_id` is available in the `is_match_valid` function.
Reviewed By: jcpetruzza
Differential Revision: D81593935
fbshipit-source-id: c00d5c7f5078ba04fb22c13238367ff1ebc91398
Summary: Use relative paths to invoke the meta-specific commands, and provide alternatives using `cargo`, configured via Shipit
Reviewed By: robertoaloi
Differential Revision: D82296502
fbshipit-source-id: 854591848d4c5212cf0cd0eda57559acf5cc7411
Summary:
VS Code allows project-specific tasks to be configured for a project.
Add some ones for ELP development on an OD, so the various build flavours and clippy checks can be invoked.
Reviewed By: TD5
Differential Revision: D82212928
fbshipit-source-id: daf2502db247ca60f216ec84a7bbae0f54f29225
Summary:
This diff brings feature parity when it comes to code lenses between `rebar3` and `buck2` projects. Specifically:
* Adds the `openInteractive` command to the OSS extension, which starts a rebar3 shell
* Adds the `debugInteractive` command to the OSS extension, which starts a rebar3 shell in debug mode (no tests are run)
* Adds the `runInteractive` command to the OSS extension, which runs the test in an open shell (either a debugging one or not)
* It enables the "debug" and "interactive" lenses by default
* It adds some extra logging
Reviewed By: alanz
Differential Revision: D82101533
fbshipit-source-id: cb051a1b6a968bc603d81d7045bfd9e34ddb5b73
Summary:
We received various reports of false positives for the `W0017` (`undefined_function`) linter. In both cases this was due to the usage of the [`lager`](https://github.com/erlang-lager/lager) logging library, which relies on a parse transformation, causing functions such as `lager:warning/X` or `lager:error/X` to be recognized as undefined.
While the medium-term plan is to allow linters to get a custom config such as:
```
[linters.undefined_function]
excludes = [
"lager",
"some:call",
"some:other/3"
]
```
For the time being, add `lager` to the hard-coded exclusion list, to mitigate the issue, reducing noise for end users.
Reviewed By: TD5
Differential Revision: D82094926
fbshipit-source-id: e73eb0ca4315a17e63d35938801badd44d7ac7fd
Summary:
Diagnostic and quick fix for simple string-related expressions which would generally be better as literals.
e.g.:
```erlang
fn() ->
atom_to_list(foo).
%% ^^^^^^^^^^^^^^^^^ 💡 information: Could be rewritten as a string literal.
```
becomes
```erlang
fn() ->
"foo".
```
Reviewed By: alanz
Differential Revision: D81578353
fbshipit-source-id: 51d73cd4ad9c01b39d90f97115f89d8469bdea16
Summary:
Previously, we didn't escape erlang strings and atoms correctly - we'd wrap them in quotes when pretty printing, but didn't escape Erlang's special characters. We add that here. **This does not offer a complete solution**, merely a step in the right direction: We don't try to handle `erl_features` keywords, for example, since they are much more complex to track.
See official Erlang implementation as a reference: ae81b2f6ff/lib/stdlib/src/io_lib.erl (L971)
Reviewed By: alanz
Differential Revision: D81776458
fbshipit-source-id: 0d7058d6e4c564005b3c4d5bc56846dd3938f277
Summary:
# Context
When working with a buck2 project, we do not simply use source roots, as a given buck2 target can be configured to use files and dependencies from anywhere.
To cope with this, we build an include-file lookup structure at project loading time, which is partly populated with information from the output of the bxl query.
If a new `.hrl` or `.erl` file is added, it is not obvious which target is should be part of, to update the relevant application and include file lookup table.
# This Diff
This diff takes a conservative approach to files being added, as they should be a reasonable rare occurrence.
It checks for a notification of a newly created source file (once in the `Running` state), and if so triggers a project reload. The query for this happens in a separate thread, and when there is a valid result it is applied. Since there is only an additional file, most of salsa should still be valid, so it does not cause cascading changes. Existing file ids are retained, as Vfs is not flushed in the process.
Reviewed By: robertoaloi
Differential Revision: D81783795
fbshipit-source-id: 19012379179d0d841bc4b0b24ccd3011e1bfab5d
Summary: This was causing a GitHub CI failure: 4970891471
Reviewed By: alanz
Differential Revision: D81902529
fbshipit-source-id: a9007bc6cc61ab52e93217d85036b52ada507250
Summary: add wam browser link into the record doc
Reviewed By: robertoaloi
Differential Revision: D81522678
fbshipit-source-id: 115f64f117b46eabe7131a3936e673ad6c32a30e
Summary:
To avoid a GitHub CI failure as in:
4957434008
Reviewed By: alanz
Differential Revision: D81774626
fbshipit-source-id: a452985ed3d1f2022b627130f75a481e0521db59
Summary:
Convert the `atoms_exhaustion` linter to use the `Linter` trait.
To enable this, ensures `sema` is available in the `is_match_valid` method.
Reviewed By: jcpetruzza
Differential Revision: D81589208
fbshipit-source-id: a41788a0d5979737550749b007f3d7b2d9413b3f
Summary:
Allow instances of the `FunctionCallLinter` trait to implement two new custom methods:
* `is_valid_match`
* `fixes`
The first one, given the *call context* allows to validate each match and return a linter-specific context which is passed around to the other functions.
The `fixes` method allows a linter to specify custom fixes. It receives the context produced by the `is_valid_match` method as part of the *match context*.
The `debugging_function` is then converted to use the new approach, becoming much simpler.
The templating mechanism from the `helpers` module is totally gone, and replaced by the new trait-based one.
There's one performance implication: when the `FunctionCallLinter` trait was introduced, we started collecting "specs" and performing a fold only once. While this approach was convenient, it would have made implementing this new functionality a lot more complicated. Instead, I propose we sacrifice the extra folds (after all, that was state of the world before traits) for the time being. This brings the function call linters closer to the SSR-based ones. Then we can think of a different approach for folding/visiting.
Reviewed By: jcpetruzza
Differential Revision: D81516582
fbshipit-source-id: 6b9dd28b91eb272a670c5bf8679660c600c8611a
Summary: The property will be later used by some of the linters (e.g `debugging_functions`).
Reviewed By: TD5
Differential Revision: D81481377
fbshipit-source-id: d1cf925f63dea74a2ef42b1bed8b13de27b32e97
Summary: Merge the processing of FunctionCallLinters / SSrLinters into a single function, avoid code duplication.
Reviewed By: TD5
Differential Revision: D81474340
fbshipit-source-id: 87df4ed02248bf16c8fe0bfc537fb9b05cdd44a3
Summary:
Fixes broken wording in the docs.
Created from CodeHub with https://fburl.com/edit-in-codehub
Reviewed By: jcpetruzza
Differential Revision: D81518020
fbshipit-source-id: d34f487ff1a21e07d32560f732c69bc77f5fe715
Summary:
Start removing the duplication for handling different types of linters. Here we extract the conditions calculations into a helper function.
This will be further simplified later.
Reviewed By: TD5
Differential Revision: D81474341
fbshipit-source-id: b69796d6d36533e48c2ae3fff0783613be3535d6
Summary: Be able to override the `experimental` property of a linter via config.
Reviewed By: TD5
Differential Revision: D81450739
fbshipit-source-id: c18b449249d48fc089709d17a5d6b1c1560db6f3
Summary: Similarly to the other properties.
Reviewed By: TD5
Differential Revision: D81450512
fbshipit-source-id: 4002024a72d5e6af87583a2502d7f2edf861aaf2
Summary:
Similarly to D81443678, make the `include_tests` property also configurable.
The duplication between `diagnostics_from_function_call_linters` and `diagnostics_from_ssr_linters` will be addressed separately.
Reviewed By: TD5
Differential Revision: D81449612
fbshipit-source-id: 2c40afd9a4c70092be5a2476f5afffee06789d40
Summary:
Severity is currently hardcoded by linters and there's no mechanism to override it. This is inconvenient for two reasons:
* Changing the severity for the linter requires an ELP release
* The linting experience cannot be easily customized by the external community
This is a first step towards a more generic linter configuration mechanism for ELP, which will incrementally expanded.
Since this is currently respected only by the linters implementing the `Linter` trait, we keep the feature currently undocumented.
Reviewed By: TD5
Differential Revision: D81443678
fbshipit-source-id: 17783df15cabb0f7c16493a461e457fd214b2bc6
2025-09-02 04:45:26 -07:00
1213 changed files with 22985 additions and 46318 deletions
ELP (Erlang Language Platform) is a language server and development tools suite for Erlang, built in Rust. This project provides IDE features, diagnostics, and code analysis for Erlang codebases.
ELP (Erlang Language Platform) is a language server and development tools suite
for Erlang, built in Rust. This project provides IDE features, diagnostics, and
code analysis for Erlang codebases.
## Build System
Use standard Cargo commands:
```bash
# Build
cargo build --release
# Run tests
cargo test --workspace
# Run clippy
cargo clippy --tests
# Format code
cargo fmt
# Code generation
cargo xtask codegen
```
## Diagnostic Code Management
@ -15,13 +38,13 @@ ELP (Erlang Language Platform) is a language server and development tools suite
When adding new diagnostic codes to `DiagnosticCode` enum:
1. **Naming Convention**: Use descriptive PascalCase names that clearly indicate the issue
1. **Naming Convention**: Use descriptive PascalCase names that clearly indicate
/// Types as defined in https://www.internalfb.com/intern/wiki/Linting/adding-linters/#flow-type
/// and https://www.internalfb.com/code/fbsource/[1238f73dac0efd4009443fee6a345a680dc9401b]/whatsapp/server/erl/tools/lint/arcanist.py?lines=17 /
// @fb-only: /// Types as defined in https://www.internalfb.com/intern/wiki/Linting/adding-linters/#flow-type
// @fb-only: /// and https://www.internalfb.com/code/fbsource/[1238f73dac0efd4009443fee6a345a680dc9401b]/whatsapp/server/erl/tools/lint/arcanist.py?lines=17
usestd::path::Path;
useserde::Serialize;
#[derive(Debug, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pubstructDiagnostic{
// Filepath
path: String,
@ -29,6 +30,7 @@ pub struct Diagnostic {
original: Option<String>,
replacement: Option<String>,
description: Option<String>,
doc_path: Option<String>,
}
#[derive(Debug, Serialize, PartialEq, Eq)]
@ -42,6 +44,7 @@ pub enum Severity {
}
implDiagnostic{
#[allow(clippy::too_many_arguments)]
pubfnnew(
path: &Path,
line: u32,
@ -50,6 +53,7 @@ impl Diagnostic {
name: String,
description: String,
original: Option<String>,
doc_path: Option<String>,
)-> Self{
Diagnostic{
path: path.display().to_string(),// lossy on Windows for unicode paths
"markdownDescription": "Whether to use the expermintal `buck2 targets` quick start process.",
"type": "boolean"
},
"elp.diagnostics.disabled": {
"default": [],
"items": {
@ -673,6 +716,11 @@ mod tests {
"markdownDescription": "Whether to show the `Link` lenses. Only applies when\n`#elp.lens.enable#` is set.",
"type": "boolean"
},
"elp.lens.logview.links": {
"default": false,
"markdownDescription": "Whether to enable LogView lens links.",
"type": "boolean"
},
"elp.lens.run.coverage.enable": {
"default": true,
"markdownDescription": "Display code coverage information when running tests via the\nCode Lenses. Only applies when `#elp.lens.enabled` and\n`#elp.lens.run.enable#` are set.",
@ -688,6 +736,16 @@ mod tests {
"markdownDescription": "Whether to show the `Run Interactive` lenses. Only applies when\n`#elp.lens.enable#` is set.",
"type": "boolean"
},
"elp.lens.scuba.links": {
"default": false,
"markdownDescription": "Whether to enable Scuba lens links.",
"type": "boolean"
},
"elp.lens.wam.links": {
"default": false,
"markdownDescription": "Whether to enable WAM lens links.",
"type": "boolean"
},
"elp.log": {
"default": "error",
"markdownDescription": "Configure LSP-based logging using env_logger syntax.",
[check_include_separate_1/include/top_includer.hrl] 3:10-3:30: E1516: can't find include file "does_not_exist.hrl"
Diagnostics reported:
Reporting all diagnostics codes
Diagnostics reported in 4 modules:
app_a: 3
0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced.
0:8-0:13::[WeakWarning] [W0046] The module is not documented.
auto_gen_a: 2
0:0-0:0::[Error] [W0012] Please add "-compile(warn_missing_spec_all)." to the module. If exported functions are not all specced, they need to be specced.
0:8-0:18::[WeakWarning] [W0046] The module is not documented.
eqwalizer: 1
1:8-1:17::[WeakWarning] [W0046] The module is not documented.
wa_buck2_module_search: 6
19:0-19:18::[WeakWarning] [W0040] The function is non-trivial, exported, but not documented.
2:8-2:30::[WeakWarning] [W0046] The module is not documented.
49:18-49:31::[WeakWarning] [W0051] Binary string can be written using sigil syntax.
51:18-51:28::[WeakWarning] [W0051] Binary string can be written using sigil syntax.
51:38-51:51::[WeakWarning] [W0051] Binary string can be written using sigil syntax.
55:30-55:40::[WeakWarning] [W0051] Binary string can be written using sigil syntax.
"markdownDescription": "Whether to use the expermintal `buck2 targets` quick start process.",
"type": "boolean"
},
"elp.diagnostics.disabled": {
"default": [],
"items": {
@ -88,6 +93,11 @@
"markdownDescription": "Whether to show the `Link` lenses. Only applies when\n`#elp.lens.enable#` is set.",
"type": "boolean"
},
"elp.lens.logview.links": {
"default": false,
"markdownDescription": "Whether to enable LogView lens links.",
"type": "boolean"
},
"elp.lens.run.coverage.enable": {
"default": true,
"markdownDescription": "Display code coverage information when running tests via the\nCode Lenses. Only applies when `#elp.lens.enabled` and\n`#elp.lens.run.enable#` are set.",
@ -103,6 +113,16 @@
"markdownDescription": "Whether to show the `Run Interactive` lenses. Only applies when\n`#elp.lens.enable#` is set.",
"type": "boolean"
},
"elp.lens.scuba.links": {
"default": false,
"markdownDescription": "Whether to enable Scuba lens links.",
"type": "boolean"
},
"elp.lens.wam.links": {
"default": false,
"markdownDescription": "Whether to enable WAM lens links.",
"type": "boolean"
},
"elp.log": {
"default": "error",
"markdownDescription": "Configure LSP-based logging using env_logger syntax.",
{"path":"app_a/src/diagnostics.erl","line":3,"char":10,"code":"ELP","severity":"disabled","name":"W0037 (unspecific_include)","original":null,"replacement":null,"description":"Unspecific include.\n\nFor more information see: /erlang-error-index/w/W0037"}
{"path":"app_a/src/diagnostics.erl","line":4,"char":1,"code":"ELP","severity":"error","name":"L0000 (L0000)","original":null,"replacement":null,"description":"Issue in included file\n\nFor more information see: /erlang-error-index/l/L0000"}
{"path":"app_a/src/diagnostics.erl","line":4,"char":10,"code":"ELP","severity":"disabled","name":"W0037 (unspecific_include)","original":null,"replacement":null,"description":"Unspecific include.\n\nFor more information see: /erlang-error-index/w/W0037"}
{"path":"app_a/src/diagnostics.erl","line":6,"char":31,"code":"ELP","severity":"error","name":"L1295 (L1295)","original":null,"replacement":null,"description":"type undefined_type/0 undefined\n\nFor more information see: /erlang-error-index/l/L1295"}
{"path":"app_a/src/diagnostics.erl","line":7,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function main/1 is unused\n\nFor more information see: /erlang-error-index/l/L1230"}
{"path":"app_a/src/diagnostics.erl","line":10,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function foo/0 is unused\n\nFor more information see: /erlang-error-index/l/L1230"}
{"path":"app_a/src/diagnostics.erl","line":3,"char":10,"code":"ELP","severity":"disabled","name":"W0037 (unspecific_include)","original":null,"replacement":null,"description":"Unspecific include.\n\nFor more information see: /erlang-error-index/w/W0037","docPath":"website/docs/erlang-error-index/w/W0037.md"}
{"path":"app_a/src/diagnostics.erl","line":4,"char":1,"code":"ELP","severity":"error","name":"L0000 (L0000)","original":null,"replacement":null,"description":"Issue in included file\n\nFor more information see: /erlang-error-index/l/L0000","docPath":null}
{"path":"app_a/src/diagnostics.erl","line":4,"char":10,"code":"ELP","severity":"disabled","name":"W0037 (unspecific_include)","original":null,"replacement":null,"description":"Unspecific include.\n\nFor more information see: /erlang-error-index/w/W0037","docPath":"website/docs/erlang-error-index/w/W0037.md"}
{"path":"app_a/src/diagnostics.erl","line":6,"char":31,"code":"ELP","severity":"error","name":"L1295 (L1295)","original":null,"replacement":null,"description":"type undefined_type/0 undefined\n\nFor more information see: /erlang-error-index/l/L1295","docPath":null}
{"path":"app_a/src/diagnostics.erl","line":7,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function main/1 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null}
{"path":"app_a/src/diagnostics.erl","line":10,"char":1,"code":"ELP","severity":"warning","name":"L1230 (L1230)","original":null,"replacement":null,"description":"function foo/0 is unused\n\nFor more information see: /erlang-error-index/l/L1230","docPath":null}
{"path":"app_a/src/diagnostics.erl","line":12,"char":8,"code":"ELP","severity":"warning","name":"W0060 (bound_var_in_lhs)","original":null,"replacement":null,"description":"Match on a bound variable\n\nFor more information see: /erlang-error-index/w/W0060","docPath":"website/docs/erlang-error-index/w/W0060.md"}
{"path":"app_a/src/lints.erl","line":5,"char":1,"code":"ELP","severity":"error","name":"P1700 (head_mismatch)","original":null,"replacement":null,"description":"head mismatch 'head_mismatcX' vs 'head_mismatch'\n\nFor more information see: /erlang-error-index/p/P1700"}
{"path":"app_a/src/lints.erl","line":5,"char":1,"code":"ELP","severity":"error","name":"P1700 (head_mismatch)","original":null,"replacement":null,"description":"head mismatch 'head_mismatcX' vs 'head_mismatch'\n\nFor more information see: /erlang-error-index/p/P1700","docPath":null}
error: incorrect_param_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_param_type_in_cb_implementation)
┌─ check/src/callbacks5_neg.erl:13:1
│
13 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^ Parameter 1 in implementation of gen_server:format_status/2 has no overlap with expected parameter type. Expected: 'normal' | 'terminate', Got: 'bad'.
error: incorrect_param_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_param_type_in_cb_implementation)
┌─ check/src/callbacks5_neg.erl:13:1
│
13 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^ Parameter 1 in implementation of gen_server:format_status/2 has no overlap with expected parameter type. Expected: 'normal' | 'terminate', Got: 'bad'.