Compare commits

...

314 commits

Author SHA1 Message Date
Roberto Aloi
7a4eccf14d Add support for linter-specific excluded_apps
Some checks failed
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / edb (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-12-23 03:53:02 -08:00
Roberto Aloi
4bba415bc1 Fix diagnostic name
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Missed during the original rename.

Reviewed By: alanz

Differential Revision: D89460380

fbshipit-source-id: 60446aa3f505d635ad5ddc842b2d420c24f0a9d2
2025-12-22 09:17:24 -08:00
Roberto Aloi
6456f325c3 Ignore buck-out in test_projects
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
Summary: So that version control systems do not try to publish the directory.

Reviewed By: alanz

Differential Revision: D89550389

fbshipit-source-id: d60646ddd4e8f0ae443673dac3c49efbac60dba7
2025-12-19 08:58:10 -08:00
Roberto Aloi
5c7cfae09d Only enable Buck2 project model tests if feature is enabled
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
2025-12-19 08:58:10 -08:00
Alan Zimmerman
220acfd4f7 Back out "Allow project discovery for OTP"
Summary: It breaks navigation to stdlib

Reviewed By: TD5

Differential Revision: D89552844

fbshipit-source-id: 676af5f520d9189f98828b4364b0b1665531b245
2025-12-19 08:49:54 -08:00
Roberto Aloi
fc09ff94fd Enable buck2 tests on GitHub
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
2025-12-19 07:43:01 -08:00
Alan Zimmerman
8e82f1cee4 Fix codegen_test test project for new buck root
Summary: As title

Reviewed By: TheGeorge

Differential Revision: D89543670

fbshipit-source-id: 8d4a417a58950ad9f9d8877839561f407d0e9cc0
2025-12-19 04:09:00 -08:00
Facebook Community Bot
8cb6ac7620
Re-sync with internal repository (#144)
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
2025-12-19 10:51:11 +00:00
Roberto Aloi
8b4c533527 Convert EDoc syntax to plain comments in codegen_test_SUITE
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-18 23:41:12 -08:00
Roberto Aloi
b12cf72c7e Standalone Buck2 setup for test_projects
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-18 14:47:07 -08:00
Alan Zimmerman
ce0125dec9 1/n: bound var in match: detect problem
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-18 07:05:33 -08:00
Alan Zimmerman
d7b1c561ad Fix GH CI for OTP 26
Summary: As title.

Reviewed By: robertoaloi

Differential Revision: D89461312

fbshipit-source-id: 3c0c75da6ccd00735d3f444b123b0bab222d0980
2025-12-18 05:36:31 -08:00
Roberto Aloi
3804bd1706 Enable undefined_function linter in CI (prod only)
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
2025-12-18 03:37:42 -08:00
Roberto Aloi
439ebade1b Rename edoc linter into old_edoc_syntax
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
2025-12-18 03:37:42 -08:00
Roberto Aloi
54dd1089ed Do not run the old_edoc_syntax linter against test files by default
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
2025-12-18 03:37:42 -08:00
Alan Zimmerman
fa05043043 Allow project discovery for OTP (#141)
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-17 09:53:03 -08:00
Victor Lanvin
79c33480c5 Support for OTP version specific tests
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-17 08:54:32 -08:00
Alan Zimmerman
7057624c73 elp lint: print diagnostics in the case we are not streaming and not applying a fix
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
2025-12-17 06:36:56 -08:00
Alan Zimmerman
4a051d1af8 10/n: rename module: in defines RHS
Summary: Add a test demonstrating that the module rename happens in `.hrl` files too

Reviewed By: TheGeorge

Differential Revision: D89053579

fbshipit-source-id: f999484c08a5c33c76986156c10a2f6a7d34fc52
2025-12-17 06:00:04 -08:00
Alan Zimmerman
91a0d968db 9/n: rename module: remote calls in original module
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
2025-12-17 06:00:04 -08:00
Alan Zimmerman
cc0a9c26d5 8/n: rename module: well known function arguments
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
2025-12-17 06:00:04 -08:00
Alan Zimmerman
83d5b4dfd0 7/n: rename module: check module name in a call
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
2025-12-17 06:00:04 -08:00
Alan Zimmerman
9015d80659 6/n: rename module: external fun reference
Summary: A module name can occur in an external fun. Rename it too.

Reviewed By: robertoaloi

Differential Revision: D88849514

fbshipit-source-id: e715628a6fbfe419cd56761fe62b43d3b68ecde4
2025-12-17 06:00:04 -08:00
Alan Zimmerman
8997372e1a 5/n: rename module: move original file
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
2025-12-17 06:00:04 -08:00
Alan Zimmerman
bef3dd15f2 4/n: rename module: exported type references
Summary: When renaming a module, rename all references to types within it

Reviewed By: robertoaloi

Differential Revision: D87860496

fbshipit-source-id: 2ac6bc52cecaef6802fcf9f181b638f81c556d67
2025-12-17 06:00:04 -08:00
Alan Zimmerman
56e66e2cd5 3/n: rename module: renaming function references
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
2025-12-17 06:00:04 -08:00
Alan Zimmerman
a0e076cb17 2/n: rename module: simple rename works
Summary: First case, just rename the module

Reviewed By: robertoaloi

Differential Revision: D87860412

fbshipit-source-id: 0427f09bd2176778e0280b0f45f9331fa279f778
2025-12-17 06:00:04 -08:00
Alan Zimmerman
8ff602f1c3 1/n rename module, basics
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
2025-12-17 06:00:04 -08:00
Alan Zimmerman
4a83d0edde BE: extract bound_vars_by_function as a method for sema
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
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
2025-12-17 01:32:35 -08:00
Alan Zimmerman
271065da03 BE: for a fold, track the macro definition for ctx.in_macro
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
2025-12-17 01:32:35 -08:00
Roberto Aloi
37b7c5e28e Introduce top-level test directory
Reviewed By: michalmuskala

Differential Revision: D89272460

fbshipit-source-id: 91eb93d7df55a1ca64fe2b05e21097daca3b6d33
2025-12-17 01:18:32 -08:00
Roberto Aloi
d4e14636b4 Do not run selected linters on tests by default
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Differential Revision: D89302965

fbshipit-source-id: 9b5c1d3c6402a6fea9f3fd5a6d93c2e49acba51e
2025-12-16 15:30:53 -08:00
Open Source Bot
b2ea905e7f Updating hashes
Summary:
GitHub commits:

020284a6e8
261ff05851
acdd3baf0a
b435fe91fa
a75b46bbbc
427330df23
fd2a5c46a7
e95090adb4
c28a092249
fab1e58dfd
848ddcedb2
270d39b2c3
65b11fc090
0f514eb389

Reviewed By: pranavcivi

fbshipit-source-id: 0c3453ad24a874db08fbc66cc4945f70c64d25d0
2025-12-16 11:27:09 -08:00
Facebook Community Bot
858b8e64ab
Re-sync with internal repository (#143)
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
2025-12-16 10:54:56 -08:00
Alan Zimmerman
271a52c37c honour --include-generated for elp ssr
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title

Reviewed By: michalmuskala, TD5

Differential Revision: D89292307

fbshipit-source-id: cbde669d57276b2aaa2c7365906e3ed86f15aec5
2025-12-16 09:08:25 -08:00
Roberto Aloi
ba4505e981 Do not run application_env linter on test suites
Reviewed By: alanz, TheGeorge, michalmuskala

Differential Revision: D89287769

fbshipit-source-id: 29618250ee6d75ede850603cb60c5e4d77e3ff06
2025-12-16 08:56:01 -08:00
Alan Zimmerman
d2da476882 Add test project for code gen
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
2025-12-16 02:03:43 -08:00
Victor Lanvin
166770cc92 Remove logic for --include-tests, opt-in tests
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-15 03:16:34 -08:00
Roberto Aloi
b525eac0ea Pass range to fixes callback
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-12-12 06:17:31 -08:00
Victor Lanvin
2bd3d57d02 Clean-up old error messages
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
2025-12-12 06:08:41 -08:00
Roberto Aloi
eb5e0abbf8 Install Buck2 in OSS CI workflow
Summary: In preparation for enabling Buck2 tests on GitHub, we install the Buck2 binary.

Reviewed By: michalmuskala

Differential Revision: D89038926

fbshipit-source-id: 7e37c7e9ec143391e10eba8597df2b2aa9d55d0f
2025-12-12 04:22:36 -08:00
Alan Zimmerman
887d287c94 tweak elp parse-elp --severity output
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
2025-12-12 03:56:28 -08:00
Roberto Aloi
553c90d631 Bump OSS VS Code extension to 0.47.0
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
2025-12-12 03:02:33 -08:00
Alan Zimmerman
a16af7e9e2 Update emacs eglot instructions
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
2025-12-12 02:19:15 -08:00
Alan Zimmerman
0085fba772 Add --severity argument to elp parse-elp to limit output
Summary: As title.

Reviewed By: TD5

Differential Revision: D88963207

fbshipit-source-id: a8cc5ddfedcfa8063537e586ac086c8a0caac465
2025-12-12 01:38:41 -08:00
Victor Lanvin
babf61214c Bad occurrence typing with maps:foreach -- repro
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-12-11 07:25:42 -08:00
Roberto Aloi
7b0b29ae21 Temporarily ignore hierarchical_config tests
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
2025-12-11 06:36:45 -08:00
Alan Zimmerman
4bfedaee9a BE: validate all test fixtures
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
2025-12-11 06:21:28 -08:00
Alan Zimmerman
290b931170 BE: validate test fixture
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
2025-12-11 06:21:28 -08:00
Alan Zimmerman
0930edd693 BE: report malformed test fixture
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
2025-12-11 05:22:57 -08:00
Alan Zimmerman
2d693f3578 BE: restore expected test result to generate a panic
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary:
As title.

Note that this is still failing on GH.

Reviewed By: robertoaloi

Differential Revision: D88751685

fbshipit-source-id: 4050a9f2094ac7c46395f0f05a7f77dfad9a583b
2025-12-10 08:59:12 -08:00
Victor Lanvin
0aef1f4005 Update fixtures for OTP 26/28
Summary: As title.

Reviewed By: robertoaloi, TD5

Differential Revision: D88853775

fbshipit-source-id: 8954794c428f6f1139ebe4f393ed80d1836a2784
2025-12-10 08:08:55 -08:00
Roberto Aloi
29c017c565 Polish extension README, improve package.json for discoverability
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-15-intel, macos-15-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-15-intel, macos-15-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary:
* Polish extension README (which is rendered [here](https://marketplace.visualstudio.com/items?itemName=erlang-language-platform.erlang-language-platform)).
* Set `displayName` (see [reference](https://code.visualstudio.com/api/references/extension-manifest)) to improve discoverability and hopefully ranking
* Update description
* Add `erlang` keyword to improve discoverability/ranking

Reviewed By: alanz

Differential Revision: D88847040

fbshipit-source-id: e2185e790f0711dd383d6cc51ad56716eeebb61e
2025-12-10 07:06:30 -08:00
Roberto Aloi
ed8820b3b2 Update Intel runners to mac-15-interl
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
2025-12-10 07:06:17 -08:00
Roberto Aloi
a239a322cf Manually bump eqwalizer to the latest available version (#139)
Summary: Pull Request resolved: https://github.com/whatsapp/erlang-language-platform/pull/139

Reviewed By: alanz

Differential Revision: D88849209

Pulled By: robertoaloi

fbshipit-source-id: f3433841b248804dde41fca866680f8c6eaef338
2025-12-10 07:03:12 -08:00
Roberto Aloi
a4ded31602 Bump OSS VS Code extension to 0.46.0
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
2025-12-10 07:00:19 -08:00
Roberto Aloi
6dbefe9bd0 Add Homebrew installation instructions for Mac users
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
2025-12-10 03:50:13 -08:00
Roberto Aloi
4df5a7ae81 Bump OSS VS Code extension version to 0.45.0
Summary: In preparation for OSS release.

Reviewed By: alanz

Differential Revision: D88839310

fbshipit-source-id: f489b3e503c41e8302193cbdc78a46859967cbda
2025-12-10 03:45:29 -08:00
Roberto Aloi
f6b54832d7 Convert malformed_include linter to use a trait
Summary: Mechanical conversion, no functional change.

Reviewed By: alanz

Differential Revision: D88623867

fbshipit-source-id: 2d1f17430a44a705f22ec542e242165beb577285
2025-12-10 03:29:08 -08:00
Alan Zimmerman
1a086de994 BE: args.color
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-09 08:47:59 -08:00
Alan Zimmerman
77e0ff9bc8 Remove pre_parse_for_speed from elp eqwalize-all
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
2025-12-09 08:47:59 -08:00
Alan Zimmerman
debed39b42 streaming results for elp lint
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
2025-12-09 08:47:59 -08:00
Alan Zimmerman
c404d942df Update emacs eglot instructions for semantic tokens (#138)
Summary: Pull Request resolved: https://github.com/whatsapp/erlang-language-platform/pull/138

Reviewed By: michalmuskala

Differential Revision: D88746400

Pulled By: alanz

fbshipit-source-id: 0bfda35e25ebf62b62ec7f8209d1787fdbb58e80
2025-12-09 07:58:59 -08:00
Victor Lanvin
0f7069d02e Deprecate old error messages
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-09 06:29:17 -08:00
Roberto Aloi
e1296c5c14 Convert boolean_precedence linter to use a trait
Some checks are pending
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Mechanical conversion, no functional change.

Reviewed By: TheGeorge

Differential Revision: D88620344

fbshipit-source-id: fb8a06f034b9c8ebf088acedad1d75769b340293
2025-12-08 04:50:14 -08:00
Roberto Aloi
4e6851c71a Convert misspelled_attribute linter to use a trait
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
2025-12-08 04:50:14 -08:00
Roberto Aloi
61512bf9b9 Convert unused_include linter to use trait
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
2025-12-08 04:50:14 -08:00
Roberto Aloi
4726f8144d Convert missing_module linter to use a trait
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
2025-12-08 04:50:14 -08:00
Roberto Aloi
016e0d7c1e Fix false positive for undefined_function linter
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
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
2025-12-05 03:48:33 -08:00
Eddie Shen
fd8fb4abeb Replace Duration::from_secs(240) to Duration::from_mins(4)
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
2025-12-05 00:22:38 -08:00
Eddie Shen
c9cba57e40 Replace Duration::from_secs(60) to Duration::from_mins(1)
Summary:
X-link: https://github.com/meta-pytorch/torchft/pull/297

X-link: https://github.com/meta-pytorch/monarch/pull/2066

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: D88434166

fbshipit-source-id: e5e86763e0f4cfa6da502d32f1f98ffc198399ed
2025-12-05 00:22:38 -08:00
Roberto Aloi
796f015f20 Make it possible to run buck tests in isolation
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-04 09:45:48 -08:00
Roberto Aloi
d42e431df4 Add merge logic for linters configuration
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
2025-12-04 07:38:39 -08:00
Roberto Aloi
9ef2fec36e Add test for hierarchical config support
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
2025-12-04 07:38:39 -08:00
Alan Zimmerman
3461b85029 Improve emacs eglot config
Some checks are pending
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-03 06:46:58 -08:00
Alan Zimmerman
1fc2f63da8 Correctly report diagnostics from header file
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-03 03:18:32 -08:00
Alan Zimmerman
8bd2c5e571 Include related information in elp lint non-json output
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
2025-12-03 03:18:32 -08:00
Alan Zimmerman
8558c9d5dc Add tree_print for a whole module
Some checks are pending
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-12-02 08:11:47 -08:00
Alan Zimmerman
cbe9a058cc update dependencies for dependabot
Summary: As title

Reviewed By: michalmuskala

Differential Revision: D88143729

fbshipit-source-id: cd5ecc02442e7661b4bf2f7e3f9b7f346561b2c4
2025-12-02 04:52:04 -08:00
Alan Zimmerman
e4b89ebac5 BE: fix clippy warnings
Some checks are pending
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title

Reviewed By: michalmuskala, TD5, robertoaloi

Differential Revision: D88143231

fbshipit-source-id: d7eebb3449b3c05a07ba1b5228930c13dd5708f0
2025-12-02 03:07:14 -08:00
Alan Zimmerman
f80d50389d remove --prefix command line argument
Summary: This should no longer be needed, remove it to reduce code complexity

Reviewed By: jcpetruzza

Differential Revision: D87929715

fbshipit-source-id: c62a6e07084d555bba12dafb96fb893e33f6dc9f
2025-12-02 01:53:20 -08:00
Roberto Aloi
eafb4940c7 Convert edoc linter to use a trait
Some checks are pending
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Mechanical conversion.

Reviewed By: alanz

Differential Revision: D87546425

fbshipit-source-id: 4d938866586d89f9a6751e9b0c787c1faf1759d0
2025-12-01 09:05:40 -08:00
Roberto Aloi
270b8f4614 Fix support for rebar3 projects in IDE
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
2025-12-01 08:24:18 -08:00
Alan Zimmerman
89c0c87b0f Do not check for eqwalizer disappearing if we did not unpack it
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
2025-12-01 07:13:44 -08:00
Roberto Aloi
3e873e691d Make labels to denote test applications configurable
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-11-28 12:31:40 -08:00
Roberto Aloi
87bc60c524 Remove support for obsolete test_utils and elp_enabled Buck2 labels
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
2025-11-28 12:31:40 -08:00
Daniel Gorin
38c84d39a6 Remove unclear bits of W0050 docs
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-28 03:19:17 -08:00
Alan Zimmerman
7b124c7f06 Server: Impose a priority on next task selection
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-28 02:27:14 -08:00
Alan Zimmerman
06892be8c1 Add server telemetry for workspace statistics
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-27 01:48:55 -08:00
Alan Zimmerman
0da6ec3079 Introduce elp --color argument to control ANSI color codes
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-11-25 02:35:22 -08:00
Roberto Aloi
8997d5eb03 Implement support for renaming types
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
2025-11-25 02:19:42 -08:00
Cj Longoria
4fa7b6c8ac add internal rustfmt bin to elp cargo script
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
2025-11-25 02:19:37 -08:00
Alan Zimmerman
8dbbd1f6d4 Back out "Fix failing test"
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title

Reviewed By: robertoaloi

Differential Revision: D87786080

fbshipit-source-id: ab642c7b92b51c4df38fdef64f6741423e70e55a
2025-11-24 10:10:03 -08:00
Roberto Aloi
fe49f6ba3c Implement support for renaming macros
Summary: Long awaited feature: the ability to rename macros.

Reviewed By: alanz

Differential Revision: D87635298

fbshipit-source-id: 252ccd64193251fa9b0ce91cf6ab421c15c84086
2025-11-24 09:47:00 -08:00
Alan Zimmerman
be0cb21ea7 Make elp search a synonym for elp ssr
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary:
As title.

In future we may remove `elp ssr`.

Reviewed By: TD5

Differential Revision: D87766502

fbshipit-source-id: c9742292afe35984002d02b20ec0e051cfee125f
2025-11-24 05:04:16 -08:00
Alan Zimmerman
0de513221f ssr: stream command line match results
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
2025-11-24 05:04:16 -08:00
Alan Zimmerman
473c0f1c56 Fix failing test
Summary: As title

Reviewed By: ilya-klyuchnikov, michalmuskala

Differential Revision: D87765456

fbshipit-source-id: deb9fc32f4bc547215619e43fecdaecf7ceb5a0f
2025-11-24 02:55:57 -08:00
Roberto Aloi
bc2c3f05d4 Require glob >=10.5.0
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
Summary: Solves [GHSA-5j98-mcp5-4vw2](https://github.com/isaacs/node-glob/security/advisories/GHSA-5j98-mcp5-4vw2?fbclid=IwY2xjawONHSxleHRuA2FlbQIxMQBicmlkETFmTTVyb3hBUmNTbUNLeDlrc3J0YwZhcHBfaWQBMAABHt4eAVx-Yk7Cnshn0Hqrh-vQ8xKvHyVaF7_ovUMQhWSrRWN8um2ZimI4Vfmu_aem_B4s_KCafXrEOOcNU-AnJRA).

Reviewed By: TheGeorge

Differential Revision: D87628344

fbshipit-source-id: ab6ff51e5ddade4b93318606d573e6f7e5d043d5
2025-11-22 06:22:58 -08:00
Alan Zimmerman
0c2b43eb27 ssr: add test explicitly using colour output
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title

Reviewed By: TD5

Differential Revision: D87651912

fbshipit-source-id: 347be29dbb6f0dd71396dbb404b2ac98a9dbabc0
2025-11-21 10:19:14 -08:00
Alan Zimmerman
fbdb3e1baf ssr: Improve rendering of result
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-21 08:12:17 -08:00
Roberto Aloi
5470044b61 Bump js-yaml from 4.1.0 to 4.1.1 and glob from 10.4.5 to 10.5.0
Summary: Fix https://github.com/nodeca/js-yaml/security/advisories/GHSA-mh29-5h37-fv8m and https://github.com/isaacs/node-glob/security/advisories/GHSA-5j98-mcp5-4vw2

Reviewed By: jcpetruzza

Differential Revision: D87634207

fbshipit-source-id: 50ef19e9b138252d43a631b2c9501ca9a764b74a
2025-11-21 05:49:13 -08:00
Roberto Aloi
9860cc85f1 Publish OSS extension to OpenVSX marketplace
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
2025-11-21 02:44:09 -08:00
Roberto Aloi
5820634ce2 Allow severity method to receive &Semantic and FileId as arguments
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
2025-11-21 02:03:27 -08:00
Roberto Aloi
99501811a5 Remove text_edit crate
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
2025-11-21 02:03:27 -08:00
Roberto Aloi
b25b590a27 Move tree-diff functionality from syntax to ide_db crate
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
2025-11-21 02:03:27 -08:00
Roberto Aloi
1788ac77bd Move Emacs configuration under editors
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
2025-11-21 02:03:27 -08:00
Roberto Aloi
44409a4346 Remove bench runner draft
Reviewed By: alanz

Differential Revision: D87516838

fbshipit-source-id: ab8bc396f005e8c3cf843583b61bd0e06e8ee2ca
2025-11-21 02:03:27 -08:00
Alan Zimmerman
7571e57155 BE: fix off-by-one in elp lint diagnostic output
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-20 07:30:38 -08:00
Roberto Aloi
77ff228aae Convert macro_precedence_surprise linter to use a trait
Summary: Simple conversion to use the new trait.

Reviewed By: jcpetruzza

Differential Revision: D87516327

fbshipit-source-id: 8a6669c4c337a54ecf0a65c864df8be40d82e720
2025-11-20 04:38:57 -08:00
Roberto Aloi
e9a9035e5a Convert no_warn_suppressions linter to use a trait
Summary: Simple conversion to use the new trait.

Reviewed By: jcpetruzza

Differential Revision: D87447644

fbshipit-source-id: 74e0caf1fc8fd289013af2fc69839b25f0b9bdc4
2025-11-20 04:38:57 -08:00
Roberto Aloi
5187bf3d3f Convert duplicate_module linter to use a trait
Summary: Simple conversion to use the new trait.

Reviewed By: TD5

Differential Revision: D87445553

fbshipit-source-id: 8b45cea1dcefe71b0cd573aa4529433974943d3f
2025-11-20 01:02:30 -08:00
Roberto Aloi
74ed6b2de4 Convert no_dialyzer_attribute linter to use a trait
Summary: Simple conversion to use the new trait.

Reviewed By: TD5

Differential Revision: D87079003

fbshipit-source-id: 7caaf84bf43882045637fe870046537e5eb82a5f
2025-11-20 01:02:30 -08:00
Roberto Aloi
cac1c952f9 Extend unavailable_type diagnostic to also scan record definitions
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
2025-11-20 01:02:30 -08:00
Roberto Aloi
89ca280740 Ensure that linters specified via --diagnostic-filter run, even if disabled by default
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
2025-11-20 01:02:30 -08:00
Roberto Aloi
479c76ce85 Add unavailable_type diagnostic
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
2025-11-20 01:02:30 -08:00
Open Source Bot
65de999b3b Updating hashes
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary:
GitHub commits:

5a717a3930
b93909fb2a
c4ca15fcd7
2d38838986
f777219636
2ac8a7c0bb
8010220b21
c5209193b7
01b2a4fb60
c22a8d4dd8
03c425fcf4
ce1f68dda5
1e0f24c5b8

Reviewed By: sdwilsh

fbshipit-source-id: 8f60cbe0f2feac847240f89707cb2023201f1e54
2025-11-19 09:40:39 -08:00
Jon Janzen
9a91229311 Rollback submodule to enable syncing 2025-11-19 11:28:14 -08:00
Alan Zimmerman
8efb4fe29c BE: track related info in declarative tests
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-19 03:56:10 -08:00
Alan Zimmerman
dcf4e3a4ff add file_id to diagnostic RelatedInformation
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
2025-11-19 03:56:10 -08:00
Daniel Gorin
8394c84d6b Bump docusaurus to 3.9.2
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
Summary: This also bumps js-yaml to 4.1.1, addressing CVE-2025-64718

Reviewed By: robertoaloi

Differential Revision: D87222063

fbshipit-source-id: f36270df43f8412a880df7e730f562178a825156
2025-11-17 13:07:42 -08:00
Roberto Aloi
717422ebfe Convert the no_catch linter to use a trait
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Simple conversion to use the new trait.

Reviewed By: TD5

Differential Revision: D87078566

fbshipit-source-id: 5e019d3b968a78997d1ebe24f5b168cf8fce4b1f
2025-11-17 02:22:16 -08:00
Roberto Aloi
30a992691f Convert the undocumented_function linter to use trait
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-11-14 10:05:06 -08:00
Roberto Aloi
20b8d9950a Convert undocumented_module linter to use trait
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
2025-11-14 10:05:06 -08:00
Roberto Aloi
aca24c8fc3 Convert missing_compile_warn_missing_spec linter to use trait
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
2025-11-14 10:05:06 -08:00
Alan Zimmerman
276297e366 6/n: include: do not report W0058 if is is already reported by the erlang service
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-14 04:35:24 -08:00
Alan Zimmerman
a8bb2de049 5/n: include: report HIR unresolved include files W0058
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
2025-11-14 04:35:24 -08:00
Alan Zimmerman
ed673119e4 4/n: include: do not report W0057 if it is already reported by the erlang service
Summary: As title.

Reviewed By: TD5

Differential Revision: D86963332

fbshipit-source-id: ffb3020fbfd6b09a273d4e34cb28f353fa12deab
2025-11-14 04:01:31 -08:00
Alan Zimmerman
42ef1d1924 3/n: includes: convert HIR diagnostics into ide Diagnostic W0057
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
2025-11-14 04:01:31 -08:00
Alan Zimmerman
6fe7f108a1 2/n: includes: record macro expansion failures when lowering to HIR
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
2025-11-14 04:01:31 -08:00
Alan Zimmerman
59ec8ab042 1/n: includes: add not-yet-failing test case for nested include buck targets
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
2025-11-14 04:01:31 -08:00
Tom Davies
f050c6c671 Support calls to lists:nth/2
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-13 07:23:15 -08:00
Roberto Aloi
395db3dda7 Add lists_reverse_append linter
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
2025-11-13 06:33:43 -08:00
Alan Zimmerman
4486d66840 Clarify tool usage for building and testing the project in elp_development.md
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Clarify tool usage for building and testing the project in elp_development.md

Reviewed By: TD5

Differential Revision: D86951935

fbshipit-source-id: 972aea59d3050c258270bbb1694b968d83655858
2025-11-13 03:14:38 -08:00
Alan Zimmerman
f4b93ec388 Improve file watch logging destination
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: The temp directory location is not the same on all platforms.

Reviewed By: jcpetruzza

Differential Revision: D86679320

fbshipit-source-id: 39db19df4377798348ae81c87ffb9599e6f87334
2025-11-12 06:30:58 -08:00
Facebook Community Bot
c5263ed926
Re-sync with internal repository (#131)
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.
2025-11-12 14:03:18 +00:00
Alan Zimmerman
e0c5e94ac0 Add file watch logging for project switch decisions
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-12 03:31:52 -08:00
Alan Zimmerman
b01a09f2ff elp ssr: set info priority when --dump-config is set
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
2025-11-12 01:56:31 -08:00
Alan Zimmerman
49fb231fe9 BE: remove workspace reference to non-existent erl_ast crate
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
Summary: As title.

Reviewed By: jcpetruzza

Differential Revision: D86513055

fbshipit-source-id: 068357b9d6976bca2838036c5dbe308afbb52fe7
2025-11-10 03:36:04 -08:00
Alan Zimmerman
412ccca85e Update elp_development.md to improve declarative test example
Summary: We now include the diagnostic code in the expected diagnostic.

Reviewed By: RobinMorisset

Differential Revision: D86658752

fbshipit-source-id: 43f835633a0c81c15d7f43cfcdfde967db9a3178
2025-11-10 03:01:11 -08:00
Alan Zimmerman
85c1586d7d Add initial CLAUDE.md
Summary: As title. Also tweak elp_development.md

Reviewed By: TheGeorge

Differential Revision: D86507504

fbshipit-source-id: 0c3d92728014914c2954e1201d9da8fca56c19c0
2025-11-10 02:04:17 -08:00
Alan Zimmerman
6f2ee22321 buck2: Improve pop-up when the buck project is malformed
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-11-07 03:07:46 -08:00
Alan Zimmerman
4227771616 CLI ssr: Add --dump-config for .elp_lint.toml config snippet
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-11-05 02:27:35 -08:00
Victor Lanvin
9e99f9644e Update eqWAlizer submodule (#130)
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Pull Request resolved: https://github.com/whatsapp/erlang-language-platform/pull/130

Reviewed By: michalmuskala

Differential Revision: D85967546

Pulled By: VLanvin

fbshipit-source-id: 09aa6f51e939954bf1f4551553d7df3a1485e084
2025-11-04 04:25:25 -08:00
Roberto Aloi
557402920a Bump OSS VS Code extension to 0.44.0
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: In preparation for imminent OSS release.

Reviewed By: jcpetruzza

Differential Revision: D86121429

fbshipit-source-id: 5fee7c4c12c4504490f33c5e3331b97fc2e824db
2025-11-03 12:20:34 -08:00
Alan Zimmerman
0bd94b6cc1 BE: include diagnostic code in test fixtures
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-11-03 08:43:55 -08:00
Alan Zimmerman
5fd76eb0a3 Update elp_development.md to include declarative test fixtures
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
2025-11-03 08:43:55 -08:00
Rahul Jain
d52138b1fe Fix duplicate ignore annotations for multiple violations on same line
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
2025-11-03 05:05:47 -08:00
Michał Muskała
1cc3af7796 codemod_helper: save on some allocations
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-10-31 15:53:16 -07:00
Michał Muskała
8d1c120ad2 no_sleep: don't flag infinity timeout
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
2025-10-31 15:11:58 -07:00
Alan Zimmerman
ff680dfa39 Properly process changes to open configuration files
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-31 08:50:13 -07:00
Rahul Jain
90530e35c0 HIR: record parens for types
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
2025-10-31 07:34:33 -07:00
Alan Zimmerman
a6144459b8 CLI ssr: allow specifying macro and parens strategy
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
2025-10-31 04:08:27 -07:00
Victor Lanvin
0e9a4881e0 Better support for maps:map
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-30 17:19:01 -07:00
Victor Lanvin
f37f27cb74 Snapshot tests -- better maps:map/2
Summary: A snapshot test for more precise support of `maps:map/2`

Reviewed By: RobinMorisset

Differential Revision: D85677708

fbshipit-source-id: 1520e78419c51ae26604768fd78d787e06301a61
2025-10-30 17:19:01 -07:00
Victor Lanvin
52857fbf69 Fix error message heuristic on unions of maps
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
2025-10-30 11:37:37 -07:00
Victor Lanvin
37e84921d7 Useless error messages -- repro
Summary: Some error messages with unions of maps are useless. Add repros.

Reviewed By: TD5

Differential Revision: D85868726

fbshipit-source-id: c726054b934690f30bc3e5c190d55e9dd25e361f
2025-10-30 11:37:37 -07:00
Alan Zimmerman
88bb35f898 CLI ssr: allow specifying multiple SSR patterns
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
2025-10-30 10:43:41 -07:00
Alan Zimmerman
4ba56bc857 fix BodySourceMap entries for lowering Expr::Paren/Pat::Paren
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
2025-10-30 10:43:41 -07:00
Alan Zimmerman
77657ba9fb BE: tree print with ranges
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
2025-10-30 10:43:41 -07:00
Kleidi Bujari
bcde92c0a3 Add eglot to emacs docs
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Adds setup instructions for the built-in eglot LSP client.

Reviewed By: alanz

Differential Revision: D85780256

fbshipit-source-id: d977f4ed5da14f4cc8ebb4b71abdec327d5a3b2c
2025-10-30 02:30:25 -07:00
Victor Lanvin
217fa9af86 Fix occurrence typing for record/tuple unions
Some checks are pending
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
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
2025-10-29 17:29:04 -07:00
Victor Lanvin
67416c1b63 Occurrence typing fails with tuple/record mix -- repro
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
2025-10-29 17:29:04 -07:00
Michał Muskała
1c125dedc1 use jar version for unoptimised builds
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
2025-10-29 15:41:55 -07:00
Victor Lanvin
71e2caa687 Remove opaque type tests
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
2025-10-29 11:22:32 -07:00
Michał Muskała
2d8eb173fc Flatten remote unions too
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
2025-10-29 11:07:50 -07:00
Michał Muskała
4fe43a6aea tests for flattening remote unions
Summary: See next diff

Reviewed By: ilya-klyuchnikov

Differential Revision: D85669552

fbshipit-source-id: 124c06127e88c1bded404e0303a4a97f5f7eaa14
2025-10-29 11:07:50 -07:00
Alan Zimmerman
c3c68c0639 BE: Improve order of elp --help output
Summary:
As title.
Attempts to group the available options

Reviewed By: jcpetruzza

Differential Revision: D85767261

fbshipit-source-id: c5ae95b6fa45a1637666804c77c587b30dd4abc8
2025-10-29 10:05:44 -07:00
Alan Zimmerman
9d86159962 Improve the performance of elp ssr
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-29 08:52:23 -07:00
Alan Zimmerman
1c886bd9b7 buck: improve target classification for prelude vs third-party
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
2025-10-29 07:37:00 -07:00
Alan Zimmerman
aa9a4fc337 Add timing telemetry to elp lint too
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
2025-10-29 06:58:19 -07:00
Victor Lanvin
87391f55a0 Fix OTP 28 CI
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title (adding back auto-trimmed whitespace)

Reviewed By: michalmuskala

Differential Revision: D85690173

fbshipit-source-id: 39c3ac7494eb31f778d7bec41c0dd3ed35b06d31
2025-10-28 12:47:06 -07:00
Alan Zimmerman
7be8ee44a3 do not discover projects in buck-out
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
2025-10-28 10:33:30 -07:00
Alan Zimmerman
ed59eb502c buck: Applicable files for includes
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
2025-10-28 10:33:30 -07:00
Victor Lanvin
a269e11419 Fix CI for OTP 28
Summary: Snapshot `callbacks3_neg` is also OTP version dependent, fix it.

Reviewed By: michalmuskala

Differential Revision: D85675523

fbshipit-source-id: dfabda187190b669ef509c967fe3723de25d2890
2025-10-28 09:52:56 -07:00
Alan Zimmerman
fec1192e9d Add elp ssr command
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-28 07:48:10 -07:00
Alan Zimmerman
46477eeef5 Tweak telemetry manager test to not be flaky
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
2025-10-28 05:57:25 -07:00
Alan Zimmerman
dfa958a8ab 9/n: buck targets: report ELP restarts too in telemetry
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
93317ca5db 8/n: buck targets: Integrate into server mode
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
de65b598b8 7/n: buck targets: Add buck quick query to config options
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
1f3885feca 6/n: buck targets: dump target list for comparison
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
f99edec4ca 5/n: buck targets: propagate generated label
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
8e2d255651 4/n: buck targets: explicitly check for the prelude as a target, for origin
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
2036282055 3/n: buck targets; Improve CLI project-info output
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
3bde45d2b9 2/n: buck targets; initial struct for buck targets, and serde for it
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
2025-10-28 04:00:34 -07:00
Alan Zimmerman
05c8cb047c 1/n: buck targets; Add --buck-quick-start CLI argument
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
2025-10-28 04:00:34 -07:00
Victor Lanvin
efcfe7fab9 Update eqWAlizer submodule
Some checks are pending
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title.

Reviewed By: TD5

Differential Revision: D85614198

fbshipit-source-id: 63ddf9b997e3ff9a86c1406890efcb543bf6a3de
2025-10-27 16:59:10 -07:00
Victor Lanvin
4aa19d388c Add @OTPVersionDependent tag support for tests
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
2025-10-27 15:05:56 -07:00
Alan Zimmerman
719f5e2a46 CLI: log timing, meta-only
Summary: Meta internal, add telemetry for command line operation

Reviewed By: robertoaloi

Differential Revision: D84925105

fbshipit-source-id: c2788d05f92d1d4b44a1f95885563362dbf1217d
2025-10-27 10:56:25 -07:00
Alan Zimmerman
90281d7177 Specify SSR match as Ad-Hoc diagnostic
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
2025-10-27 10:16:56 -07:00
Roberto Aloi
b39d8f0486 Allow meta-only dynamic call patterns
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Reviewed By: alanz

Differential Revision: D85553363

fbshipit-source-id: 8349945a9f8a5732fb8a2ea2a930bc2c1a2ada18
2025-10-27 06:18:14 -07:00
Roberto Aloi
61af236b7f Have the create_dynamic_call_patterns function take patterns as an input
Summary: Take the patterns as a (mutable) input.

Reviewed By: alanz

Differential Revision: D85553374

fbshipit-source-id: a3185c3d0ffabc5af042fe88324cec6f79860462
2025-10-27 06:18:14 -07:00
Michał Muskała
41b9e1a21e Clean up unions with none()
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-10-24 08:50:08 -07:00
Alan Zimmerman
dd36ea17eb Fix incorrect project load on go to def in thrift file
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-24 04:33:31 -07:00
Victor Lanvin
ea25281dc5 Fix OTP 26/28 fixtures
Summary: As title. Copy from OTP 27.

Reviewed By: michalmuskala, alanz

Differential Revision: D85421561

fbshipit-source-id: e29aa0141f0c905a5a3aedfae26272bfd45d7819
2025-10-24 02:38:13 -07:00
Victor Lanvin
0b0dfa5469 Fix occurrence typing for is_function/2
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
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
2025-10-23 07:18:25 -07:00
Victor Lanvin
379bfd61ee Occurrence with is_function/2 -- snapshot tests
Summary: Tests showing `is_function/2` is not properly refined negatively

Reviewed By: michalmuskala

Differential Revision: D85336037

fbshipit-source-id: a8b5d841b8e55559d95de30581df621e329e1c77
2025-10-23 07:18:25 -07:00
Alan Zimmerman
e8bd4fdfc3 Fix failing test
Some checks are pending
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: We have a currently failing buck test, fix it.

Reviewed By: jcpetruzza

Differential Revision: D85331710

fbshipit-source-id: a4e50354ec3553643d4283c58f4a283c3320ff2c
2025-10-23 03:45:49 -07:00
Cj Longoria
0c723ff3f5 rustfmt update
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary:
X-link: https://github.com/meta-pytorch/monarch/pull/1646

update rustfmt to match 1.90.0 cut.

Fixed formatting issues by updating project's rustfmt.toml or updating code.

Reviewed By: dtolnay

Differential Revision: D84213462

fbshipit-source-id: 3df02141c6eec83e6193d9e32675f81d475a784c
2025-10-22 15:17:54 -07:00
Roberto Aloi
f2a95d73e0 Recommend release-thin profile for development
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Add tip for ELP developers, to avoid slow compilation times during develoment.

Reviewed By: jcpetruzza

Differential Revision: D85240198

fbshipit-source-id: 93db3cc8646ff3d954fb2fe7af33963755727274
2025-10-22 05:20:38 -07:00
Roberto Aloi
5fe7e93fd6 Update docs to take into account eqwalizer as a submodule
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
2025-10-22 03:52:56 -07:00
Alan Zimmerman
6d8c16078a check if a file is in a project when it opens
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
2025-10-22 03:35:15 -07:00
Alan Zimmerman
f417b8afd9 Tweak devmate rules to give a crate name to directory mapping
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
2025-10-22 03:03:59 -07:00
Roberto Aloi
fdbb4bf401 Allow filtering of OTP apps in indexing
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
2025-10-22 02:46:27 -07:00
Cj Longoria
86d61bd779 update rustfmt.toml for projects
Some checks are pending
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-21 15:05:55 -07:00
Roberto Aloi
d6f2636f01 Bump OSS VS Code extension version to 0.43.0
Some checks are pending
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: In preparation for OSS release.

Reviewed By: jcpetruzza

Differential Revision: D85158896

fbshipit-source-id: 71464b4a04b29955c97680b5d51445481f6a7387
2025-10-21 10:36:56 -07:00
Roberto Aloi
d811a4fa55 Add eqwalizer as submodule (#120)
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-21 03:20:03 -07:00
Roberto Aloi
621a3fdb8b Introduce no_persistent_term linter
Differential Revision: D85067388

fbshipit-source-id: bf52063b5eba5886e58638834cd5d625bd648f86
2025-10-21 02:39:44 -07:00
Roberto Aloi
ff9791ff69 Introduce helper to rename module from a call target
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
2025-10-21 02:39:44 -07:00
Roberto Aloi
6bef355a52 Introduce method to extract module name range from a call expression
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
2025-10-21 02:39:44 -07:00
Roberto Aloi
cfb0cc7d6d Skip -doc related tests in OTP 26
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-20 12:49:52 -07:00
Roberto Aloi
541262572f Allow overriding is_enabled property via config for trait linters
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
2025-10-20 12:47:58 -07:00
Victor Lanvin
dab22ffa03 Re-add logic to report diagnostics as Severity::Disabled
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-10-17 08:08:19 -07:00
Victor Lanvin
4bde32775f Fix CI for OTP 26,28
Summary: As title. Re-add automatically trimmed whitespaces

Reviewed By: ilya-klyuchnikov, alanz, jcpetruzza

Differential Revision: D84914077

fbshipit-source-id: 7bbe76edd33745342d95ee3bda3071c991e755c3
2025-10-17 05:45:31 -07:00
Victor Lanvin
c882b95968 Improve typing of Pat = Var = Expr
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-17 04:19:28 -07:00
Victor Lanvin
562d30ee1b Snapshots Pat = Var = Expr
Summary: Snapshot tests for exprs of the form `Pat = Var = Expr`.

Reviewed By: michalmuskala

Differential Revision: D84819136

fbshipit-source-id: a229e453ea48d2bb6b0b45ad430d362b765f58ee
2025-10-17 04:19:28 -07:00
Roberto Aloi
07fe4f7876 Define is_in_otp as a File method
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
2025-10-17 03:45:31 -07:00
Roberto Aloi
bca196c289 Do not report an undefined function warning if the function name is a variable
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
2025-10-17 02:30:18 -07:00
Roberto Aloi
7cf2eafc9b Do not mark deprecated functions diagnostics as experimental
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
2025-10-17 01:54:50 -07:00
Roberto Aloi
7172056397 Only cover the function name in the deprecation_function linter
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
2025-10-17 01:54:50 -07:00
Roberto Aloi
29877042a6 Do not report an undefined function warning if the module name is a variable
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
2025-10-17 01:54:50 -07:00
Roberto Aloi
80cbfe7f83 Enable documentation for types
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-10-15 02:28:45 -07:00
Alan Zimmerman
a89365692b BE:prioritise extract variable over extract function in UI
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-14 09:04:53 -07:00
Tristan Sloughter
5937388a4e fix: including based on an application path requires include_lib (#118)
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-13 06:11:06 -07:00
Roberto Aloi
0a1f82c441 Introduce simple_snapshot_output_contains helper, fix failing testcase
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
2025-10-13 05:02:35 -07:00
Roberto Aloi
55a4aa6d3d Fix OSS compilation warnings
Summary: Avoid unused variable warnings in OSS version.

Reviewed By: alanz

Differential Revision: D84486791

fbshipit-source-id: 5fde1b02a5a27ed892df220ded3a533302abe73b
2025-10-13 02:24:38 -07:00
Roberto Aloi
2b658e2600 Extend memory analysis to lint command
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
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
2025-10-10 09:12:00 -07:00
Roberto Aloi
747af175c2 Bump OSS VS Code extension for release (0.41.0 -> 0.42.0)
Summary: As per release instructions.

Reviewed By: alanz

Differential Revision: D84351530

fbshipit-source-id: 73fa5ce1922dd5e3baa930823fe75cc05c3711ad
2025-10-10 07:14:35 -07:00
Roberto Aloi
bba151232f Point Cargo.toml to tree-sitter-erlang crate
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
2025-10-10 05:08:28 -07:00
Roberto Aloi
5471c712e7 Include per-query memory info when using --report-system-stats
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
2025-10-10 04:33:06 -07:00
Alan Zimmerman
bde2492376 server: only register dynamic capabilities once
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
2025-10-10 02:39:02 -07:00
Roberto Aloi
e9c2cd40c9 Refactor extraction of exdoc links
Reviewed By: alanz

Differential Revision: D84252436

fbshipit-source-id: 42016266ed3ccdd42939a6da852407d84a07cc43
2025-10-10 01:53:26 -07:00
Roberto Aloi
aabdad4b1b Remove warnings due to ShipIt
Summary: Remove some compilation noise from unused variables.

Reviewed By: alanz

Differential Revision: D84250963

fbshipit-source-id: 429d2f149246522b0d7cd49bcbfee8fd800b43a2
2025-10-10 01:53:26 -07:00
Alan Zimmerman
4b44e20931 Allow extract variable inside a macro call
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-10-09 07:12:42 -07:00
Roberto Aloi
66612ad821 Remove obsolete Haskell E2E tests for the Erlang extension
Reviewed By: TheGeorge, alanz

Differential Revision: D84231176

fbshipit-source-id: e01b3c92c54064bd9c87bc836ba782e8bbf3dbb7
2025-10-09 02:20:45 -07:00
Alan Zimmerman
293a2aca0d Update loader progress on percent change only
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
2025-10-09 02:03:52 -07:00
Roberto Aloi
98bba7ab44 Fixed name of EQWALIZER_DIR variable
Reviewed By: alanz

Differential Revision: D84165374

fbshipit-source-id: e63c3ea96e548d78bdd284d329acbf5a7f556151
2025-10-09 01:22:43 -07:00
Victor Lanvin
312319b2da Remove old arc diagnostics logic
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-08 13:49:48 -07:00
Roberto Aloi
5e1154dbc1 Cleanup references
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Reviewed By: michalmuskala

Differential Revision: D84063145

fbshipit-source-id: a4b3537290347fa48dd38290b92cbecc2953e46e
2025-10-08 06:43:43 -07:00
Yongchao Lyu
47e775924a Fix some issues in WhatsApp ELP Glean
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
2025-10-08 06:04:47 -07:00
Roberto Aloi
1bbfa6c642 Improve linters documentation
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
2025-10-08 02:31:40 -07:00
Alan Zimmerman
742281abcf Bump tree-sitter-erlang version to 0.15
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title

Reviewed By: VLanvin

Differential Revision: D84054291

fbshipit-source-id: c3843ca1e86b73a4a6bdd2843aba943e2322be6a
2025-10-07 07:05:12 -07:00
Alan Zimmerman
31e798f369 send explicit telemetry to track the time from the server starting to operational
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
2025-10-07 01:12:55 -07:00
Roberto Aloi
8ddb16f879 Add testcase showcasing the issue with dynamic calls from macros
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: Add a testcase that showcases an existing bug in ELP.

Reviewed By: alanz

Differential Revision: D83968438

fbshipit-source-id: 6fdb5d98fb0634b9c5de16c8f35c0489cecb3915
2025-10-06 08:49:11 -07:00
Yongchao Lyu
3e25ccb49b Add a fact about the module info
Summary:
This diff aims to add a module fact to Glean, including -

- Name of the module
- Oncall, e.g., `-oncall("my_oncall").`
- Behavior, e.g., `-behaviour(my_behaviour).`
- Exported functions, e.g., `-export([start/2, stop/1]).`
- Moduledoc, e.g., `-moduledoc """ ... """`
- File path

Reviewed By: phlalx, robertoaloi

Differential Revision: D83240181

fbshipit-source-id: 7d9b2b32bf960c4983254b87a2e39a7685d0a65b
2025-10-06 07:20:24 -07:00
Roberto Aloi
84ee71d963 Include dynamic calls when finding references
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
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
2025-10-06 05:42:16 -07:00
Roberto Aloi
cb9f719878 Use a FxHashMap to store the patterns of interest for dynamic calls and a macro to reduce verbosity
Some checks failed
ELP CI / edb (push) Has been cancelled
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Has been cancelled
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Has been cancelled
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Has been cancelled
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
2025-10-03 10:58:55 -07:00
Roberto Aloi
64fb3fb3d3 Include the most common 'erpc' functions when searching for dynamic calls
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
2025-10-03 10:58:55 -07:00
Roberto Aloi
95dfeb4ea4 Include some of the 'erlang' functions when searching for dynamic calls
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
2025-10-03 10:58:55 -07:00
Roberto Aloi
3177337123 Find references for rpc dynamic calls
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
2025-10-03 10:58:55 -07:00
Roberto Aloi
bb49a578c6 Generalize lookup for dynamic calls
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
2025-10-03 10:58:55 -07:00
Alan Zimmerman
8805345e78 BE: Add oncalls metadata to elp_development LLMs rules
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Summary: As title.

Reviewed By: acw224

Differential Revision: D83758431

fbshipit-source-id: 63ee552d84e12829a1b9cef369ca9a1e4e9bee1d
2025-10-03 01:15:51 -07:00
Roberto Aloi
1eb41cc292 Add support for docPath
Some checks are pending
ELP CI / edb (push) Waiting to run
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, true, linux-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, linux, 26.2, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, true, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-13, macos-13-x64, x86_64-apple-darwin, true, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, macos, 26.2, macos-latest, macos-latest-arm, aarch64-apple-darwin, true, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (26, 26.2.5.13, windows, 26.2, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, true, win32-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, linux, 27.3, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, macos, 27.3, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (27, 27.3.4, windows, 27.3, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04, ubuntu-22.04-x64, x86_64-unknown-linux-gnu, false, linux-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, linux, 28, ubuntu-22.04-arm, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, false, linux-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-13, macos-13-x64, x86_64-apple-darwin, false, darwin-x64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, macos, 28, macos-latest, macos-latest-arm, aarch64-apple-darwin, false, darwin-arm64) (push) Blocked by required conditions
ELP CI / ci (28, 28.0.1, windows, 28, windows-2022, windows-2022-x64, x86_64-pc-windows-msvc, false, win32-x64) (push) Blocked by required conditions
Deploy Website to GitHub Pages / Deploy Website to GitHub Pages (push) Waiting to run
Reviewed By: alanz

Differential Revision: D82713207

fbshipit-source-id: 25373ae95968db30f1797d3e5aa96b7cb29e49d9
2025-10-02 06:03:07 -07:00
Roberto Aloi
57f6788022 Pin 2022 version for Windows
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
2025-09-30 07:31:36 -07:00
Roberto Aloi
dac0ab0eef Fix broken VSCodeErlangOpenDocs E2E test
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
2025-09-30 04:24:23 -07:00
Roberto Aloi
06fa2d01ea Explicitly include rustfmt during setup
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
2025-09-30 03:31:18 -07:00
Alan Zimmerman
7bb16e4986 Fix flaky tests using buck cell info
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
2025-09-29 10:00:24 -07:00
Roberto Aloi
06fc13bcaa Add build-oss script
Reviewed By: TheGeorge

Differential Revision: D83472522

fbshipit-source-id: 8bf19926e65d945e2f8b0024dbe2d0a411471f6f
2025-09-29 07:35:52 -07:00
Roberto Aloi
b4e24a8415 Avoid compilation warning
Reviewed By: alanz

Differential Revision: D83471730

fbshipit-source-id: ad475cbc5552c019439f43671d069c7250ffe9b9
2025-09-29 07:35:52 -07:00
Alan Zimmerman
ec97959534 3/n: Reload project if a buck2 generated input changes
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
2025-09-29 05:10:28 -07:00
Alan Zimmerman
f8c8cc5b41 2/n: Include watches for buck2 generated inputs
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
2025-09-29 05:10:28 -07:00
Alan Zimmerman
6afb92eaed 1/n: Add field to track generation source file inputs for buck2 generated targets
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
2025-09-29 05:10:28 -07:00
Alan Zimmerman
e27ffab6a5 Use buck2 cell info to resolve target directories
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
2025-09-25 07:52:58 -07:00
Roberto Aloi
14ae7af91e Add --report-system-stats to parse-elp command
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
2025-09-25 05:31:06 -07:00
Roberto Aloi
3bff3407e3 Convert wid_tuple linter to use trait
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
2025-09-24 09:42:42 -07:00
Roberto Aloi
853d37f3f4 Do not attempt to import MetaOnly resources in OSS build
Reviewed By: alanz

Differential Revision: D83049782

fbshipit-source-id: 6031e13458fb7b27d9691f8f114f8299e15e38cd
2025-09-24 01:26:00 -07:00
Alan Zimmerman
932323035a Add telemetry for textDocument/reference timing
Summary: Track the file, position and duration of processing a references request

Reviewed By: michalmuskala

Differential Revision: D83053371

fbshipit-source-id: 84261b4c8a9d13c89458c33a76aa8e13b54d4d71
2025-09-23 07:17:35 -07:00
Roberto Aloi
d9f02ee599 Split token identification and documentation extraction
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
2025-09-22 10:06:04 -07:00
Roberto Aloi
e6b0c60033 Track destination in telemetry for go-to-definition
Reviewed By: alanz

Differential Revision: D82815837

fbshipit-source-id: c78e5d85ba5660fd6017004e3e7ccc7c9056bf76
2025-09-22 10:06:04 -07:00
Roberto Aloi
03c28b446c Convert unused_macro linter to use new GenericLinter trait
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
2025-09-22 10:06:04 -07:00
Alan Zimmerman
63a28043af BE: Include a formatted start and end time stamp in telemetry
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
2025-09-22 06:58:20 -07:00
Alan Zimmerman
91b432fae9 BE: Provide explicit state change telemetry
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
2025-09-22 06:58:20 -07:00
Alan Zimmerman
7f67904387 BE: Use a vec for load telemetry
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
2025-09-22 06:24:09 -07:00
Roberto Aloi
f7e9bf9c4e Use local def_map in unused_macro linter
Summary: By using the local def_map, we avoid external file ids altogether.

Reviewed By: alanz

Differential Revision: D82636531

fbshipit-source-id: d0015a6002b14c237b2be5722deffa194543a5a1
2025-09-19 03:32:39 -07:00
Roberto Aloi
b32bd857fd Convert cross_node_eval linter to use trait
Summary: Convert the `cross_node_eval` linter to use the `FunctionCallLinter` trait.

Reviewed By: alanz

Differential Revision: D82633601

fbshipit-source-id: 131c5cfb09b5747813ee0e551bf20c4324b4d79b
2025-09-19 03:32:39 -07:00
Alan Zimmerman
ea45ecfdd1 BE: always check stderr in elp lint fix tests
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
2025-09-18 05:43:32 -07:00
Roberto Aloi
686d42f782 Add new option to mark Erlang Service warnings as errors
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
2025-09-17 07:49:31 -07:00
Alan Zimmerman
a849eaf3cd buck2: Remove BuckTargetOrigin::Prelude
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
2025-09-17 02:51:58 -07:00
Alan Zimmerman
cedda2811a buck2: do not provide deps_targets to elp.bxl
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
2025-09-17 02:51:58 -07:00
Roberto Aloi
ee888495e5 Only show hover link to docs if the function has docs
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
2025-09-17 01:38:03 -07:00
Roberto Aloi
1185d992f0 Specify exclusion list for undefined_function linter via config
Reviewed By: alanz

Differential Revision: D82543237

fbshipit-source-id: efd7b272aef7386f0615272922090bdb5306535a
2025-09-16 10:00:51 -07:00
Roberto Aloi
314dbd68ca Allow excluding function call matches via config
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
2025-09-16 10:00:51 -07:00
Roberto Aloi
8d82b307ed Allow function call linters to specify a list of matches to exclude from processing
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
2025-09-16 05:36:26 -07:00
Roberto Aloi
a42d118475 Convert undefined_function linter to use trait
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
2025-09-15 23:41:12 -07:00
Roberto Aloi
545452cc6d Provide an example of a poor translation from catch to try ... catch
Reviewed By: acw224

Differential Revision: D82297776

fbshipit-source-id: 02aa5da78182369656c3343cee63d8a7faa7d97a
2025-09-15 10:49:47 -07:00
Roberto Aloi
679ed1fb70 Return a &'static str for descriptions
Summary: Avoid some unnecessary allocations.

Reviewed By: TheGeorge

Differential Revision: D82434334

fbshipit-source-id: b67baf4fa52d8f641e172d0bc5cdd4d9d7560cb1
2025-09-15 07:57:01 -07:00
Roberto Aloi
39da159281 Avoid passing sema and file_id since they are already part of the context
Summary: As per title.

Reviewed By: jcpetruzza, TheGeorge

Differential Revision: D82433557

fbshipit-source-id: 03c299fdfc73ca3c46816b4eba659b4f5f3ededa
2025-09-15 07:57:01 -07:00
Roberto Aloi
2e30b64679 Rename is_match_valid into check_match
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
2025-09-15 07:57:01 -07:00
Roberto Aloi
0f39e522af Convert no_forgets_api linter to use the Linter trait
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
2025-09-15 07:57:01 -07:00
Alan Zimmerman
92a009df63 Make tasks.json work for internal and OSS usage
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
2025-09-12 02:39:39 -07:00
Alan Zimmerman
981d254628 Add tasks for common ELP dev actions
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
2025-09-11 08:45:47 -07:00
Roberto Aloi
2edd91934f Bump OSS VS Code extension for imminent release
Summary: Bump the extension to `0.41.0`.

Reviewed By: mapoulin

Differential Revision: D82220520

fbshipit-source-id: b33f40d92919bdedfeee5fb4c65875d0c6159623
2025-09-11 08:15:04 -07:00
Roberto Aloi
ff9c0b89c8 Add support for interactive debugging for rebar3 projects
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
2025-09-11 06:06:54 -07:00
Roberto Aloi
5ee1111075 Mitigate false positive undefined function for lager
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
2025-09-10 03:26:26 -07:00
Tom Davies
fb24c22520 Add linter to find and fix expressions which could be string literals
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
2025-09-08 08:11:33 -07:00
Tom Davies
a787db0b48 Partially fix escaping when pretty printing strings
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
2025-09-08 08:11:33 -07:00
Alan Zimmerman
1f0e95596d detect new project source files
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
2025-09-08 03:07:32 -07:00
Roberto Aloi
a826c8c47d Fix OSS compilation of glean.rs
Reviewed By: alanz

Differential Revision: D81907094

fbshipit-source-id: 68d4569ad46028f4adda199eeb73cd2035830aa9
2025-09-08 02:51:14 -07:00
Roberto Aloi
12ecfe5bb0 Fix location of meta-only comment
Summary: This was causing a GitHub CI failure: 4970891471

Reviewed By: alanz

Differential Revision: D81902529

fbshipit-source-id: a9007bc6cc61ab52e93217d85036b52ada507250
2025-09-08 01:53:36 -07:00
Brian Suh (WhatsApp)
ab12249dac add gatekeeper for new links
Reviewed By: robertoaloi

Differential Revision: D81690172

fbshipit-source-id: cb3986344d75fbdf77350d240c502ad145b7db9d
2025-09-05 09:56:07 -07:00
Brian Suh (WhatsApp)
b1f429ad86 add links to scuba
Summary: add scuba links to macro doc

Reviewed By: robertoaloi

Differential Revision: D81545729

fbshipit-source-id: 8b87e01ebfbc715de33cab0a60f2f93c41244915
2025-09-05 09:56:07 -07:00
Brian Suh (WhatsApp)
d55260aaa4 add links to wam browser
Summary: add wam browser link into the record doc

Reviewed By: robertoaloi

Differential Revision: D81522678

fbshipit-source-id: 115f64f117b46eabe7131a3936e673ad6c32a30e
2025-09-05 09:56:07 -07:00
Brian Suh (WhatsApp)
1897fe15bf add links to logview
Summary: add logview link into the macro doc

Reviewed By: robertoaloi

Differential Revision: D81513245

fbshipit-source-id: 37768bd67e9f6cdca774343c849a51a33dee1ede
2025-09-05 09:56:07 -07:00
Roberto Aloi
6faa9f865a Ignore formatting to avoid fb_only/oss_only inconsistency
Summary:
To avoid a GitHub CI failure as in:

4957434008

Reviewed By: alanz

Differential Revision: D81774626

fbshipit-source-id: a452985ed3d1f2022b627130f75a481e0521db59
2025-09-05 05:20:33 -07:00
Roberto Aloi
3caae9249c Refactor definition of linters
Summary: Clearer definition of linters.

Reviewed By: jcpetruzza, TD5

Differential Revision: D81589873

fbshipit-source-id: b8ee681fce7dd834759eedde69e1b893f03c0052
2025-09-04 01:04:33 -07:00
Roberto Aloi
26c8c3058a Convert atoms exhaustion linter to use the FunctionCallLinter trait
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
2025-09-03 10:07:47 -07:00
Roberto Aloi
2dc5420836 Support custom fixes in FunctionCallLinter trait
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
2025-09-03 10:07:47 -07:00
Roberto Aloi
2d6afacd92 Allowing specifying a custom cli_severity/override
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
2025-09-03 10:07:47 -07:00
Roberto Aloi
43614330fa Avoid duplication in treating function / ssr linters
Summary: Merge the processing of FunctionCallLinters / SSrLinters into a single function, avoid code duplication.

Reviewed By: TD5

Differential Revision: D81474340

fbshipit-source-id: 87df4ed02248bf16c8fe0bfc537fb9b05cdd44a3
2025-09-03 10:07:47 -07:00
Tom Davies
be360da10e Fix wording in W0030 diagnostic docs (dedicated maps:put/3 syntax)
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
2025-09-03 04:10:11 -07:00
Roberto Aloi
2d8c4a03cf Avoid duplication to extract linter conditions
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
2025-09-02 04:45:26 -07:00
Roberto Aloi
6dbb64aa35 Be able to override a linter's experimental property via config
Summary: Be able to override the `experimental` property of a linter via config.

Reviewed By: TD5

Differential Revision: D81450739

fbshipit-source-id: c18b449249d48fc089709d17a5d6b1c1560db6f3
2025-09-02 04:45:26 -07:00
Roberto Aloi
a92b4eea99 Be able to override a linter's include_generated property via config
Summary: Similarly to the other properties.

Reviewed By: TD5

Differential Revision: D81450512

fbshipit-source-id: 4002024a72d5e6af87583a2502d7f2edf861aaf2
2025-09-02 04:45:26 -07:00
Roberto Aloi
04ec06feb0 Be able to override a linter's include_test property via config
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
2025-09-02 04:45:26 -07:00
Roberto Aloi
1e496247fb Be able to override diagnostic severities via config
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

View file

@ -1,8 +1,8 @@
[alias]
xtask = "run --package xtask --"
# @fb-only
# @fb-only
# @fb-only: [build]
# @fb-only: target-dir = "../../../buck-out/elp"
[profile.release]
codegen-units = 1

View file

@ -24,4 +24,4 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build website
run: yarn build
run: yarn build-oss

View file

@ -30,7 +30,7 @@ jobs:
strategy:
fail-fast: false
matrix:
platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-13-x64, macos-latest-arm, windows-latest-x64]
platform-arch: [ubuntu-22.04-x64, ubuntu-22.04-arm, macos-15-x64, macos-latest-arm, windows-2022-x64]
otp-version: [26.2, 27.3, 28.0]
include:
- otp-version: 26.2
@ -55,8 +55,8 @@ jobs:
os: linux
target: aarch64-unknown-linux-gnu
vscode-target: linux-arm64
- platform-arch: macos-13-x64
platform: macos-13
- platform-arch: macos-15-x64
platform: macos-15-intel
os: macos
target: x86_64-apple-darwin
vscode-target: darwin-x64
@ -65,8 +65,8 @@ jobs:
os: macos
target: aarch64-apple-darwin
vscode-target: darwin-arm64
- platform-arch: windows-latest-x64
platform: windows-latest
- platform-arch: windows-2022-x64
platform: windows-2022
os: windows
target: x86_64-pc-windows-msvc
vscode-target: win32-x64
@ -75,12 +75,8 @@ jobs:
steps:
- name: Checkout erlang-language-platform
uses: "actions/checkout@v3"
- name: Checkout eqwalizer
uses: "actions/checkout@v3"
with:
repository: WhatsApp/eqwalizer
path: eqwalizer
ref: main
submodules: true
- name: Set up GraalVM
uses: graalvm/setup-graalvm@v1
with:
@ -95,11 +91,14 @@ jobs:
uses: dtolnay/rust-toolchain@stable
with:
target: ${{ matrix.target }}
components: rustfmt
- name: Set up cross-compiler
if: matrix.platform-arch == 'ubuntu-22.04-arm'
run: |
sudo apt-get update
sudo apt-get install -y crossbuild-essential-arm64
- name: Install Buck2
uses: dtolnay/install-buck2@latest
- id: setup-erlang
uses: ./.github/actions/setup-erlang
with:
@ -138,7 +137,7 @@ jobs:
- name: Test elp
# Do not run the tests in case of cross-compilation or on Windows
if: matrix.platform-arch != 'macos-latest-arm' && matrix.os != 'windows'
run: 'cargo test --no-default-features --workspace --target ${{ matrix.target }}'
run: 'cargo test --workspace --target ${{ matrix.target }}'
- name: Build elp (No Windows)
if: matrix.os != 'windows'
run: 'cargo build --release --target ${{ matrix.target }} --config target.aarch64-unknown-linux-gnu.linker=\"aarch64-linux-gnu-gcc\"'
@ -203,6 +202,8 @@ jobs:
node-version: 20
- name: Install VSCE
run: npm install -g vsce
- name: Install OVSX
run: npm install -g ovsx
- name: Prepare VS Code Extension to host binaries (No Windows)
if: matrix.os != 'windows'
run: mkdir -p editors/code/bin
@ -288,3 +289,7 @@ jobs:
working-directory: editors/code
if: ${{ github.event_name == 'release' && matrix.vscode-publish && matrix.os != 'windows' }}
run: vsce publish -p ${{ secrets.VSCE_PAT }} --packagePath erlang-language-platform.vsix
- name: Publish extension to OpenVSX marketplace
working-directory: editors/code
if: ${{ github.event_name == 'release' && matrix.vscode-publish && matrix.os != 'windows' }}
run: ovsx publish -p ${{ secrets.OVSX_PAT }} --packagePath erlang-language-platform.vsix

View file

@ -24,7 +24,7 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build website
run: yarn build
run: yarn build-oss
# Popular action to deploy to GitHub Pages:
# Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "eqwalizer"]
path = eqwalizer
url = https://github.com/WhatsApp/eqwalizer

View file

@ -1,13 +1,36 @@
---
llms-gk: 'devmate_elp_development_md'
apply_to_regex: '^(.*\.rs|.*\.md)$'
oncalls: ['vscode_erlang']
---
# ELP Development Rules for LLMs
# ELP Development Rules for LLMs (OSS)
## Project Overview
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
the issue
- Good: `UnusedFunctionArg`, `MissingCompileWarnMissingSpec`
- Bad: `Error1`, `BadCode`
2. **Code Assignment**: Follow the established numbering scheme
- `W0000-W9999`: Native ELP diagnostics, visible in the OSS version
- `WA000-WA999`: WhatsApp-specific warnings, only visible in Meta builds
- Use the next available number in the appropriate range
- Never change the number of an existing diagnostic code
- Never change the label of an existing diagnostic code
@ -35,7 +58,8 @@ When adding new diagnostic codes to `DiagnosticCode` enum:
4. **Documentation**: Add comments explaining complex diagnostic codes
5. **Documentation File**: Create a corresponding documentation file in the website
5. **Documentation File**: Create a corresponding documentation file in the
website
- Location: `website/docs/erlang-error-index/{namespace}/{code}.md`
- Example: `W0051``website/docs/erlang-error-index/w/W0051.md`
- Include frontmatter with `sidebar_position` matching the code number
@ -49,16 +73,19 @@ When adding new diagnostic codes to `DiagnosticCode` enum:
### Creating DiagnosticDescriptor
Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines when and how the diagnostic runs:
Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines
when and how the diagnostic runs:
1. **Static Descriptor Declaration**: Create a public static descriptor in your diagnostic module
1. **Static Descriptor Declaration**: Create a public static descriptor in your
diagnostic module
- Use `pub(crate) static DESCRIPTOR: DiagnosticDescriptor` pattern
- Define `DiagnosticConditions` with appropriate flags
- Provide a checker function that implements the diagnostic logic
2. **Diagnostic Conditions**: Configure when the diagnostic should run
- `experimental`: Mark as true for experimental/unstable diagnostics
- `include_generated`: Set to false if diagnostic shouldn't run on generated code
- `include_generated`: Set to false if diagnostic shouldn't run on generated
code
- `include_tests`: Set to false if diagnostic shouldn't run on test files
- `default_disabled`: Set to true if diagnostic requires explicit enabling
@ -67,7 +94,8 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w
- Push diagnostics to the `diags` vector using `Diagnostic::new()`
- Use helper functions to keep the checker clean and focused
4. **Registration**: Add the descriptor to `diagnostics_descriptors()` function in `diagnostics.rs`
4. **Registration**: Add the descriptor to `diagnostics_descriptors()` function
in `diagnostics.rs`
- Include your module's `DESCRIPTOR` in the returned vector
5. **Module Structure**: Follow the established pattern
@ -76,12 +104,6 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w
- Include comprehensive tests with `#[cfg(test)]`
- Use SSR patterns when appropriate for complex matching
### Meta-Only vs OSS Code
- Use `@fb-only` and `@oss-only` comments to mark platform-specific code
- Meta-only diagnostics should use `MetaOnlyDiagnosticCode` wrapper
- Ensure OSS builds work by providing fallbacks for Meta-only features
## Rust Code Style
### Error Handling
@ -116,12 +138,96 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w
- Group related tests in the same module
- Use descriptive test names that explain the scenario
### Declarative Test Fixtures
ELP uses a declarative test fixture system that allows you to write tests with
inline annotations and markers directly in test strings. This system is defined
in `crates/project_model/src/test_fixture.rs`.
#### Key Features
1. **File Organization**: Use `//- /path/to/file.erl` to define multiple files
in a single test
2. **Metadata Markers**: Specify app names, include paths, OTP apps, etc. using
metadata after the path
3. **Annotations**: Mark expected diagnostics or ranges using `%% ^^^` syntax
4. **Cursors and Ranges**: Use `~` markers to indicate positions or ranges in
test code
#### Annotation Syntax
Annotations allow you to mark expected diagnostics, types, or other information
directly in test code:
- **Basic annotation**: `%% ^^^ some text` - Points to the range above matching
the caret length
- **Top-of-file marker**: `%% <<< text` (at file start) - Creates annotation at
position 0..0
- **File-wide annotation**: `%% ^^^file text` - Annotation spans the entire file
contents
- **Left-margin annotation**: `%%<^^^ text` - Annotation starts at `%%` position
instead of first `^`
- **Multiline annotations**: Use continuation lines with `%% | next line`
- Continuation lines are particularly useful for diagnostics with related information:
```erlang
foo() -> syntax error oops.
%% ^^^^^ error: P1711: syntax error before: error
%% | Related info: 0:45-50 function foo/0 undefined
```
#### Example Test Fixture
```rust
let fixture = r#"
//- /src/main.erl
-module(main).
foo( -> ok. %%
%% ^ error: W0004: Missing ')'~
"#;
```
### Test Data
- Create minimal test cases that focus on specific functionality
- Use realistic Erlang code examples in tests
- Test both positive and negative cases
### Running Tests for Specific Crates
When running tests for a specific crate, you need to specify the crate name, not
the directory name. The mapping is:
| Crate Name | Directory Name |
| -------------------- | ----------------------- |
| `elp` | `crates/elp` |
| `elp_base_db` | `crates/base_db` |
| `elp_eqwalizer` | `crates/eqwalizer` |
| `elp_erlang_service` | `crates/erlang_service` |
| `elp_ide` | `crates/ide` |
| `elp_ide_assists` | `crates/ide_assists` |
| `elp_ide_completion` | `crates/ide_completion` |
| `elp_ide_db` | `crates/ide_db` |
| `elp_ide_ssr` | `crates/ide_ssr` |
| `elp_log` | `crates/elp_log` |
| `elp_project_model` | `crates/project_model` |
| `elp_syntax` | `crates/syntax` |
| `elp_text_edit` | `crates/text_edit` |
| `elp_types_db` | `crates/types_db` |
| `hir` | `crates/hir` |
Example: To run tests for the `elp_ide` crate:
```bash
cargo test -p elp_ide
```
Or to run tests in a specific directory:
```bash
cargo test --manifest-path crates/ide/Cargo.toml
```
### Existing tests
- Do not change existing tests without asking
@ -209,14 +315,8 @@ Every diagnostic must have a corresponding `DiagnosticDescriptor` that defines w
- Collect multiple errors rather than failing on the first one
- Provide partial results when full analysis isn't possible
### Tools
- ELP uses a cargo workspace.
- Inside Meta, use `./meta/cargo.sh` instead of `cargo`
- Inside Meta, use `./meta/clippy.sh` to run clippy
- Use `arc lint --apply-patches` for formatting.
### Process
- Always run tests before finishing.
- Always run `./meta/cargo.sh clippy --tests` before submitting a diff
- Always run tests before finishing
- Always run `cargo clippy --tests` before submitting PRs
- Use `cargo fmt` for code formatting

95
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,95 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "ELP: build (debug)",
"type": "shell",
// @fb-only: "command": "./meta/cargo.sh build",
"command": "cargo build", // @oss-only
"group": {
"kind": "build",
"is_default": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "ELP: build (release)",
"type": "shell",
// @fb-only: "command": "./meta/cargo.sh build --release",
"command": "cargo build --release", // @oss-only
"group": {
"kind": "build",
"is_default": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "ELP: build (release-thin)",
"type": "shell",
// @fb-only: "command": "./meta/cargo.sh build --profile release-thin --bins",
"command": "cargo build --profile release-thin --bins", // @oss-only
"group": {
"kind": "build",
"is_default": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "ELP: run clippy on workspace",
"type": "shell",
// @fb-only: "command": "./meta/clippy.sh --workspace --tests",
"command": "cargo clippy --workspace --tests", // @oss-only
"group": {
"kind": "build",
"is_default": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "ELP: run clippy on workspace, apply fixes",
"type": "shell",
// @fb-only: "command": "./meta/clippy.sh --workspace --tests --fix",
"command": "cargo clippy --workspace --tests --fix", // @oss-only
"group": {
"kind": "build",
"is_default": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "ELP: run tests on workspace",
"type": "shell",
// @fb-only: "command": "./meta/cargo.sh test --workspace",
"command": "cargo test --workspace", // @oss-only
"group": {
"kind": "build",
"is_default": true,
},
"presentation": {
"reveal": "always",
"panel": "new"
}
},
]
}

23
Cargo.lock generated
View file

@ -446,10 +446,10 @@ dependencies = [
"crossbeam-channel",
"elp_eqwalizer",
"elp_ide",
"elp_ide_db",
"elp_log",
"elp_project_model",
"elp_syntax",
"elp_text_edit",
"env_logger",
"expect-test",
"fs_extra",
@ -572,7 +572,6 @@ dependencies = [
"elp_ide_ssr",
"elp_project_model",
"elp_syntax",
"elp_text_edit",
"elp_types_db",
"env_logger",
"expect-test",
@ -604,7 +603,6 @@ dependencies = [
"cov-mark",
"elp_ide_db",
"elp_syntax",
"elp_text_edit",
"expect-test",
"fxhash",
"hir",
@ -637,6 +635,7 @@ name = "elp_ide_db"
version = "1.1.0"
dependencies = [
"anyhow",
"cov-mark",
"eetf",
"either",
"elp_base_db",
@ -644,12 +643,12 @@ dependencies = [
"elp_erlang_service",
"elp_project_model",
"elp_syntax",
"elp_text_edit",
"elp_types_db",
"expect-test",
"fxhash",
"hir",
"indexmap 2.9.0",
"itertools 0.10.5",
"lazy_static",
"log",
"memchr",
@ -664,6 +663,7 @@ dependencies = [
"strum",
"strum_macros",
"tempfile",
"text-size",
"toml",
"tracing",
]
@ -734,10 +734,8 @@ dependencies = [
name = "elp_syntax"
version = "1.1.0"
dependencies = [
"cov-mark",
"eetf",
"elp_ide_db",
"elp_text_edit",
"expect-test",
"fxhash",
"indexmap 2.9.0",
@ -757,14 +755,6 @@ dependencies = [
"tree-sitter-erlang",
]
[[package]]
name = "elp_text_edit"
version = "1.1.0"
dependencies = [
"itertools 0.10.5",
"text-size",
]
[[package]]
name = "elp_types_db"
version = "1.1.0"
@ -2534,10 +2524,11 @@ dependencies = [
[[package]]
name = "tree-sitter-erlang"
version = "0.14.0"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2091cce4eda19c03d77928c608ac6617445a6a25691dde1e93ac0102467a6be"
dependencies = [
"cc",
"tree-sitter",
"tree-sitter-language",
]

View file

@ -30,13 +30,9 @@ elp_ide_ssr = { path = "./crates/ide_ssr" }
elp_log = { path = "./crates/elp_log" }
elp_project_model = { path = "./crates/project_model" }
elp_syntax = { path = "./crates/syntax" }
elp_text_edit = { path = "./crates/text_edit" }
elp_types_db = { path = "./crates/types_db" }
hir = { path = "./crates/hir" }
# Forks
erl_ast = { path = "./crates/erl_ast" }
# External crates
trie-rs = "0.4.2"
always-assert = "0.1.3"
@ -112,8 +108,9 @@ threadpool = "1.8.1"
timeout-readwrite = "0.3.3"
toml = "0.5"
tree-sitter = "0.23.2"
# @fb-only
tree-sitter-erlang = "0.14.0" # @oss-only
# When developing the grammar, you may want to point to a local version
# tree-sitter-erlang = { path = "./tree-sitter-erlang" }
tree-sitter-erlang = "0.15.0"
url = "2.5.4"
ustr = { version = "1.1.0", features = ["serde"] }
vfs = { git = "https://github.com/rust-lang/rust-analyzer", rev = "2025-03-04" }

View file

@ -1,60 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is dual-licensed under either the MIT license found in the
* LICENSE-MIT file in the root directory of this source tree or the Apache
* License, Version 2.0 found in the LICENSE-APACHE file in the root directory
* of this source tree. You may select, at your option, one of the
* above-listed licenses.
*/
use std::thread;
use std::time;
use criterion::BenchmarkId;
use criterion::Criterion;
use criterion::criterion_group;
use criterion::criterion_main;
fn fibonacci_slow(n: u64) -> u64 {
match n {
0 => 1,
1 => 1,
n => fibonacci_slow(n - 1) + fibonacci_slow(n - 2),
}
}
fn fibonacci_fast(n: u64) -> u64 {
let mut a = 0;
let mut b = 1;
let millis = time::Duration::from_millis(12);
thread::sleep(millis);
match n {
0 => b,
_ => {
for _ in 0..n {
let c = a + b;
a = b;
b = c;
}
b
}
}
}
fn bench_fibs(c: &mut Criterion) {
let mut group = c.benchmark_group("Fibonacci");
for i in [20u64, 21u64].iter() {
group.bench_with_input(BenchmarkId::new("Recursive", i), i, |b, i| {
b.iter(|| fibonacci_slow(*i))
});
group.bench_with_input(BenchmarkId::new("Iterative", i), i, |b, i| {
b.iter(|| fibonacci_fast(*i))
});
}
group.finish();
}
criterion_group!(benches, bench_fibs);
criterion_main!(benches);

View file

@ -1,16 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is dual-licensed under either the MIT license found in the
* LICENSE-MIT file in the root directory of this source tree or the Apache
* License, Version 2.0 found in the LICENSE-APACHE file in the root directory
* of this source tree. You may select, at your option, one of the
* above-listed licenses.
*/
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
println!("ARGS: {:?}", args);
}

View file

@ -87,6 +87,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
let (fixture, change) = ChangeFixture::parse(fixture_str);
let mut db = Self::default();
change.apply(&mut db, &|path| fixture.resolve_file_id(path));
fixture.validate(&db);
(db, fixture)
}
}
@ -101,6 +102,7 @@ pub struct ChangeFixture {
pub diagnostics_enabled: DiagnosticsEnabled,
pub tags: FxHashMap<FileId, Vec<(TextRange, Option<String>)>>,
pub annotations: FxHashMap<FileId, Vec<(TextRange, String)>>,
pub expect_parse_errors: bool,
}
struct Builder {
@ -172,6 +174,7 @@ impl ChangeFixture {
let FixtureWithProjectMeta {
fixture,
mut diagnostics_enabled,
expect_parse_errors,
} = fixture_with_meta.clone();
let builder = Builder::new(diagnostics_enabled.clone());
@ -295,7 +298,7 @@ impl ChangeFixture {
ProjectManifest::discover(&AbsPathBuf::assert(json_config_file.into())).unwrap();
let loaded_project = Project::load(
&manifest,
elp_config.eqwalizer,
&elp_config,
&BuckQueryConfig::BuildGeneratedCode,
&|_| {},
)
@ -344,6 +347,7 @@ impl ChangeFixture {
diagnostics_enabled,
tags,
annotations,
expect_parse_errors,
},
change,
project,
@ -405,6 +409,64 @@ impl ChangeFixture {
.get(&VfsPath::from(path.clone()))
.cloned()
}
/// Validate all files in the fixture for syntax errors.
/// Panics with context if any syntax errors are found.
/// Skips validation if `expect_parse_errors` is set to true.
#[track_caller]
pub fn validate<DB: SourceDatabaseExt>(&self, db: &DB) {
if self.expect_parse_errors {
return;
}
let mut errors_found = Vec::new();
for file_id in &self.files {
let parse = db.parse(*file_id);
let errors = parse.errors();
if !errors.is_empty() {
let path = self
.files_by_path
.iter()
.find_map(|(vfs_path, id)| {
if id == file_id {
Some(
vfs_path
.as_path()
.map(|p| p.to_string())
.unwrap_or_else(|| format!("{:?}", vfs_path)),
)
} else {
None
}
})
.unwrap_or_else(|| format!("FileId({:?})", file_id));
let file_text = SourceDatabaseExt::file_text(db, *file_id);
let tree = parse.tree();
errors_found.push((path, file_text.to_string(), errors.to_vec(), tree));
}
}
if !errors_found.is_empty() {
let mut message =
String::from("Fixture validation failed: syntax errors found in test fixture\n\n");
for (path, text, errors, tree) in errors_found {
message.push_str(&format!("File: {}\n", path));
message.push_str(&format!("Errors: {:?}\n", errors));
message.push_str(&format!("Content:\n{}\n", text));
message.push_str(&format!("Parse Tree:\n{:#?}\n", tree));
message.push_str("---\n");
}
message.push_str(
"If this is expected, add `//- expect_parse_errors` to the start of the fixture\n",
);
panic!("{}", message);
}
}
}
fn inc_file_id(file_id: &mut FileId) {
@ -484,8 +546,8 @@ bar() -> ?FOO.
app_map: {
SourceRootId(
0,
): (
Some(
): AppMapData {
app_data: Some(
AppData {
project_id: ProjectId(
0,
@ -519,12 +581,13 @@ bar() -> ?FOO.
is_test_target: None,
},
),
None,
),
applicable_files: None,
gen_src_files: None,
},
SourceRootId(
2,
): (
Some(
): AppMapData {
app_data: Some(
AppData {
project_id: ProjectId(
1,
@ -569,12 +632,13 @@ bar() -> ?FOO.
is_test_target: None,
},
),
None,
),
applicable_files: None,
gen_src_files: None,
},
SourceRootId(
1,
): (
Some(
): AppMapData {
app_data: Some(
AppData {
project_id: ProjectId(
0,
@ -608,14 +672,16 @@ bar() -> ?FOO.
is_test_target: None,
},
),
None,
),
applicable_files: None,
gen_src_files: None,
},
SourceRootId(
3,
): (
None,
None,
),
): AppMapData {
app_data: None,
applicable_files: None,
gen_src_files: None,
},
},
project_map: {
ProjectId(
@ -741,8 +807,8 @@ foo() -> ?BAR.
app_map: {
SourceRootId(
0,
): (
Some(
): AppMapData {
app_data: Some(
AppData {
project_id: ProjectId(
0,
@ -792,14 +858,16 @@ foo() -> ?BAR.
is_test_target: None,
},
),
None,
),
applicable_files: None,
gen_src_files: None,
},
SourceRootId(
1,
): (
None,
None,
),
): AppMapData {
app_data: None,
applicable_files: None,
gen_src_files: None,
},
},
project_map: {
ProjectId(

View file

@ -15,13 +15,13 @@ use std::sync::Arc;
use elp_project_model::AppName;
use elp_project_model::AppType;
use elp_project_model::ApplicableFiles;
use elp_project_model::EqwalizerConfig;
use elp_project_model::Project;
use elp_project_model::ProjectAppData;
use elp_project_model::buck::IncludeMapping;
use elp_project_model::buck::TargetFullName;
use fxhash::FxHashMap;
use fxhash::FxHashSet;
use paths::RelPath;
use paths::Utf8Path;
use vfs::AbsPathBuf;
@ -179,11 +179,23 @@ impl AppData {
/// Note that `AppStructure` is build-system agnostic
#[derive(Debug, Clone, Default /* Serialize, Deserialize */)]
pub struct AppStructure {
pub(crate) app_map: FxHashMap<SourceRootId, (Option<AppData>, Option<ApplicableFiles>)>,
pub(crate) app_map: FxHashMap<SourceRootId, AppMapData>,
pub(crate) project_map: FxHashMap<ProjectId, ProjectData>,
pub(crate) catch_all_source_root: SourceRootId,
}
#[derive(Debug, Clone, Default)]
pub struct AppMapData {
app_data: Option<AppData>, // TODO: should this be Arc?
applicable_files: Option<FxHashSet<AbsPathBuf>>,
gen_src_files: Option<FxHashSet<AbsPathBuf>>,
}
pub struct ApplyOutput {
pub unresolved_app_id_paths: FxHashMap<AbsPathBuf, AppDataId>,
pub gen_src_inputs: FxHashMap<AbsPathBuf, AppDataId>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
pub struct AppDataId(pub u32);
@ -192,13 +204,20 @@ impl AppStructure {
&mut self,
source_root_id: SourceRootId,
app_data: Option<AppData>,
applicable_files: Option<ApplicableFiles>,
applicable_files: Option<FxHashSet<AbsPathBuf>>,
gen_src_files: Option<FxHashSet<AbsPathBuf>>,
) {
let prev = self
.app_map
.insert(source_root_id, (app_data, applicable_files));
let prev = self.app_map.insert(
source_root_id,
AppMapData {
app_data,
applicable_files,
gen_src_files,
},
);
assert!(prev.is_none());
}
pub fn add_project_data(&mut self, project_id: ProjectId, project_data: ProjectData) {
let prev = self.project_map.insert(project_id, project_data);
assert!(prev.is_none());
@ -209,15 +228,16 @@ impl AppStructure {
self,
db: &mut dyn SourceDatabaseExt,
resolve_file_id: &impl Fn(&AbsPathBuf) -> Option<FileId>,
) -> FxHashMap<AbsPathBuf, AppDataId> {
) -> ApplyOutput {
let mut app_index = AppDataIndex::default();
let mut app_data_id = AppDataId(0);
let mut unresolved_paths = FxHashMap::default();
for (source_root_id, (data, applicable_files)) in self.app_map {
let arc_data = data.map(Arc::new);
let mut gen_src_inputs = FxHashMap::default();
for (source_root_id, app_map_data) in self.app_map {
let arc_data = app_map_data.app_data.map(Arc::new);
db.set_app_data_by_id(app_data_id, arc_data);
db.set_app_data_id(source_root_id, app_data_id);
if let Some(files) = applicable_files {
if let Some(files) = app_map_data.applicable_files {
files.iter().for_each(|path| {
if let Some(file_id) = resolve_file_id(path) {
app_index.map.insert(file_id, app_data_id);
@ -226,6 +246,11 @@ impl AppStructure {
}
})
}
if let Some(files) = app_map_data.gen_src_files {
for file in files {
gen_src_inputs.insert(file.clone(), app_data_id);
}
}
app_data_id = AppDataId(app_data_id.0 + 1);
}
for (project_id, project_data) in self.project_map {
@ -234,7 +259,10 @@ impl AppStructure {
db.set_app_index(Arc::new(app_index));
db.set_catch_all_source_root(self.catch_all_source_root);
unresolved_paths
ApplyOutput {
unresolved_app_id_paths: unresolved_paths,
gen_src_inputs,
}
}
}
@ -380,7 +408,12 @@ impl<'a> ProjectApps<'a> {
ebin_path: app.ebin.clone(),
is_test_target: app.is_test_target,
};
app_structure.add_app_data(root_id, Some(input_data), app.applicable_files.clone());
app_structure.add_app_data(
root_id,
Some(input_data),
app.applicable_files.clone(),
app.gen_src_files.clone(),
);
}
let mut app_roots = project_root_map.remove(&project_id).unwrap_or_default();
@ -403,7 +436,7 @@ impl<'a> ProjectApps<'a> {
// Final SourceRoot for out-of-project files
log::info!("Final source root: {:?}", SourceRootId(app_idx));
app_structure.add_app_data(SourceRootId(app_idx), None, None);
app_structure.add_app_data(SourceRootId(app_idx), None, None, None);
app_structure.catch_all_source_root = SourceRootId(app_idx);
app_structure
}

View file

@ -32,7 +32,7 @@ mod module_index;
// Public API
pub mod fixture;
// @fb-only
// @fb-only: mod meta_only;
pub mod test_utils;
pub use change::Change;
pub use elp_project_model::AppType;
@ -476,7 +476,7 @@ static ref IGNORED_SOURCES: Vec<Regex> = {
let regexes: Vec<Vec<Regex>> = vec![
vec![Regex::new(r"^.*_SUITE_data/.+$").unwrap()],
//ignore sources goes here
// @fb-only
// @fb-only: meta_only::ignored_sources_regexes()
];
regexes.into_iter().flatten().collect::<Vec<Regex>>()
};

View file

@ -18,10 +18,10 @@ workspace = true
[dependencies]
elp_eqwalizer.workspace = true
elp_ide.workspace = true
elp_ide_db.workspace = true
elp_log.workspace = true
elp_project_model.workspace = true
elp_syntax.workspace = true
elp_text_edit.workspace = true
hir.workspace = true
always-assert.workspace = true

View file

@ -8,13 +8,14 @@
* above-listed licenses.
*/
/// 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
use std::path::Path;
use serde::Serialize;
#[derive(Debug, Serialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Diagnostic {
// 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 {
}
impl Diagnostic {
#[allow(clippy::too_many_arguments)]
pub fn new(
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
@ -61,6 +65,7 @@ impl Diagnostic {
original,
replacement: None,
description: Some(description),
doc_path,
}
}
}

View file

@ -11,14 +11,20 @@
use std::cmp::Ordering;
use std::env;
use std::fs;
use std::io::IsTerminal;
use std::path::PathBuf;
use anyhow::Result;
use anyhow::bail;
use bpaf::Bpaf;
use bpaf::Parser;
use bpaf::construct;
use bpaf::long;
use elp_ide::elp_ide_db::DiagnosticCode;
use elp_project_model::buck::BuckQueryConfig;
use hir::fold::MacroStrategy;
use hir::fold::ParenStrategy;
use hir::fold::Strategy;
use itertools::Itertools;
use serde::Deserialize;
@ -63,6 +69,20 @@ pub struct ParseAllElp {
guard(format_guard, "Please use json")
)]
pub format: Option<String>,
/// Report system memory usage and other statistics
#[bpaf(long("report-system-stats"))]
pub report_system_stats: bool,
/// Minimum severity level to report. Valid values: error, warning, weak_warning, information
#[bpaf(
argument("SEVERITY"),
complete(severity_completer),
fallback(None),
guard(
severity_guard,
"Please use error, warning, weak_warning, or information"
)
)]
pub severity: Option<String>,
}
#[derive(Clone, Debug, Bpaf)]
@ -135,8 +155,6 @@ pub struct EqwalizeAll {
/// Also eqwalize opted-in generated modules from project (deprecated)
#[bpaf(hide)]
pub include_generated: bool,
/// Also eqwalize test modules from project
pub include_tests: bool,
/// Exit with a non-zero status code if any errors are found
pub bail_on_error: bool,
/// Print statistics when done
@ -153,8 +171,6 @@ pub struct EqwalizeTarget {
/// Also eqwalize opted-in generated modules from application (deprecated)
#[bpaf(hide)]
pub include_generated: bool,
/// Also eqwalize test modules from project
pub include_tests: bool,
/// Exit with a non-zero status code if any errors are found
pub bail_on_error: bool,
/// target, like //erl/chatd/...
@ -173,8 +189,6 @@ pub struct EqwalizeApp {
/// Also eqwalize opted-in generated modules from project (deprecated)
#[bpaf(hide)]
pub include_generated: bool,
/// Also eqwalize test modules from project
pub include_tests: bool,
/// Run with rebar
pub rebar: bool,
/// Exit with a non-zero status code if any errors are found
@ -197,8 +211,6 @@ pub struct EqwalizeStats {
/// Also eqwalize opted-in generated modules from project (deprecated)
#[bpaf(hide)]
pub include_generated: bool,
/// Also eqwalize test modules from project
pub include_tests: bool,
/// If specified, use the provided CLI severity mapping instead of the default one
pub use_cli_severity: bool,
}
@ -266,8 +278,6 @@ pub struct Lint {
guard(format_guard, "Please use json")
)]
pub format: Option<String>,
/// Optional prefix to prepend to each diagnostic file path. Only used when --format=json is set
pub prefix: Option<String>,
/// Include diagnostics produced by erlc
pub include_erlc_diagnostics: bool,
@ -320,11 +330,106 @@ pub struct Lint {
/// than one at a time.
pub one_shot: bool,
/// Report system memory usage and other statistics
#[bpaf(long("report-system-stats"))]
pub report_system_stats: bool,
/// Disable streaming of diagnostics when applying fixes (collect all before printing)
pub no_stream: bool,
/// Rest of args are space separated list of apps to ignore
#[bpaf(positional("IGNORED_APPS"))]
pub ignore_apps: Vec<String>,
}
#[derive(Clone, Debug, Bpaf)]
pub struct Ssr {
/// Path to directory with project, or to a JSON file (defaults to `.`)
#[bpaf(argument("PROJECT"), fallback(PathBuf::from(".")))]
pub project: PathBuf,
/// Parse a single module from the project, not the entire project.
#[bpaf(argument("MODULE"))]
pub module: Option<String>,
/// Parse a single application from the project, not the entire project.
#[bpaf(long("app"), long("application"), argument("APP"))]
pub app: Option<String>,
/// Parse a single file from the project, not the entire project. This can be an include file or escript, etc.
#[bpaf(argument("FILE"))]
pub file: Option<String>,
/// Run with rebar
pub rebar: bool,
/// Rebar3 profile to pickup (default is test)
#[bpaf(long("as"), argument("PROFILE"), fallback("test".to_string()))]
pub profile: String,
/// Also generate diagnostics for generated files
pub include_generated: bool,
/// Also generate diagnostics for test files
pub include_tests: bool,
/// Show diagnostics in JSON format
#[bpaf(
argument("FORMAT"),
complete(format_completer),
fallback(None),
guard(format_guard, "Please use json")
)]
pub format: Option<String>,
/// Macro expansion strategy: expand | no-expand | visible-expand (default expand)
#[bpaf(
long("macros"),
argument("STRATEGY"),
complete(macros_completer),
fallback(None),
guard(macros_guard, "Please supply a valid macro expansion value")
)]
pub macro_strategy: Option<String>,
/// Explicitly match parentheses. If omitted, they are ignored.
#[bpaf(long("parens"))]
pub paren_strategy: bool,
/// Dump a configuration snippet that can be put in .elp_lint.toml to match the given SSR patterns
pub dump_config: bool,
/// Show source code context for matches
#[bpaf(long("show-source"))]
pub show_source: bool,
/// Print NUM lines of leading context, enables --show-source
#[bpaf(short('B'), long("before-context"), argument("NUM"))]
pub before_context: Option<usize>,
/// Print NUM lines of trailing context, enables --show-source
#[bpaf(short('A'), long("after-context"), argument("NUM"))]
pub after_context: Option<usize>,
/// Print NUM lines of output context, enables --show-source
#[bpaf(short('C'), long("context"), argument("NUM"))]
pub context: Option<usize>,
/// Print SEP on line between matches with context, enables --show-source
#[bpaf(long("group-separator"), argument("SEP"))]
pub group_separator: Option<String>,
/// Do not print separator for matches with context, enables --show-source
#[bpaf(long("no-group-separator"))]
pub no_group_separator: bool,
/// Report system memory usage and other statistics
#[bpaf(long("report-system-stats"))]
pub report_system_stats: bool,
/// SSR specs to use
#[bpaf(
positional("SSR_SPECS"),
guard(at_least_1, "there should be at least one spec")
)]
pub ssr_specs: Vec<String>,
}
#[derive(Clone, Debug, Bpaf)]
pub struct Explain {
/// Error code to explain
@ -349,6 +454,8 @@ pub struct ProjectInfo {
pub to: Option<PathBuf>,
/// Include the buck uquery results in the output
pub buck_query: bool,
/// Dump a list of targets and their types
pub target_types: bool,
}
#[derive(Clone, Debug, Bpaf)]
@ -367,8 +474,6 @@ pub struct Glean {
pub pretty: bool,
/// Output each fact separately
pub multi: bool,
/// Optional prefix to prepend to each fact
pub prefix: Option<String>,
}
#[derive(Clone, Debug, Bpaf)]
@ -388,6 +493,7 @@ pub enum Command {
GenerateCompletions(GenerateCompletions),
RunServer(RunServer),
Lint(Lint),
Ssr(Ssr),
Version(Version),
Shell(Shell),
Explain(Explain),
@ -411,18 +517,47 @@ pub struct Args {
/// When using buck, do not invoke a build step for generated files.
pub no_buck_generated: bool,
/// Use buck2 targets for first stage project loading
pub buck_quick_start: bool,
/// Use color in output; WHEN is 'always', 'never', or 'auto'
#[bpaf(
long("color"),
long("colour"),
argument("WHEN"),
fallback(Some("always".to_string())),
guard(color_guard, "Please use always, never, or auto")
)]
pub color: Option<String>,
#[bpaf(external(command))]
pub command: Command,
}
impl Args {
pub fn query_config(&self) -> BuckQueryConfig {
if self.no_buck_generated {
if self.buck_quick_start {
BuckQueryConfig::BuckTargetsOnly
} else if self.no_buck_generated {
BuckQueryConfig::NoBuildGeneratedCode
} else {
BuckQueryConfig::BuildGeneratedCode
}
}
/// Determine if color should be used based on the --color argument
pub fn should_use_color(&self) -> bool {
match self.color.as_deref() {
Some("always") => true,
Some("never") => false,
Some("auto") | None => {
// Check NO_COLOR environment variable - if set (regardless of value), disable color
// Also check if stdout is connected to a TTY
env::var("NO_COLOR").is_err() && std::io::stdout().is_terminal()
}
_ => false, // Should be caught by the guard, but handle anyway
}
}
}
pub fn command() -> impl Parser<Command> {
@ -466,7 +601,8 @@ pub fn command() -> impl Parser<Command> {
.map(Command::EqwalizeStats)
.to_options()
.command("eqwalize-stats")
.help("Return statistics about code quality for eqWAlizer");
.help("Return statistics about code quality for eqWAlizer")
.hide();
let dialyze_all = dialyze_all()
.map(Command::DialyzeAll)
@ -493,6 +629,18 @@ pub fn command() -> impl Parser<Command> {
.command("lint")
.help("Parse files in project and emit diagnostics, optionally apply fixes.");
let search = ssr()
.map(Command::Ssr)
.to_options()
.command("search")
.help("Alias for 'ssr': Run SSR (Structural Search and Replace) pattern matching on project files.");
let ssr = ssr()
.map(Command::Ssr)
.to_options()
.command("ssr")
.help("Run SSR (Structural Search and Replace) pattern matching on project files.");
let run_server = run_server()
.map(Command::RunServer)
.to_options()
@ -536,23 +684,26 @@ pub fn command() -> impl Parser<Command> {
.help("Dump a JSON config stanza suitable for use in VS Code project.json");
construct!([
// Note: The order here is what is used for `elp --help` output
version,
run_server,
shell,
eqwalize,
eqwalize_all,
eqwalize_app,
eqwalize_target,
eqwalize_stats,
dialyze_all,
lint,
run_server,
generate_completions,
ssr,
search,
parse_all,
parse_elp,
build_info,
version,
shell,
eqwalize_stats,
explain,
build_info,
project_info,
glean,
generate_completions,
config_stanza,
])
.fallback(Help())
@ -635,6 +786,48 @@ fn format_guard(format: &Option<String>) -> bool {
}
}
fn severity_completer(_: &Option<String>) -> Vec<(String, Option<String>)> {
vec![
("error".to_string(), None),
("warning".to_string(), None),
("weak_warning".to_string(), None),
("information".to_string(), None),
]
}
fn severity_guard(severity: &Option<String>) -> bool {
match severity {
None => true,
Some(s) if s == "error" || s == "warning" || s == "weak_warning" || s == "information" => {
true
}
_ => false,
}
}
fn macros_completer(_: &Option<String>) -> Vec<(String, Option<String>)> {
vec![
("expand".to_string(), None),
("no-expand".to_string(), None),
("visible-expand".to_string(), None),
]
}
fn macros_guard(format: &Option<String>) -> bool {
match format {
None => true,
Some(_) => parse_macro_strategy(format).is_ok(),
}
}
fn color_guard(color: &Option<String>) -> bool {
match color {
None => true,
Some(c) if c == "always" || c == "never" || c == "auto" => true,
_ => false,
}
}
#[allow(clippy::ptr_arg)] // This is needed in the BPAF macros
fn at_least_1(data: &Vec<String>) -> bool {
!data.is_empty()
@ -715,6 +908,44 @@ impl Lint {
pub fn is_format_json(&self) -> bool {
self.format == Some("json".to_string())
}
/// To prevent flaky test results we allow disabling streaming when applying fixes
pub fn skip_stream_print(&self) -> bool {
self.apply_fix || self.no_stream
}
}
fn parse_macro_strategy(macro_strategy: &Option<String>) -> Result<MacroStrategy> {
match macro_strategy.as_deref() {
Some("no-expand") => Ok(MacroStrategy::DoNotExpand),
Some("expand") => Ok(MacroStrategy::Expand),
Some("visible-expand") => Ok(MacroStrategy::ExpandButIncludeMacroCall),
None => Ok(MacroStrategy::Expand),
Some(s) => bail!(
"Invalid macro strategy '{}'. Valid options are: expand, no-expand, visible-expand",
s
),
}
}
impl Ssr {
pub fn is_format_normal(&self) -> bool {
self.format.is_none()
}
pub fn is_format_json(&self) -> bool {
self.format == Some("json".to_string())
}
pub fn parse_strategy(&self) -> Result<Strategy> {
let macros = parse_macro_strategy(&self.macro_strategy)?;
let parens = if self.paren_strategy {
ParenStrategy::VisibleParens
} else {
ParenStrategy::InvisibleParens
};
Ok(Strategy { macros, parens })
}
}
impl ParseAllElp {

View file

@ -15,15 +15,18 @@ use std::io::Write;
use anyhow::Result;
use elp_ide::elp_ide_db::elp_base_db::AbsPath;
use elp_ide::elp_ide_db::elp_base_db::AbsPathBuf;
use elp_project_model::AppType;
use elp_project_model::ElpConfig;
use elp_project_model::EqwalizerConfig;
use elp_project_model::IncludeParentDirs;
use elp_project_model::Project;
use elp_project_model::ProjectAppData;
use elp_project_model::ProjectBuildData;
use elp_project_model::ProjectManifest;
use elp_project_model::buck::BuckQueryConfig;
use elp_project_model::buck::query_buck_targets_bxl;
use elp_project_model::buck::BuckTarget;
use elp_project_model::buck::query_buck_targets;
use elp_project_model::json::JsonConfig;
use fxhash::FxHashMap;
use crate::args::BuildInfo;
use crate::args::ProjectInfo;
@ -31,8 +34,8 @@ use crate::args::ProjectInfo;
pub(crate) fn save_build_info(args: BuildInfo, query_config: &BuckQueryConfig) -> Result<()> {
let root = fs::canonicalize(&args.project)?;
let root = AbsPathBuf::assert_utf8(root);
let (_elp_config, manifest) = ProjectManifest::discover(&root)?;
let project = Project::load(&manifest, EqwalizerConfig::default(), query_config, &|_| {})?;
let (elp_config, manifest) = ProjectManifest::discover(&root)?;
let project = Project::load(&manifest, &elp_config, query_config, &|_| {})?;
let mut writer = File::create(&args.to)?;
let json_str = serde_json::to_string_pretty::<JsonConfig>(&project.as_json(root))?;
writer.write_all(json_str.as_bytes())?;
@ -66,25 +69,68 @@ pub(crate) fn save_project_info(args: ProjectInfo, query_config: &BuckQueryConfi
if args.buck_query
&& let ProjectBuildData::Buck(buck) = &project.project_build_data
{
let buck_targets_query = query_buck_targets_bxl(&buck.buck_conf, query_config);
writer.write_all(b"================buck targets query raw================\n")?;
writer.write_all(format!("{:#?}\n", &buck_targets_query).as_bytes())?;
};
writer.write_all(b"================manifest================\n")?;
writer.write_all(format!("{:#?}\n", &manifest).as_bytes())?;
writer.write_all(b"================project_build_data================\n")?;
writer.write_all(format!("{:#?}\n", &project.project_build_data).as_bytes())?;
writer.write_all(b"================project_app_data================\n")?;
writer.write_all(format!("{:#?}\n", &project.project_apps).as_bytes())?;
let buck_targets_query = query_buck_targets(&buck.buck_conf, query_config);
if let Ok(targets) = &buck_targets_query {
writer.write_all(format!("{:#?}\n", sort_buck_targets(targets)).as_bytes())?;
} else {
writer.write_all(format!("{:#?}\n", &buck_targets_query).as_bytes())?;
}
} else if args.target_types {
writer.write_all(b"================target types================\n")?;
for line in buck_targets_and_types(&project.project_apps) {
writer.write_all(format!("{}\n", line).as_bytes())?;
}
} else {
writer.write_all(b"================manifest================\n")?;
writer.write_all(format!("{:#?}\n", &manifest).as_bytes())?;
writer.write_all(b"================project_build_data================\n")?;
writer.write_all(format!("{:#?}\n", &project.project_build_data).as_bytes())?;
writer.write_all(b"================project_app_data================\n")?;
writer.write_all(format!("{:#?}\n", &project.project_apps).as_bytes())?;
}
Ok(())
}
fn sort_buck_targets(hash_map: &FxHashMap<String, BuckTarget>) -> Vec<(String, &BuckTarget)> {
let mut vec = hash_map
.iter()
.map(|(n, t)| (format!("target_name:{}", n), t))
.collect::<Vec<_>>();
vec.sort_by(|a, b| a.0.cmp(&b.0));
vec
}
fn buck_targets_and_types(apps: &[ProjectAppData]) -> Vec<String> {
let tn = |tn| -> String {
if let Some(tn) = tn {
tn
} else {
"".to_string()
}
};
let mut vec = apps
.iter()
.filter(|app| app.app_type != AppType::Otp)
.filter(|app| app.is_buck_generated != Some(true))
.map(|app| {
format!(
"{:?} {:<30} {}",
app.app_type,
app.name,
tn(app.buck_target_name.clone())
)
})
.collect::<Vec<_>>();
vec.sort();
vec
}
fn load_project(
root: &AbsPath,
query_config: &BuckQueryConfig,
) -> Result<(ProjectManifest, Project)> {
let (elp_config, manifest) = ProjectManifest::discover(root)?;
let project = Project::load(&manifest, elp_config.eqwalizer, query_config, &|_| {})?;
let project = Project::load(&manifest, &elp_config, query_config, &|_| {})?;
Ok((manifest, project))
}
@ -94,6 +140,6 @@ fn load_fallback(
) -> Result<(ProjectManifest, Project)> {
let manifest = ProjectManifest::discover_no_manifest(root, IncludeParentDirs::Yes);
let elp_config = ElpConfig::default();
let project = Project::load(&manifest, elp_config.eqwalizer, query_config, &|_| {})?;
let project = Project::load(&manifest, &elp_config, query_config, &|_| {})?;
Ok((manifest, project))
}

View file

@ -14,6 +14,7 @@ use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::str;
use std::time::SystemTime;
use anyhow::Result;
use anyhow::bail;
@ -21,8 +22,8 @@ use elp::build::load;
use elp::build::types::LoadResult;
use elp::cli::Cli;
use elp::convert;
use elp::memory_usage::MemoryUsage;
use elp::otp_file_to_ignore;
use elp::server::file_id_to_url;
use elp_eqwalizer::Mode;
use elp_ide::Analysis;
use elp_ide::diagnostics;
@ -39,6 +40,7 @@ use elp_ide::elp_ide_db::elp_base_db::IncludeOtp;
use elp_ide::elp_ide_db::elp_base_db::ModuleName;
use elp_ide::elp_ide_db::elp_base_db::Vfs;
use elp_ide::elp_ide_db::elp_base_db::VfsPath;
use elp_log::telemetry;
use elp_project_model::AppType;
use elp_project_model::DiscoverConfig;
use elp_project_model::buck::BuckQueryConfig;
@ -53,6 +55,36 @@ use vfs::AbsPath;
use crate::args::ParseAllElp;
use crate::reporting;
use crate::reporting::print_memory_usage;
fn parse_severity(severity: &str) -> Option<diagnostics::Severity> {
match severity {
"error" => Some(diagnostics::Severity::Error),
"warning" => Some(diagnostics::Severity::Warning),
"weak_warning" => Some(diagnostics::Severity::WeakWarning),
"information" => Some(diagnostics::Severity::Information),
_ => None,
}
}
fn severity_rank(severity: diagnostics::Severity) -> u8 {
match severity {
diagnostics::Severity::Error => 1,
diagnostics::Severity::Warning => 2,
diagnostics::Severity::WeakWarning => 3,
diagnostics::Severity::Information => 4,
}
}
fn meets_severity_threshold(
diag_severity: diagnostics::Severity,
min_severity: Option<diagnostics::Severity>,
) -> bool {
match min_severity {
None => true,
Some(min) => severity_rank(diag_severity) <= severity_rank(min),
}
}
#[derive(Debug)]
struct ParseResult {
@ -68,6 +100,10 @@ pub fn parse_all(
) -> Result<()> {
log::info!("Loading project at: {:?}", args.project);
let start_time = SystemTime::now();
// Track memory usage at the start
let memory_start = MemoryUsage::now();
let config = DiscoverConfig::new(args.rebar, &args.profile);
let loaded = load::load_project_at(
cli,
@ -124,8 +160,7 @@ pub fn parse_all(
(None, _, true) => do_parse_all_seq(cli, &loaded, &cfg, &args.to)?,
(None, _, false) => do_parse_all_par(cli, &loaded, &cfg, &args.to)?,
(Some(file_id), Some(name), _) => {
do_parse_one(&analysis, &loaded.vfs, &cfg, &args.to, file_id, &name)?
.map_or(vec![], |x| vec![x])
do_parse_one(&analysis, &cfg, &args.to, file_id, &name)?.map_or(vec![], |x| vec![x])
}
(Some(file_id), _, _) => panic!("Could not get name from file_id for {file_id:?}"),
};
@ -136,14 +171,32 @@ pub fn parse_all(
let db = loaded.analysis_host.raw_database();
// We need a `Url` for converting to the lsp_types::Diagnostic for
// printing, but do not print it out. So just create a dummy value
let url = lsp_types::Url::parse("file:///unused_url").ok().unwrap();
telemetry::report_elapsed_time("parse-elp operational", start_time);
let memory_end = MemoryUsage::now();
let memory_used = memory_end - memory_start;
let min_severity = args
.severity
.as_ref()
.and_then(|s| parse_severity(s.as_str()));
res.retain(|parse_result| {
parse_result
.diagnostics
.diagnostics_for(parse_result.file_id)
.iter()
.any(|diag| meets_severity_threshold(diag.severity, min_severity))
});
if res.is_empty() {
if args.is_format_normal() {
writeln!(cli, "No errors reported")?;
}
if args.is_format_normal() && args.report_system_stats {
print_memory_usage(loaded.analysis_host, loaded.vfs, cli)?;
writeln!(cli, "{}", memory_used)?;
}
Ok(())
} else {
if args.is_format_normal() {
@ -154,6 +207,7 @@ pub fn parse_all(
for diags in res {
let mut combined: Vec<diagnostics::Diagnostic> =
diags.diagnostics.diagnostics_for(diags.file_id);
combined.retain(|diag| meets_severity_threshold(diag.severity, min_severity));
if args.is_format_normal() {
writeln!(cli, " {}: {}", diags.name, combined.len())?;
}
@ -180,11 +234,19 @@ pub fn parse_all(
cli,
)?;
} else {
print_diagnostic(&diag, &line_index, &url, &mut err_in_diag, cli)?;
print_diagnostic(&diag, &line_index, &mut err_in_diag, cli)?;
}
}
}
}
telemetry::report_elapsed_time("parse-elp done", start_time);
if args.is_format_normal() && args.report_system_stats {
print_memory_usage(loaded.analysis_host, loaded.vfs, cli)?;
writeln!(cli, "{}", memory_used)?;
}
if err_in_diag {
bail!("Parse failures found")
} else {
@ -217,11 +279,10 @@ fn print_diagnostic_json(
fn print_diagnostic(
diag: &diagnostics::Diagnostic,
line_index: &LineIndex,
url: &lsp_types::Url,
err_in_diag: &mut bool,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
let diag = convert::ide_to_lsp_diagnostic(line_index, url, diag);
let diag = convert::ide_to_lsp_diagnostic(line_index, diag, |_file_id| None);
let severity = match diag.severity {
None => DiagnosticSeverity::ERROR,
Some(sev) => {
@ -264,7 +325,6 @@ fn do_parse_all_par(
let pb = cli.progress(module_iter.len() as u64, "Parsing modules");
let vfs = &loaded.vfs;
Ok(module_iter
.par_bridge()
.progress_with(pb)
@ -275,7 +335,7 @@ fn do_parse_all_par(
&& file_source == FileSource::Src
&& db.file_app_type(file_id).ok() != Some(Some(AppType::Dep))
{
do_parse_one(db, vfs, config, to, file_id, module_name.as_str()).unwrap()
do_parse_one(db, config, to, file_id, module_name.as_str()).unwrap()
} else {
None
}
@ -296,7 +356,6 @@ fn do_parse_all_seq(
let pb = cli.progress(module_iter.len() as u64, "Parsing modules (sequential)");
let vfs = &loaded.vfs;
let db = loaded.analysis();
Ok(module_iter
.progress_with(pb)
@ -305,7 +364,7 @@ fn do_parse_all_seq(
&& file_source == FileSource::Src
&& db.file_app_type(file_id).ok() != Some(Some(AppType::Dep))
{
do_parse_one(&db, vfs, config, to, file_id, module_name.as_str()).unwrap()
do_parse_one(&db, config, to, file_id, module_name.as_str()).unwrap()
} else {
None
}
@ -315,13 +374,11 @@ fn do_parse_all_seq(
fn do_parse_one(
db: &Analysis,
vfs: &Vfs,
config: &DiagnosticsConfig,
to: &Option<PathBuf>,
file_id: FileId,
name: &str,
) -> Result<Option<ParseResult>> {
let url = file_id_to_url(vfs, file_id);
let native = db.native_diagnostics(config, &vec![], file_id)?;
let erlang_service_diagnostics =
db.erlang_service_diagnostics(file_id, config, RemoveElpReported::Yes)?;
@ -339,11 +396,13 @@ fn do_parse_one(
let mut output = File::create(to_path)?;
for diagnostic in native.iter() {
let diagnostic = convert::ide_to_lsp_diagnostic(&line_index, &url, diagnostic);
let diagnostic =
convert::ide_to_lsp_diagnostic(&line_index, diagnostic, |_file_id| None);
writeln!(output, "{diagnostic:?}")?;
}
for diagnostic in erlang_service.iter() {
let diagnostic = convert::ide_to_lsp_diagnostic(&line_index, &url, diagnostic);
let diagnostic =
convert::ide_to_lsp_diagnostic(&line_index, diagnostic, |_file_id| None);
writeln!(output, "{diagnostic:?}")?;
}
}

View file

@ -10,6 +10,7 @@
use std::path::Path;
use std::sync::Arc;
use std::time::SystemTime;
use anyhow::Context;
use anyhow::Result;
@ -38,6 +39,7 @@ use elp_ide::elp_ide_db::elp_base_db::FileId;
use elp_ide::elp_ide_db::elp_base_db::IncludeOtp;
use elp_ide::elp_ide_db::elp_base_db::ModuleName;
use elp_ide::elp_ide_db::elp_base_db::VfsPath;
use elp_log::telemetry;
use elp_project_model::AppName;
use elp_project_model::DiscoverConfig;
use elp_project_model::ProjectBuildData;
@ -76,6 +78,7 @@ pub fn eqwalize_module(
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
) -> Result<()> {
let start_time = SystemTime::now();
let config = DiscoverConfig::new(args.rebar, &args.profile);
let mut loaded = load::load_project_at(
cli,
@ -86,7 +89,10 @@ pub fn eqwalize_module(
query_config,
)?;
build::compile_deps(&loaded, cli)?;
do_eqwalize_module(args, &mut loaded, cli)
telemetry::report_elapsed_time("eqwalize operational", start_time);
let r = do_eqwalize_module(args, &mut loaded, cli);
telemetry::report_elapsed_time("eqwalize done", start_time);
r
}
pub fn do_eqwalize_module(
@ -143,6 +149,7 @@ pub fn eqwalize_all(
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
) -> Result<()> {
let start_time = SystemTime::now();
// Hack to avoid hint appearing in tests
cli.spinner(SHELL_HINT).finish();
let config = DiscoverConfig::new(args.rebar, &args.profile);
@ -155,7 +162,10 @@ pub fn eqwalize_all(
query_config,
)?;
build::compile_deps(&loaded, cli)?;
do_eqwalize_all(args, &mut loaded, cli)
telemetry::report_elapsed_time("eqwalize-all operational", start_time);
let r = do_eqwalize_all(args, &mut loaded, cli);
telemetry::report_elapsed_time("eqwalize-all done", start_time);
r
}
pub fn do_eqwalize_all(
@ -176,10 +186,7 @@ pub fn do_eqwalize_all(
.par_bridge()
.progress_with(pb.clone())
.map_with(analysis.clone(), |analysis, (name, _source, file_id)| {
if analysis
.should_eqwalize(file_id, args.include_tests)
.unwrap()
&& !otp_file_to_ignore(analysis, file_id)
if analysis.should_eqwalize(file_id).unwrap() && !otp_file_to_ignore(analysis, file_id)
{
if args.stats {
add_stat(name.to_string());
@ -226,6 +233,7 @@ pub fn eqwalize_app(
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
) -> Result<()> {
let start_time = SystemTime::now();
let config = DiscoverConfig::new(args.rebar, &args.profile);
let mut loaded = load::load_project_at(
cli,
@ -236,7 +244,10 @@ pub fn eqwalize_app(
query_config,
)?;
build::compile_deps(&loaded, cli)?;
do_eqwalize_app(args, &mut loaded, cli)
telemetry::report_elapsed_time("eqwalize-app operational", start_time);
let r = do_eqwalize_app(args, &mut loaded, cli);
telemetry::report_elapsed_time("eqwalize-app done", start_time);
r
}
pub fn do_eqwalize_app(
@ -255,9 +266,7 @@ pub fn do_eqwalize_app(
.iter_own()
.filter_map(|(_name, _source, file_id)| {
if analysis.file_app_name(file_id).ok()? == Some(AppName(args.app.clone()))
&& analysis
.should_eqwalize(file_id, args.include_tests)
.unwrap()
&& analysis.should_eqwalize(file_id).unwrap()
&& !otp_file_to_ignore(analysis, file_id)
{
Some(file_id)
@ -283,6 +292,7 @@ pub fn eqwalize_target(
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
) -> Result<()> {
let start_time = SystemTime::now();
let config = DiscoverConfig::buck();
let mut loaded = load::load_project_at(
cli,
@ -294,6 +304,7 @@ pub fn eqwalize_target(
)?;
set_eqwalizer_config(&mut loaded);
telemetry::report_elapsed_time("eqwalize-target operational", start_time);
let buck = match &loaded.project.project_build_data {
ProjectBuildData::Buck(buck) => buck,
@ -323,9 +334,7 @@ pub fn eqwalize_target(
let vfs_path = VfsPath::from(src.clone());
if let Some((file_id, _)) = loaded.vfs.file_id(&vfs_path) {
at_least_one_found = true;
if analysis
.should_eqwalize(file_id, args.include_tests)
.unwrap()
if analysis.should_eqwalize(file_id).unwrap()
&& !otp_file_to_ignore(analysis, file_id)
{
file_ids.push(file_id);
@ -353,13 +362,15 @@ elp eqwalize-target erl/chatd #same as //erl/chatd/... but enables shell complet
let mut reporter = reporting::PrettyReporter::new(analysis, &loaded, cli);
let bail_on_error = args.bail_on_error;
eqwalize(EqwalizerInternalArgs {
let r = eqwalize(EqwalizerInternalArgs {
analysis,
loaded: &loaded,
file_ids,
reporter: &mut reporter,
bail_on_error,
})
});
telemetry::report_elapsed_time("eqwalize-target done", start_time);
r
}
pub fn eqwalize_stats(
@ -390,9 +401,7 @@ pub fn eqwalize_stats(
.par_bridge()
.progress_with(pb.clone())
.map_with(analysis.clone(), |analysis, (name, _source, file_id)| {
if analysis
.should_eqwalize(file_id, args.include_tests)
.expect("cancelled")
if analysis.should_eqwalize(file_id).expect("cancelled")
&& !otp_file_to_ignore(analysis, file_id)
{
analysis
@ -464,8 +473,6 @@ fn eqwalize(
bail!("No files to eqWAlize detected")
}
pre_parse_for_speed(reporter, analysis.clone(), &file_ids);
let files_count = file_ids.len();
let pb = reporter.progress(files_count as u64, "EqWAlizing");
let output = loaded.with_eqwalizer_progress_bar(pb.clone(), move |analysis| {
@ -584,17 +591,6 @@ fn eqwalize(
}
}
fn pre_parse_for_speed(reporter: &dyn Reporter, analysis: Analysis, file_ids: &[FileId]) {
let pb = reporter.progress(file_ids.len() as u64, "Parsing modules");
file_ids
.par_iter()
.progress_with(pb.clone())
.for_each_with(analysis, |analysis, &file_id| {
let _ = analysis.module_ast(file_id);
});
pb.finish();
}
fn set_eqwalizer_config(loaded: &mut LoadResult) {
let config = EqwalizerConfig::default();
let db = loaded.analysis_host.raw_database_mut();

View file

@ -11,6 +11,7 @@
use std::fs;
use std::path::Path;
use std::str;
use std::time::SystemTime;
use anyhow::Context;
use anyhow::Error;
@ -26,6 +27,7 @@ use elp_ide::Analysis;
use elp_ide::elp_ide_db::elp_base_db::FileId;
use elp_ide::elp_ide_db::elp_base_db::IncludeOtp;
use elp_ide::erlang_service::DiagnosticLocation;
use elp_log::telemetry;
use elp_log::timeit;
use elp_project_model::AppType;
use elp_project_model::DiscoverConfig;
@ -40,6 +42,7 @@ use crate::reporting::add_stat;
use crate::reporting::dump_stats;
pub fn parse_all(args: &ParseAll, cli: &mut dyn Cli, query_config: &BuckQueryConfig) -> Result<()> {
let start_time = SystemTime::now();
let config = DiscoverConfig::new(!args.buck, &args.profile);
let loaded = load::load_project_at(
cli,
@ -52,10 +55,15 @@ pub fn parse_all(args: &ParseAll, cli: &mut dyn Cli, query_config: &BuckQueryCon
build::compile_deps(&loaded, cli)?;
fs::create_dir_all(&args.to)?;
telemetry::report_elapsed_time("parse-all operational", start_time);
let parse_diagnostics = do_parse_all(cli, &loaded, &args.to, &args.module, args.buck)?;
if args.stats {
dump_stats(cli, args.list_modules);
}
telemetry::report_elapsed_time("parse-all done", start_time);
if !parse_diagnostics.is_empty() {
writeln!(
cli,
@ -142,14 +150,15 @@ pub fn do_parse_one(
.chain(result.warnings.iter())
.map(|err| {
let relative_path: &Path = err.path.strip_prefix(root_dir).unwrap_or(&err.path);
let (range, line_num) = match err.location {
let (range, line_num) = match &err.location {
None => (None, convert::position(&line_index, 0.into()).line + 1),
Some(DiagnosticLocation::Normal(range)) => (
Some(range),
convert::position(&line_index, range.start()).line + 1,
),
Some(DiagnosticLocation::Included {
directive_location,
file_attribute_location: directive_location,
error_path: _,
error_location: _,
}) => (
Some(directive_location),
@ -161,7 +170,7 @@ pub fn do_parse_one(
relative_path: relative_path.to_owned(),
line_num,
msg: err.msg.to_owned(),
range,
range: range.copied(),
}
})
.collect();

View file

@ -8,9 +8,9 @@
* above-listed licenses.
*/
use core::option::Option::None;
use std::io::Write;
use std::mem;
use std::path::Path;
use anyhow::Result;
use elp::build::load;
@ -24,6 +24,7 @@ use elp_ide::elp_ide_db::EqwalizerDatabase;
use elp_ide::elp_ide_db::LineIndexDatabase;
use elp_ide::elp_ide_db::RootDatabase;
use elp_ide::elp_ide_db::docs::DocDatabase;
use elp_ide::elp_ide_db::docs::Documentation;
use elp_ide::elp_ide_db::elp_base_db::FileId;
use elp_ide::elp_ide_db::elp_base_db::IncludeOtp;
use elp_ide::elp_ide_db::elp_base_db::ModuleName;
@ -51,9 +52,11 @@ use hir::DefineId;
use hir::Expr;
use hir::ExprId;
use hir::ExprSource;
use hir::File;
use hir::InFile;
use hir::Literal;
use hir::MacroName;
use hir::Module;
use hir::Name;
use hir::NameArity;
use hir::PPDirective;
@ -81,7 +84,7 @@ const REC_ARITY: u32 = 99;
const HEADER_ARITY: u32 = 100;
const FACTS_FILE: &str = "facts.json";
// @fb-only
// @fb-only: mod meta_only;
#[derive(Serialize, Debug, Eq, Hash, PartialEq, Clone)]
struct GleanFileId(u32);
@ -89,7 +92,6 @@ struct GleanFileId(u32);
#[derive(Clone, Debug, Default)]
struct IndexConfig {
pub multi: bool,
pub prefix: Option<String>,
}
impl From<GleanFileId> for FileId {
@ -143,6 +145,45 @@ impl FileLinesFact {
}
}
#[derive(Serialize, Debug)]
pub(crate) struct ModuleFact {
#[serde(rename = "file")]
file_id: GleanFileId,
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
oncall: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
exports: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
behaviours: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
module_doc: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
exdoc_link: Option<String>,
}
impl ModuleFact {
fn new(
file_id: FileId,
name: String,
oncall: Option<String>,
exports: Option<Vec<String>>,
behaviours: Option<Vec<String>>,
module_doc: Option<String>,
exdoc_link: Option<String>,
) -> Self {
Self {
file_id: file_id.into(),
name,
oncall,
exports,
behaviours,
module_doc,
exdoc_link,
}
}
}
#[derive(Serialize, Debug)]
pub(crate) struct FunctionDeclarationFact {
#[serde(rename = "file")]
@ -237,6 +278,8 @@ pub(crate) enum Fact {
XRef { facts: Vec<Key<XRefFact>> },
#[serde(rename = "erlang.DeclarationComment")]
DeclarationComment { facts: Vec<Key<CommentFact>> },
#[serde(rename = "erlang.Module")]
Module { facts: Vec<Key<ModuleFact>> },
}
#[derive(Serialize, Debug)]
@ -300,6 +343,10 @@ pub(crate) struct MacroTarget {
expansion: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
ods_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
logview_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
scuba_urls: Option<Vec<(String, String)>>,
}
#[derive(Serialize, Debug)]
@ -314,6 +361,8 @@ pub(crate) struct RecordTarget {
#[serde(rename = "file")]
file_id: GleanFileId,
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
wam_url: Option<String>,
}
#[derive(Serialize, Debug)]
@ -434,6 +483,7 @@ struct IndexedFacts {
file_line_facts: Vec<FileLinesFact>,
declaration_facts: Vec<FunctionDeclarationFact>,
xref_facts: Vec<XRefFact>,
module_facts: Vec<ModuleFact>,
//v2 facts
file_declarations: Vec<FileDeclaration>,
xref_v2: Vec<XRefFile>,
@ -446,6 +496,7 @@ impl IndexedFacts {
decl: FileDeclaration,
xref: XRefFile,
facts_v1: Option<(Vec<FunctionDeclarationFact>, XRefFact)>,
module_fact: Option<ModuleFact>,
) -> Self {
let mut facts = Self::default();
facts.file_facts.push(file_fact);
@ -456,6 +507,9 @@ impl IndexedFacts {
facts.declaration_facts.extend(decl);
facts.xref_facts.push(xref);
}
if let Some(module_fact) = module_fact {
facts.module_facts.push(module_fact);
}
facts
}
@ -466,6 +520,7 @@ impl IndexedFacts {
decl: FileDeclaration,
xref: XRefFile,
facts: Option<(Vec<FunctionDeclarationFact>, XRefFact)>,
module_fact: Option<ModuleFact>,
) {
self.file_facts.push(file_fact);
self.file_line_facts.push(line_fact);
@ -475,6 +530,9 @@ impl IndexedFacts {
self.declaration_facts.extend(decl);
self.xref_facts.push(xref);
}
if let Some(module_fact) = module_fact {
self.module_facts.push(module_fact);
}
}
fn into_v1_facts(mut self) -> Vec<Fact> {
@ -680,6 +738,8 @@ impl IndexedFacts {
});
}
let xref_fact = xrefs.into_iter().map_into().collect();
let module_facts = mem::take(&mut self.module_facts);
let module_facts = module_facts.into_iter().map_into().collect();
vec![
Fact::File {
facts: mem::take(&mut self.file_facts),
@ -692,6 +752,9 @@ impl IndexedFacts {
},
Fact::XRef { facts: xref_fact },
Fact::DeclarationComment { facts: comments },
Fact::Module {
facts: module_facts,
},
]
}
}
@ -704,10 +767,7 @@ pub struct GleanIndexer {
pub fn index(args: &Glean, cli: &mut dyn Cli, query_config: &BuckQueryConfig) -> Result<()> {
let (indexer, _loaded) = GleanIndexer::new(args, cli, query_config)?;
let config = IndexConfig {
multi: args.multi,
prefix: args.prefix.clone(),
};
let config = IndexConfig { multi: args.multi };
let (facts, module_index) = indexer.index(config)?;
write_results(facts, module_index, cli, args)
}
@ -796,19 +856,12 @@ impl GleanIndexer {
let source_root_id = db.file_source_root(file_id);
let source_root = db.source_root(source_root_id);
let path = source_root.path_for_file(&file_id).unwrap();
match Self::index_file(
db,
file_id,
path,
project_id,
&module_index,
config.prefix.as_ref(),
) {
Some((file, line, decl, xref, facts)) => {
match Self::index_file(db, file_id, path, project_id, &module_index) {
Some((file, line, decl, xref, facts, module_fact)) => {
let mut result = FxHashMap::default();
result.insert(
FACTS_FILE.to_string(),
IndexedFacts::new(file, line, decl, xref, facts),
IndexedFacts::new(file, line, decl, xref, facts, module_fact),
);
result
}
@ -819,21 +872,14 @@ impl GleanIndexer {
.into_par_iter()
.map_with(self.analysis.clone(), |analysis, (file_id, path)| {
analysis.with_db(|db| {
Self::index_file(
db,
file_id,
&path,
project_id,
&module_index,
config.prefix.as_ref(),
)
Self::index_file(db, file_id, &path, project_id, &module_index)
})
})
.flatten()
.flatten();
if config.multi {
iter.map(|(file, line, decl, xref, facts)| {
IndexedFacts::new(file, line, decl, xref, facts)
iter.map(|(file, line, decl, xref, facts, module_fact)| {
IndexedFacts::new(file, line, decl, xref, facts, module_fact)
})
.collect::<Vec<_>>()
.into_iter()
@ -844,8 +890,8 @@ impl GleanIndexer {
let mut result = FxHashMap::default();
let facts = iter.collect::<Vec<_>>().into_iter().fold(
IndexedFacts::default(),
|mut acc, (file_fact, line_fact, decl, xref, facts)| {
acc.add(file_fact, line_fact, decl, xref, facts);
|mut acc, (file_fact, line_fact, decl, xref, facts, module_fact)| {
acc.add(file_fact, line_fact, decl, xref, facts, module_fact);
acc
},
);
@ -883,15 +929,15 @@ impl GleanIndexer {
path: &VfsPath,
project_id: ProjectId,
module_index: &FxHashMap<GleanFileId, String>,
prefix: Option<&String>,
) -> Option<(
FileFact,
FileLinesFact,
FileDeclaration,
XRefFile,
Option<(Vec<FunctionDeclarationFact>, XRefFact)>,
Option<ModuleFact>,
)> {
let file_fact = Self::file_fact(db, file_id, path, project_id, prefix)?;
let file_fact = Self::file_fact(db, file_id, path, project_id)?;
let line_fact = Self::line_fact(db, file_id);
let mut xref_v2 = Self::xrefs_v2(db, file_id, module_index);
let mut file_decl = Self::declarations_v2(db, file_id, path)?;
@ -901,9 +947,65 @@ impl GleanIndexer {
if let Some(module) = elp_module_index.module_for_file(file_id) {
let decl = Self::declarations_v1(db, file_id, module);
let xref = Self::xrefs(db, file_id, module_index);
return Some((file_fact, line_fact, file_decl, xref_v2, Some((decl, xref))));
let module_fact = Self::module_fact(db, file_id, module);
return Some((
file_fact,
line_fact,
file_decl,
xref_v2,
Some((decl, xref)),
Some(module_fact),
));
}
Some((file_fact, line_fact, file_decl, xref_v2, None))
Some((file_fact, line_fact, file_decl, xref_v2, None, None))
}
fn module_fact(db: &RootDatabase, file_id: FileId, module_name: &ModuleName) -> ModuleFact {
let module = Module {
file: File { file_id },
};
let name = module_name.to_string();
// Extract exported functions from def_map
let def_map = db.def_map_local(file_id);
let mut exports = vec![];
for (fun, def) in def_map.get_functions() {
if def.exported {
exports.push(format!("{}/{}", fun.name(), fun.arity()));
}
}
// Extract oncall, behaviour, and moduledoc using form_list API
let sema = Semantic::new(db);
let form_list = sema.form_list(file_id);
let oncall = sema.attribute_value_as_string(file_id, hir::known::oncall);
let behaviours: Vec<String> = form_list
.behaviour_attributes()
.map(|(_, behaviour)| behaviour.name.to_string())
.collect();
let module_doc = sema.module_attribute(file_id).and_then(|module_attribute| {
let docs = Documentation::new(db, &sema);
docs.to_doc(InFile::new(file_id, &module_attribute))
.map(|doc| doc.markdown_text().to_string())
.filter(|text| !text.is_empty())
});
// @fb-only: let exdoc_link = elp_ide::meta_only::exdoc_links::module_exdoc_link(&module, &sema);
let exdoc_link: Option<String> = None; // @oss-only
ModuleFact::new(
file_id,
name,
oncall,
(!exports.is_empty()).then_some(exports),
(!behaviours.is_empty()).then_some(behaviours),
module_doc,
exdoc_link,
)
}
fn add_xref_based_declarations(
@ -928,12 +1030,43 @@ impl GleanIndexer {
let range = def.source(db).syntax().text_range();
let text = &db.file_text(id)[range];
let text = format!("```erlang\n{text}\n```");
let doc = match (&x.key.expansion, &x.key.ods_url) {
(None, None) => text,
(None, Some(o)) => format!("[ODS]({o})\n{text}"),
(Some(e), None) => format!("{text}\n---\n\n{e}"),
(Some(e), Some(o)) => format!("[ODS]({o})\n{text}\n---\n\n{e}"),
let scuba_links =
x.key
.scuba_urls
.as_ref()
.map_or(String::new(), |scuba_urls| {
scuba_urls
.iter()
.map(|(display_name, url)| {
format!("[{}]({})", display_name, url)
})
.collect::<Vec<_>>()
.join(" | ")
});
let scuba_section = if !scuba_links.is_empty() {
format!("Scuba: {}\n", scuba_links)
} else {
String::new()
};
let doc = format!(
"{}{}{}{}{}",
x.key
.ods_url
.as_ref()
.map_or(String::new(), |o| format!("[ODS]({})\n", o)),
x.key
.logview_url
.as_ref()
.map_or(String::new(), |l| format!("[LogView]({})\n", l)),
scuba_section,
text,
x.key
.expansion
.as_ref()
.map_or(String::new(), |e| format!("\n---\n\n{}", e))
);
let decl = Declaration::MacroDeclaration(
MacroDecl {
name: x.key.name.clone(),
@ -956,6 +1089,38 @@ impl GleanIndexer {
x.key.arity = Some(xref.source.start);
}
}
XRefTarget::Record(x) => {
// Add WAM documentation for records that have wam_url
if let Some(wam_url) = &x.key.wam_url {
let id: FileId = x.key.file_id.clone().into();
let def_map = db.def_map(id);
let record_name = Name::from_erlang_service(&x.key.name);
if let Some(def) = def_map.get_record(&record_name) {
let range = def.source(db).syntax().text_range();
let text = &db.file_text(id)[range];
let text = format!("```erlang\n{text}\n```");
let doc = format!("[WAM]({})\n{}", wam_url, text);
let decl = Declaration::RecordDeclaration(
RecordDecl {
name: x.key.name.clone(),
span: xref.source.clone(),
}
.into(),
);
let doc_decl = Declaration::DocDeclaration(
DocDecl {
target: Box::new(decl.clone()),
span: xref.source.clone(),
text: doc,
}
.into(),
);
file_decl.declarations.push(decl);
file_decl.declarations.push(doc_decl);
x.key.file_id = file_id.into();
}
}
}
_ => (),
}
}
@ -988,16 +1153,12 @@ impl GleanIndexer {
file_id: FileId,
path: &VfsPath,
project_id: ProjectId,
prefix: Option<&String>,
) -> Option<FileFact> {
let project_data = db.project_data(project_id);
let root = project_data.root_dir.as_path();
let file_path = path.as_path()?;
let file_path = file_path.strip_prefix(root)?;
let file_path = match prefix {
Some(prefix) => Path::new(&prefix).join(file_path).to_str()?.into(),
None => file_path.as_str().to_string(),
};
let file_path = file_path.as_str().to_string();
Some(FileFact::new(file_id, file_path))
}
@ -1371,7 +1532,7 @@ impl GleanIndexer {
}) => {
let def = macro_def.as_ref()?;
let mut resolved = Self::resolve_macro_v2(sema, def, source_file, ctx)?;
// @fb-only
// @fb-only: meta_only::resolve_macro_expansion(sema, *expansion, ctx, &mut resolved);
Some(resolved)
}
hir::AnyExpr::Pat(Pat::MacroCall { macro_def, .. })
@ -1399,7 +1560,7 @@ impl GleanIndexer {
vars: FxHashMap<&Location, &String>,
) -> Vec<VarDecl> {
let mut result = vec![];
if !db.is_eqwalizer_enabled(file_id, false) {
if !db.is_eqwalizer_enabled(file_id) {
return result;
}
let module_diagnostics = db.eqwalizer_diagnostics_by_project(project_id, vec![file_id]);
@ -1619,6 +1780,8 @@ impl GleanIndexer {
arity: define.name.arity(),
expansion,
ods_url: None,
logview_url: None,
scuba_urls: None,
};
Some(XRef {
source: range.into(),
@ -1711,12 +1874,19 @@ impl GleanIndexer {
let (_, _, expr_source) = ctx.body_with_expr_source(sema)?;
let source_file = sema.parse(file_id);
let range = Self::find_range(sema, ctx, &source_file, &expr_source)?;
// @fb-only: use elp_ide::meta_only::wam_links;
// @fb-only: let wam_ctx = wam_links::WamEventCtx::new(sema.db.upcast());
// @fb-only: let wam_url = wam_ctx.build_wam_link(name).map(|link| link.url());
let wam_url = None; // @oss-only
Some(XRef {
source: range.into(),
target: XRefTarget::Record(
RecordTarget {
file_id: def.file.file_id.into(),
name: def.record.name.to_string(),
wam_url,
}
.into(),
),
@ -1801,22 +1971,22 @@ mod tests {
start: 0,
length: 10,
};
let module = "smax_product_catalog";
let name = "product_visibility_update_request_iq";
let module_name = "test_module";
let func_name = "test_function";
let arity = 0;
let file_facts = vec![
FileFact::new(
file_id,
"/local/whatsapp/server/erl/groupd_service/test/p13n/grpd_p13n_new_create_group_SUITE.erl".into(),
)
];
let file_facts = vec![FileFact::new(
file_id,
"/test/app/src/test_module.erl".into(),
)];
let file_line_facts = vec![FileLinesFact::new(file_id, vec![71, 42], true)];
let decl = FileDeclaration {
file_id: file_id.into(),
declarations: vec![Declaration::FunctionDeclaration(
FuncDecl {
name: name.to_string(),
name: func_name.to_string(),
arity,
span: location.clone(),
exported: false,
@ -1825,6 +1995,7 @@ mod tests {
.into(),
)],
};
let xref = XRefFile {
file_id: file_id.into(),
xrefs: vec![XRef {
@ -1832,7 +2003,7 @@ mod tests {
target: XRefTarget::Function(
FunctionTarget {
file_id: file_id.into(),
name: name.to_string(),
name: func_name.to_string(),
arity,
}
.into(),
@ -1840,11 +2011,22 @@ mod tests {
}],
};
let module = ModuleFact {
file_id: file_id.into(),
name: module_name.to_string(),
oncall: Some("test_team".to_string()),
exports: Some(vec![format!("{func_name}/{arity}")]),
behaviours: Some(vec!["test_behaviour".to_string()]),
module_doc: Some("Test module documentation".to_string()),
exdoc_link: Some("https://example.com/docs/test_module.html".to_string()),
};
let facts = IndexedFacts {
file_facts,
file_line_facts,
declaration_facts: vec![],
xref_facts: vec![],
module_facts: vec![module],
file_declarations: vec![decl],
xref_v2: vec![xref],
};
@ -1857,16 +2039,14 @@ mod tests {
v2: true,
pretty: false,
multi: false,
prefix: None,
};
let mut module_index = FxHashMap::default();
module_index.insert(file_id.into(), module.to_string());
module_index.insert(file_id.into(), module_name.to_string());
write_results(map, module_index, &mut cli, &args).expect("success");
let (out, err) = cli.to_strings();
let expected = expect_file!["../resources/test/glean/serialization_test.out"];
expected.assert_eq(&out);
assert_eq!(expected.data().trim(), &out);
assert_eq!(err, "")
}
@ -1885,25 +2065,6 @@ mod tests {
);
}
#[test]
fn file_fact_prefix_test() {
let spec = r#"
//- /glean/app_glean/src/glean_module2.erl
-module(glean_module2).
"#;
let config = IndexConfig {
multi: false,
prefix: Some("my/prefix".to_string()),
};
let result = facts_with_annotations_with_config(spec, config).0;
assert_eq!(result.file_facts.len(), 1);
let file_fact = &result.file_facts[0];
assert_eq!(
file_fact.file_path.as_str(),
"my/prefix/glean/app_glean/src/glean_module2.erl"
);
}
#[test]
fn line_fact_with_new_line_test() {
let spec = r#"
@ -2174,10 +2335,10 @@ mod tests {
fn xref_types_test() {
let spec = r#"
//- /glean/app_glean/src/glean_module81.erl
-type small() :: #{non_neg_integer() | infinity}.
-type small() :: {non_neg_integer() | infinity}.
//- /glean/app_glean/src/glean_module8.erl
-type huuuge() :: #{non_neg_integer() | infinity}.
-type huuuge() :: {non_neg_integer() | infinity}.
-spec baz(
A :: huuuge(),
%% ^^^^^^ glean_module8/huuuge/0
@ -2232,10 +2393,10 @@ mod tests {
fn xref_types_v2_test() {
let spec = r#"
//- /glean/app_glean/src/glean_module81.erl
-type small() :: #{non_neg_integer() | infinity}.
-type small() :: {non_neg_integer() | infinity}.
//- /glean/app_glean/src/glean_module8.erl
-type huuuge() :: #{non_neg_integer() | infinity}.
-type huuuge() :: {non_neg_integer() | infinity}.
-spec baz(
A :: huuuge(),
%% ^^^^^^ glean_module8.erl/type/huuuge/0
@ -2274,7 +2435,7 @@ mod tests {
}).
baz(A) ->
#query{ size = A }.
%% ^^^^^^ glean_module9.erl/rec/query
%% ^^^^^^ glean_module9.erl/rec/query/no_wam
"#;
xref_v2_check(spec);
@ -2304,9 +2465,9 @@ mod tests {
-record(stats, {count, time}).
baz(Time) ->
[{#stats.count, 1},
%% ^^^^^^ glean_module10.erl/rec/stats
%% ^^^^^^ glean_module10.erl/rec/stats/no_wam
{#stats.time, Time}].
%% ^^^^^^ glean_module10.erl/rec/stats
%% ^^^^^^ glean_module10.erl/rec/stats/no_wam
"#;
@ -2335,7 +2496,7 @@ mod tests {
-record(stats, {count, time}).
baz(Stats) ->
Stats#stats.count.
%% ^^^^^^ glean_module11.erl/rec/stats
%% ^^^^^^ glean_module11.erl/rec/stats/no_wam
"#;
xref_v2_check(spec);
@ -2363,7 +2524,7 @@ mod tests {
-record(stats, {count, time}).
baz(Stats, NewCnt) ->
Stats#stats{count = NewCnt}.
%% ^^^^^^ glean_module12.erl/rec/stats
%% ^^^^^^ glean_module12.erl/rec/stats/no_wam
"#;
xref_v2_check(spec);
@ -2393,7 +2554,7 @@ mod tests {
-record(stats, {count, time}).
baz(Stats) ->
#stats{count = Count, time = Time} = Stats.
%% ^^^^^^ glean_module13.erl/rec/stats
%% ^^^^^^ glean_module13.erl/rec/stats/no_wam
"#;
xref_v2_check(spec);
@ -2417,7 +2578,7 @@ mod tests {
//- /glean/app_glean/src/glean_module14.erl
-record(rec, {field}).
foo(#rec.field) -> ok.
%% ^^^^ glean_module14.erl/rec/rec
%% ^^^^ glean_module14.erl/rec/rec/no_wam
"#;
xref_v2_check(spec);
@ -2443,10 +2604,10 @@ mod tests {
//- /glean/app_glean/src/glean_module15.erl
-record(stats, {count, time}).
-spec baz() -> #stats{}.
%% ^^^^^^ glean_module15.erl/rec/stats
%% ^^^^^^ glean_module15.erl/rec/stats/no_wam
baz() ->
#stats{count = 1, time = 2}.
%% ^^^^^^ glean_module15.erl/rec/stats
%% ^^^^^^ glean_module15.erl/rec/stats/no_wam
"#;
xref_v2_check(spec);
@ -2467,25 +2628,12 @@ mod tests {
baz(1) -> ?TAU;
%% ^^^ macro.erl/macro/TAU/117/no_ods/6.28
baz(N) -> ?MAX(N, 200).
%% ^^^ macro.erl/macro/MAX/137/no_ods/if (N > 200) -> N; 'true' -> 200 end
%% ^^^ macro.erl/macro/MAX/137/no_ods/if (N > 200) -> N; true -> 200 end
"#;
xref_v2_check(spec);
}
#[test]
fn xref_macro_ods_v2_test() {
let spec = r#"
//- /src/macro.erl
-module(macro).
-define(COUNT_INFRA(X), wa_stats_counter:count(X)).
baz(atom) -> ?COUNT_INFRA(atom),
%% ^^^^^^^^^^^ macro.erl/macro/COUNT_INFRA/94/has_ods/'wa_stats_counter':'count'( 'atom' )
"#;
// @fb-only
}
#[test]
fn xref_macro_in_pat_v2_test() {
let spec = r#"
@ -2508,7 +2656,7 @@ mod tests {
-define(TYPE, integer()).
-spec baz(ok) -> ?TYPE.
%% ^^^^ macro.erl/macro/TYPE/73/no_ods/'erlang':'integer'()
%% ^^^^ macro.erl/macro/TYPE/73/no_ods/erlang:integer()
baz(ok) -> 1.
"#;
@ -2522,14 +2670,114 @@ mod tests {
-module(macro).
-define(FOO(X), X).
-wild(?FOO(atom)).
%% ^^^ macro.erl/macro/FOO/53/no_ods/'atom'
%% ^^^ macro.erl/macro/FOO/53/no_ods/atom
"#;
xref_v2_check(spec);
}
#[test]
fn module_fact_test() {
let spec = r#"
//- /src/sample_worker.erl
%%% This is a module documentation
%%% It explains what this module does
-module(sample_worker).
-oncall("platform_team").
-behaviour(test_behaviour).
-export([init/1, handle_task/2]).
init(Args) -> {ok, Args}.
handle_task(Task, State) -> {reply, ok, State}.
internal_helper(X) -> X + 1.
"#;
let (facts, _, _, _, _) = facts_with_annotations(spec);
assert_eq!(facts.module_facts.len(), 1);
let module_fact = &facts.module_facts[0];
assert_eq!(module_fact.name, "sample_worker");
assert_eq!(module_fact.oncall, Some("platform_team".to_string()));
assert_eq!(
module_fact.behaviours,
Some(vec!["test_behaviour".to_string()])
);
assert_eq!(module_fact.exports.as_ref().map(|v| v.len()), Some(2));
for expected in ["handle_task/2", "init/1"] {
assert!(
module_fact
.exports
.as_ref()
.unwrap()
.contains(&expected.to_string())
);
}
assert!(module_fact.module_doc.is_none());
}
#[test]
fn module_fact_multiple_behaviours_test() {
let spec = r#"
//- /src/factory_service.erl
-module(factory_service).
-oncall("manufacturing_team").
-behaviour(supervisor).
-behaviour(test_behaviour1).
-behaviour(test_behaviour2).
start_supervision() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
create_product(Type, Config) -> test_behaviour1:produce(Type, Config).
manage_assembly(Parts) -> test_behaviour2:assemble(Parts).
"#;
let (facts, _, _, _, _) = facts_with_annotations(spec);
assert_eq!(facts.module_facts.len(), 1);
let module_fact = &facts.module_facts[0];
assert_eq!(module_fact.name, "factory_service");
assert_eq!(module_fact.oncall, Some("manufacturing_team".to_string()));
assert_eq!(module_fact.behaviours.as_ref().map(|v| v.len()), Some(3));
for expected in ["test_behaviour1", "test_behaviour2", "supervisor"] {
assert!(
module_fact
.behaviours
.as_ref()
.unwrap()
.contains(&expected.to_string())
);
}
assert!(module_fact.exports.is_none());
assert!(module_fact.module_doc.is_none());
}
#[test]
fn module_fact_no_oncall_test() {
let spec = r#"
//- /src/utility_helper.erl
-module(utility_helper).
-behaviour(supervisor).
-export([start_link/0, add_child/2]).
start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
add_child(ChildSpec, Opts) -> supervisor:start_child(?MODULE, {ChildSpec, Opts}).
"#;
let (facts, _, _, _, _) = facts_with_annotations(spec);
assert_eq!(facts.module_facts.len(), 1);
let module_fact = &facts.module_facts[0];
assert_eq!(module_fact.name, "utility_helper");
assert_eq!(module_fact.oncall, None);
assert_eq!(module_fact.behaviours, Some(vec!["supervisor".to_string()]));
assert_eq!(module_fact.exports.as_ref().map(|v| v.len()), Some(2));
for expected in ["add_child/2", "start_link/0"] {
assert!(
module_fact
.exports
.as_ref()
.unwrap()
.contains(&expected.to_string())
);
}
assert!(module_fact.module_doc.is_none());
}
#[allow(clippy::type_complexity)]
fn facts_with_annotations(
pub(crate) fn facts_with_annotations(
spec: &str,
) -> (
IndexedFacts,
@ -2623,7 +2871,7 @@ mod tests {
}
#[track_caller]
fn xref_v2_check(spec: &str) {
pub(crate) fn xref_v2_check(spec: &str) {
let (facts, mut expected_by_file, file_names, _d, _) = facts_with_annotations(spec);
for xref_fact in facts.xref_v2 {
let file_id = xref_fact.file_id;
@ -2818,9 +3066,15 @@ mod tests {
Some(arity) => arity.to_string(),
None => "no_arity".to_string(),
};
let ods_link = match &xref.key.ods_url {
Some(_) => "has_ods",
None => "no_ods",
let ods_link = match (
&xref.key.ods_url,
&xref.key.logview_url,
&xref.key.scuba_urls,
) {
(Some(_), _, _) => "has_ods",
(None, Some(_), _) => "has_logview",
(None, None, Some(_)) => "has_scuba",
(None, None, None) => "no_ods",
};
let exp = match &xref.key.expansion {
Some(exp) => exp
@ -2838,7 +3092,13 @@ mod tests {
)
}
XRefTarget::Header(_) => f.write_str("header"),
XRefTarget::Record(xref) => f.write_str(format!("rec/{}", xref.key.name).as_str()),
XRefTarget::Record(xref) => {
let wam_link = match &xref.key.wam_url {
Some(_) => "has_wam",
None => "no_wam",
};
f.write_str(format!("rec/{}/{}", xref.key.name, wam_link).as_str())
}
XRefTarget::Type(xref) => {
f.write_str(format!("type/{}/{}", xref.key.name, xref.key.arity).as_str())
}

View file

@ -13,16 +13,19 @@ use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::str;
use std::sync::Arc;
use std::thread;
use std::time::SystemTime;
use anyhow::Result;
use anyhow::bail;
use crossbeam_channel::unbounded;
use elp::build::load;
use elp::build::types::LoadResult;
use elp::cli::Cli;
use elp::convert;
use elp::memory_usage::MemoryUsage;
use elp::otp_file_to_ignore;
use elp::read_lint_config_file;
use elp_eqwalizer::Mode;
@ -50,16 +53,16 @@ use elp_ide::elp_ide_db::elp_base_db::ProjectId;
use elp_ide::elp_ide_db::elp_base_db::Vfs;
use elp_ide::elp_ide_db::elp_base_db::VfsPath;
use elp_ide::elp_ide_db::source_change::SourceChange;
use elp_ide_db::text_edit::TextSize;
use elp_log::telemetry;
use elp_project_model::AppName;
use elp_project_model::AppType;
use elp_project_model::DiscoverConfig;
use elp_project_model::buck::BuckQueryConfig;
use elp_text_edit::TextSize;
use fxhash::FxHashMap;
use fxhash::FxHashSet;
use hir::FormIdx;
use hir::InFile;
use indicatif::ParallelProgressIterator;
use itertools::Itertools;
use paths::Utf8PathBuf;
use rayon::prelude::ParallelBridge;
@ -67,12 +70,16 @@ use rayon::prelude::ParallelIterator;
use crate::args::Lint;
use crate::reporting;
use crate::reporting::print_memory_usage;
pub fn run_lint_command(
args: &Lint,
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
) -> Result<()> {
let start_time = SystemTime::now();
let memory_start = MemoryUsage::now();
if let Some(to) = &args.to {
fs::create_dir_all(to)?
};
@ -82,8 +89,22 @@ pub fn run_lint_command(
// We load the project after loading config, in case it bails with
// errors. No point wasting time if the config is wrong.
let mut loaded = load_project(args, cli, query_config)?;
telemetry::report_elapsed_time("lint operational", start_time);
do_codemod(cli, &mut loaded, &diagnostics_config, args)
let result = do_codemod(cli, &mut loaded, &diagnostics_config, args);
telemetry::report_elapsed_time("lint done", start_time);
let memory_end = MemoryUsage::now();
let memory_used = memory_end - memory_start;
// Print memory usage at the end if requested and format is normal
if args.is_format_normal() && args.report_system_stats {
print_memory_usage(loaded.analysis_host, loaded.vfs, cli)?;
writeln!(cli, "{}", memory_used)?;
}
result
}
fn get_and_report_diagnostics_config(args: &Lint, cli: &mut dyn Cli) -> Result<DiagnosticsConfig> {
@ -94,7 +115,7 @@ fn get_and_report_diagnostics_config(args: &Lint, cli: &mut dyn Cli) -> Result<D
Ok(diagnostics_config)
}
fn load_project(
pub fn load_project(
args: &Lint,
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
@ -111,47 +132,101 @@ fn load_project(
)
}
fn do_parse_all(
cli: &dyn Cli,
fn do_diagnostics_all(
cli: &mut dyn Cli,
analysis: &Analysis,
project_id: &ProjectId,
config: &DiagnosticsConfig,
args: &Lint,
) -> Result<Vec<(String, FileId, DiagnosticCollection)>> {
loaded: &LoadResult,
module: &Option<String>,
) -> Result<(Vec<(String, FileId, DiagnosticCollection)>, bool, bool)> {
let module_index = analysis.module_index(*project_id).unwrap();
let module_iter = module_index.iter_own();
let ignored_apps: FxHashSet<Option<Option<AppName>>> = args
.ignore_apps
.iter()
.map(|name| Some(Some(AppName(name.to_string()))))
.collect();
let pb = cli.progress(module_iter.len() as u64, "Parsing modules");
let app_name = args.app.as_ref().map(|name| AppName(name.to_string()));
Ok(module_iter
.par_bridge()
.progress_with(pb)
.map_with(
analysis.clone(),
|db, (module_name, _file_source, file_id)| {
if !otp_file_to_ignore(db, file_id)
&& db.file_app_type(file_id).ok() != Some(Some(AppType::Dep))
&& !ignored_apps.contains(&db.file_app_name(file_id).ok())
&& (app_name.is_none()
|| db.file_app_name(file_id).ok().as_ref() == Some(&app_name))
{
do_parse_one(db, config, file_id, module_name.as_str(), args).unwrap()
} else {
None
}
},
)
.flatten()
.collect())
// Create a channel for streaming results
let (tx, rx) = unbounded();
// Collect modules into an owned vector
let modules: Vec<_> = module_index
.iter_own()
.map(|(name, source, file_id)| (name.as_str().to_string(), source, file_id))
.collect();
let analysis_clone = analysis.clone();
let config_clone = config.clone();
let args_clone = args.clone();
let join_handle = thread::spawn(move || {
modules
.into_iter()
.par_bridge()
.map_with(
(analysis_clone, tx),
|(db, tx), (module_name, _file_source, file_id)| {
if !otp_file_to_ignore(db, file_id)
&& db.file_app_type(file_id).ok() != Some(Some(AppType::Dep))
&& !ignored_apps.contains(&db.file_app_name(file_id).ok())
&& (app_name.is_none()
|| db.file_app_name(file_id).ok().as_ref() == Some(&app_name))
&& let Ok(Some(result)) = do_diagnostics_one(
db,
&config_clone,
file_id,
&module_name,
&args_clone,
)
{
// Send result through channel
let _ = tx.send(result);
}
},
)
.for_each(|_| {}); // Consume the iterator
});
// Collect results as they arrive from the channel
let mut results = Vec::new();
let mut err_in_diag = false;
let mut module_count = 0;
let mut any_diagnostics_printed = false;
for result in rx {
let printed = if args.skip_stream_print() {
false
} else {
print_diagnostic_result(
cli,
analysis,
config,
args,
loaded,
module,
&mut err_in_diag,
&mut module_count,
&result,
)?
};
any_diagnostics_printed = any_diagnostics_printed || printed;
results.push(result);
}
// Wait for the thread to complete before returning
// This ensures that analysis_clone is dropped and its read lock is released
join_handle
.join()
.expect("Failed to join diagnostics thread");
Ok((results, err_in_diag, any_diagnostics_printed))
}
fn do_parse_one(
fn do_diagnostics_one(
db: &Analysis,
config: &DiagnosticsConfig,
file_id: FileId,
@ -218,6 +293,8 @@ pub fn do_codemod(
) -> Result<()> {
// Declare outside the block so it has the right lifetime for filter_diagnostics
let res;
let streamed_err_in_diag;
let mut any_diagnostics_printed = false;
let mut initial_diags = {
// We put this in its own block so that analysis is
// freed before we apply lints. To apply lints
@ -258,7 +335,18 @@ pub fn do_codemod(
res = match (file_id, name) {
(None, _) => {
do_parse_all(cli, &analysis, &loaded.project_id, diagnostics_config, args)?
let (results, err_in_diag, any_printed) = do_diagnostics_all(
cli,
&analysis,
&loaded.project_id,
diagnostics_config,
args,
loaded,
&args.module,
)?;
streamed_err_in_diag = err_in_diag;
any_diagnostics_printed = any_printed;
results
}
(Some(file_id), Some(name)) => {
if let Some(app) = &args.app
@ -267,87 +355,124 @@ pub fn do_codemod(
{
panic!("Module {} does not belong to app {}", name.as_str(), app)
}
do_parse_one(&analysis, diagnostics_config, file_id, &name, args)?
.map_or(vec![], |x| vec![x])
let result =
do_diagnostics_one(&analysis, diagnostics_config, file_id, &name, args)?
.map_or(vec![], |x| vec![x]);
// Print diagnostics for the single file
let mut err_in_diag = false;
let mut module_count = 0;
if args.skip_stream_print() {
any_diagnostics_printed = false;
} else {
for r in &result {
let printed = print_diagnostic_result(
cli,
&analysis,
diagnostics_config,
args,
loaded,
&args.module,
&mut err_in_diag,
&mut module_count,
r,
)?;
any_diagnostics_printed = any_diagnostics_printed || printed;
}
}
streamed_err_in_diag = err_in_diag;
result
}
(Some(file_id), _) => {
panic!("Could not get name from file_id for {file_id:?}")
}
};
filter_diagnostics(
&analysis,
&args.module,
Some(&diagnostics_config.enabled),
&res,
&FxHashSet::default(),
)?
res
};
if initial_diags.is_empty() {
if args.is_format_normal() {
writeln!(cli, "No diagnostics reported")?;
}
} else {
initial_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b));
let mut err_in_diag = false;
if args.is_format_json() {
for (_name, file_id, diags) in &initial_diags {
if args.print_diags {
for diag in diags {
// We use JSON output for CI, and want to see warnings too.
// So do not filter on errors only
err_in_diag = true;
let vfs_path = loaded.vfs.file_path(*file_id);
let analysis = loaded.analysis();
let root_path = &analysis
.project_data(*file_id)
.unwrap_or_else(|_err| panic!("could not find project data"))
.unwrap_or_else(|| panic!("could not find project data"))
.root_dir;
let relative_path = reporting::get_relative_path(root_path, vfs_path);
let prefix = args.prefix.as_ref();
print_diagnostic_json(
diag,
&analysis,
*file_id,
with_prefix(relative_path, prefix).as_path(),
args.use_cli_severity,
cli,
)?;
}
}
}
} else {
writeln!(
cli,
"Diagnostics reported in {} modules:",
initial_diags.len()
)?;
let mut err_in_diag = streamed_err_in_diag;
// At this point, the analysis variable from above is dropped
for (name, file_id, diags) in &initial_diags {
writeln!(cli, " {}: {}", name, diags.len())?;
if args.print_diags {
for diag in diags {
if let diagnostics::Severity::Error = diag.severity {
err_in_diag = true;
};
print_diagnostic(
diag,
&loaded.analysis(),
*file_id,
args.use_cli_severity,
cli,
)?;
}
}
}
// When streaming is disabled (--no-stream) and we're not applying fixes,
// we need to print diagnostics now since they weren't printed during streaming
if args.no_stream && !args.apply_fix && !initial_diags.is_empty() {
let analysis = loaded.analysis();
let mut module_count = 0;
initial_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b));
for result in &initial_diags {
let printed = print_diagnostic_result(
cli,
&analysis,
diagnostics_config,
args,
loaded,
&args.module,
&mut err_in_diag,
&mut module_count,
result,
)?;
any_diagnostics_printed = any_diagnostics_printed || printed;
}
if args.apply_fix && diagnostics_config.enabled.all_enabled() {
}
// Handle apply_fix case separately since it needs to filter diagnostics anyway
if args.apply_fix {
if diagnostics_config.enabled.all_enabled() {
bail!(
"We cannot apply fixes if all diagnostics enabled. Perhaps provide --diagnostic-filter"
);
}
if args.apply_fix && !diagnostics_config.enabled.all_enabled() {
let mut filtered_diags = {
let analysis = loaded.analysis();
filter_diagnostics(
&analysis,
&args.module,
Some(&diagnostics_config.enabled),
&initial_diags,
&FxHashSet::default(),
)?
};
if filtered_diags.is_empty() {
if args.is_format_normal() {
writeln!(cli, "No diagnostics reported")?;
}
} else {
if args.skip_stream_print() {
filtered_diags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b));
let module_count: &mut i32 = &mut 0;
let has_diagnostics: &mut bool = &mut false;
if args.is_format_json() {
do_print_diagnostics_json_filtered(
cli,
args,
loaded,
&mut err_in_diag,
module_count,
has_diagnostics,
&filtered_diags,
)?;
} else {
{
// Scope the analysis instance to ensure it's dropped before creating Lints
let analysis = loaded.analysis();
do_print_diagnostics_filtered(
cli,
&analysis,
args,
loaded,
&mut err_in_diag,
module_count,
has_diagnostics,
&filtered_diags,
)?;
// Analysis is dropped here
}
}
}
let mut changed_files = FxHashSet::default();
let mut lints = Lints::new(
&mut loaded.analysis_host,
@ -355,7 +480,7 @@ pub fn do_codemod(
&mut loaded.vfs,
args,
&mut changed_files,
initial_diags,
filtered_diags,
);
// We handle the fix application result here, so
// the overall status of whether error-severity
@ -367,20 +492,232 @@ pub fn do_codemod(
writeln!(cli, "Apply fix failed: {err:#}").ok();
}
};
if err_in_diag {
bail!("Errors found")
}
}
if err_in_diag {
} else {
// Non-apply-fix case: rely on any_diagnostics_printed which is set
// correctly based on filtered diagnostics during streaming/batch printing
if !any_diagnostics_printed {
if args.is_format_normal() {
writeln!(cli, "No diagnostics reported")?;
}
} else if err_in_diag {
bail!("Errors found")
}
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn print_diagnostic_result(
cli: &mut dyn Cli,
analysis: &Analysis,
config: &DiagnosticsConfig,
args: &Lint,
loaded: &LoadResult,
module: &Option<String>,
err_in_diag: &mut bool,
module_count: &mut i32,
result: &(String, FileId, DiagnosticCollection),
) -> Result<bool> {
if args.is_format_json() {
do_print_diagnostic_collection_json(
cli,
analysis,
config,
args,
loaded,
module,
err_in_diag,
module_count,
result,
)
} else {
do_print_diagnostic_collection(
cli,
analysis,
config,
args,
loaded,
module,
err_in_diag,
module_count,
result,
)
}
}
#[allow(clippy::too_many_arguments)]
fn do_print_diagnostic_collection(
cli: &mut dyn Cli,
analysis: &Analysis,
config: &DiagnosticsConfig,
args: &Lint,
loaded: &LoadResult,
module: &Option<String>,
err_in_diag: &mut bool,
module_count: &mut i32,
result: &(String, FileId, DiagnosticCollection),
) -> Result<bool> {
let single_result = vec![result.clone()];
let mut has_diagnostics = false;
if let Ok(filtered) = filter_diagnostics(
analysis,
module,
Some(&config.enabled),
&single_result,
&FxHashSet::default(),
) {
do_print_diagnostics_filtered(
cli,
analysis,
args,
loaded,
err_in_diag,
module_count,
&mut has_diagnostics,
&filtered,
)?;
}
Ok(has_diagnostics)
}
#[allow(clippy::too_many_arguments)]
fn do_print_diagnostics_filtered(
cli: &mut dyn Cli,
analysis: &Analysis,
args: &Lint,
loaded: &LoadResult,
err_in_diag: &mut bool,
module_count: &mut i32,
has_diagnostics: &mut bool,
filtered: &[(String, FileId, Vec<diagnostics::Diagnostic>)],
) -> Result<(), anyhow::Error> {
let _: () = for (name, file_id, diags) in filtered {
if !diags.is_empty() {
*has_diagnostics = true;
if *module_count == 0 {
writeln!(cli, "Diagnostics reported:")?;
}
*module_count += 1;
if !args.print_diags {
writeln!(cli, " {}: {}", name, diags.len())?;
} else {
for diag in diags {
if let diagnostics::Severity::Error = diag.severity {
*err_in_diag = true;
};
// Get relative path for diagnostic output
let vfs_path = loaded.vfs.file_path(*file_id);
let root_path = &analysis
.project_data(*file_id)
.unwrap_or_else(|_err| panic!("could not find project data"))
.unwrap_or_else(|| panic!("could not find project data"))
.root_dir;
let relative_path = reporting::get_relative_path(root_path, vfs_path);
print_diagnostic(
diag,
analysis,
&loaded.vfs,
*file_id,
Some(relative_path),
args.use_cli_severity,
cli,
)?;
}
}
}
};
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn do_print_diagnostic_collection_json(
cli: &mut dyn Cli,
analysis: &Analysis,
config: &DiagnosticsConfig,
args: &Lint,
loaded: &LoadResult,
module: &Option<String>,
err_in_diag: &mut bool,
module_count: &mut i32,
result: &(String, FileId, DiagnosticCollection),
) -> Result<bool> {
let single_result = vec![result.clone()];
let mut has_diagnostics = false;
if let Ok(filtered) = filter_diagnostics(
analysis,
module,
Some(&config.enabled),
&single_result,
&FxHashSet::default(),
) {
do_print_diagnostics_json_filtered(
cli,
args,
loaded,
err_in_diag,
module_count,
&mut has_diagnostics,
&filtered,
)?;
}
Ok(has_diagnostics)
}
fn do_print_diagnostics_json_filtered(
cli: &mut dyn Cli,
args: &Lint,
loaded: &LoadResult,
err_in_diag: &mut bool,
module_count: &mut i32,
has_diagnostics: &mut bool,
filtered: &[(String, FileId, Vec<diagnostics::Diagnostic>)],
) -> Result<(), anyhow::Error> {
let _: () = for (name, file_id, diags) in filtered {
if !diags.is_empty() {
*has_diagnostics = true;
*module_count += 1;
if !args.print_diags {
writeln!(cli, " {}: {}", name, diags.len())?;
} else {
for diag in diags {
*err_in_diag = true;
// Get relative path for diagnostic output
let vfs_path = loaded.vfs.file_path(*file_id);
let analysis = loaded.analysis();
let root_path = &analysis
.project_data(*file_id)
.unwrap_or_else(|_err| panic!("could not find project data"))
.unwrap_or_else(|| panic!("could not find project data"))
.root_dir;
let relative_path = reporting::get_relative_path(root_path, vfs_path);
print_diagnostic_json(
diag,
&analysis,
*file_id,
relative_path,
args.use_cli_severity,
cli,
)?;
}
}
}
};
Ok(())
}
fn get_diagnostics_config(args: &Lint) -> Result<DiagnosticsConfig> {
let cfg_from_file = if args.read_config || args.config_file.is_some() {
read_lint_config_file(&args.project, &args.config_file)?
} else {
LintConfig::default()
};
let cfg = DiagnosticsConfig::default()
.configure_diagnostics(
&cfg_from_file,
@ -399,12 +736,82 @@ fn get_diagnostics_config(args: &Lint) -> Result<DiagnosticsConfig> {
fn print_diagnostic(
diag: &diagnostics::Diagnostic,
analysis: &Analysis,
vfs: &Vfs,
file_id: FileId,
path: Option<&Path>,
use_cli_severity: bool,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
let line_index = analysis.line_index(file_id)?;
writeln!(cli, " {}", diag.print(&line_index, use_cli_severity))?;
let diag_str = diag.print(&line_index, use_cli_severity);
if let Some(path) = path {
writeln!(cli, "{}:{}", path.display(), diag_str)?;
} else {
writeln!(cli, " {}", diag_str)?;
}
// Print any related information, indented
if let Some(related_info) = &diag.related_info {
for info in related_info {
let info_line_index = analysis.line_index(info.file_id)?;
let start = info_line_index.line_col(info.range.start());
let end = info_line_index.line_col(info.range.end());
// Include file identifier if related info is from a different file
if info.file_id != file_id {
let file_identifier =
if let Ok(Some(module_name)) = analysis.module_name(info.file_id) {
// It's a module (.erl file), use module name
format!("[{}]", module_name.as_str())
} else {
// Not a module (e.g., include file), use relative path
let vfs_path = vfs.file_path(info.file_id);
if let Ok(Some(project_data)) = analysis.project_data(info.file_id) {
let relative_path =
reporting::get_relative_path(&project_data.root_dir, vfs_path);
format!("[{}]", relative_path.display())
} else {
// Fallback: just show location without file identifier
String::new()
}
};
if file_identifier.is_empty() {
writeln!(
cli,
" {}:{}-{}:{}: {}",
start.line + 1,
start.col_utf16 + 1,
end.line + 1,
end.col_utf16 + 1,
info.message
)?;
} else {
writeln!(
cli,
" {} {}:{}-{}:{}: {}",
file_identifier,
start.line + 1,
start.col_utf16 + 1,
end.line + 1,
end.col_utf16 + 1,
info.message
)?;
}
} else {
writeln!(
cli,
" {}:{}-{}:{}: {}",
start.line + 1,
start.col_utf16 + 1,
end.line + 1,
end.col_utf16 + 1,
info.message
)?;
}
}
}
Ok(())
}
@ -589,13 +996,10 @@ impl<'a> Lints<'a> {
if self.args.check_eqwalize_all {
writeln!(cli, "Running eqwalize-all to check for knock-on problems.")?;
}
let diags = do_parse_one(
&self.analysis_host.analysis(),
self.cfg,
file_id,
&name,
self.args,
)?;
let diags = {
let analysis = self.analysis_host.analysis();
do_diagnostics_one(&analysis, self.cfg, file_id, &name, self.args)?
};
let err_in_diags = diags.iter().any(|(_, file_id, diags)| {
let diags = diags.diagnostics_for(*file_id);
diags
@ -606,14 +1010,15 @@ impl<'a> Lints<'a> {
bail!("Applying change introduces an error diagnostic");
} else {
self.changed_files.insert((file_id, name.clone()));
let changes = changes
.iter()
.filter_map(|d| {
form_from_diff(&self.analysis_host.analysis(), file_id, d)
})
.collect::<Vec<_>>();
let changed_forms = {
let analysis = self.analysis_host.analysis();
changes
.iter()
.filter_map(|d| form_from_diff(&analysis, file_id, d))
.collect::<Vec<_>>()
};
for form_id in &changes {
for form_id in &changed_forms {
self.changed_forms.insert(InFile::new(file_id, *form_id));
}
@ -626,24 +1031,24 @@ impl<'a> Lints<'a> {
.flatten()
.collect::<Vec<_>>();
let new_diagnostics = filter_diagnostics(
&self.analysis_host.analysis(),
&None,
None,
&new_diags,
&self.changed_forms,
)?;
let new_diagnostics = {
let analysis = self.analysis_host.analysis();
filter_diagnostics(&analysis, &None, None, &new_diags, &self.changed_forms)?
};
self.diags = diagnostics_by_file_id(&new_diagnostics);
if !self.diags.is_empty() {
writeln!(cli, "---------------------------------------------\n")?;
writeln!(cli, "New filtered diagnostics")?;
let analysis = self.analysis_host.analysis();
for (file_id, (name, diags)) in &self.diags {
writeln!(cli, " {}: {}", name, diags.len())?;
for diag in diags.iter() {
print_diagnostic(
diag,
&self.analysis_host.analysis(),
&analysis,
self.vfs,
*file_id,
None,
self.args.use_cli_severity,
cli,
)?;
@ -715,10 +1120,13 @@ impl<'a> Lints<'a> {
if format_normal {
writeln!(cli, "---------------------------------------------\n")?;
writeln!(cli, "Applying fix in module '{name}' for")?;
let analysis = self.analysis_host.analysis();
print_diagnostic(
diagnostic,
&self.analysis_host.analysis(),
&analysis,
self.vfs,
file_id,
None,
self.args.use_cli_severity,
cli,
)?;
@ -785,7 +1193,9 @@ impl<'a> Lints<'a> {
print_diagnostic(
&diagnostic,
&self.analysis_host.analysis(),
self.vfs,
file_id,
None,
self.args.use_cli_severity,
cli,
)?;
@ -920,13 +1330,6 @@ fn get_form_id_at_offset(
Some(form_id)
}
fn with_prefix(path: &Path, prefix: Option<&String>) -> PathBuf {
match prefix {
Some(prefix) => Path::new(prefix).join(path),
None => path.into(),
}
}
#[cfg(test)]
mod tests {
use std::ffi::OsString;
@ -935,6 +1338,7 @@ mod tests {
use elp::cli::Fake;
use elp_ide::FunctionMatch;
use elp_ide::diagnostics::DiagnosticCode;
use elp_ide::diagnostics::ErlangServiceConfig;
use elp_ide::diagnostics::Lint;
use elp_ide::diagnostics::LintsFromConfig;
use elp_ide::diagnostics::ReplaceCall;
@ -942,6 +1346,7 @@ mod tests {
use elp_ide::diagnostics::Replacement;
use expect_test::Expect;
use expect_test::expect;
use fxhash::FxHashMap;
use super::LintConfig;
use super::do_codemod;
@ -966,12 +1371,19 @@ mod tests {
},
enabled_lints: vec![DiagnosticCode::HeadMismatch],
disabled_lints: vec![],
linters: FxHashMap::default(),
erlang_service: ErlangServiceConfig {
warnings_as_errors: true,
},
})
.unwrap();
expect![[r#"
enabled_lints = ["P1700"]
disabled_lints = []
[erlang_service]
warnings_as_errors = true
[[ad_hoc_lints.lints]]
type = "ReplaceCall"
@ -983,6 +1395,8 @@ mod tests {
[ad_hoc_lints.lints.action]
action = "Replace"
type = "UseOk"
[linters]
"#]]
.assert_eq(&result);
}
@ -1003,9 +1417,13 @@ mod tests {
TrivialMatch,
],
disabled_lints: [],
erlang_service: ErlangServiceConfig {
warnings_as_errors: false,
},
ad_hoc_lints: LintsFromConfig {
lints: [],
},
linters: {},
}
"#]]
.assert_debug_eq(&lint_config);
@ -1051,11 +1469,11 @@ mod tests {
head_mismatcX(0) -> 0.
"#,
expect![[r#"
module specified: lints
Diagnostics reported in 1 modules:
lints: 1
4:2-4:15::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
"#]],
module specified: lints
Diagnostics reported:
app_a/src/lints.erl:5:3-5:16::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
4:3-4:16: Mismatched clause name
"#]],
expect![""],
);
}
@ -1072,9 +1490,8 @@ mod tests {
"#,
expect![[r#"
module specified: lints
Diagnostics reported in 1 modules:
lints: 1
2:2-2:5::[Warning] [L1230] function foo/0 is unused
Diagnostics reported:
app_a/src/lints.erl:3:3-3:6::[Warning] [L1230] function foo/0 is unused
"#]],
expect![""],
);

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@ use elp::cli::Cli;
use elp::convert;
use elp::memory_usage::MemoryUsage;
use elp_ide::Analysis;
use elp_ide::AnalysisHost;
use elp_ide::TextRange;
use elp_ide::elp_ide_db::EqwalizerDiagnostic;
use elp_ide::elp_ide_db::elp_base_db::AbsPath;
@ -38,6 +39,7 @@ use indicatif::ProgressBar;
use itertools::Itertools;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use vfs::Vfs;
pub trait Reporter {
fn write_eqwalizer_diagnostics(
@ -225,8 +227,6 @@ impl Reporter for JsonReporter<'_> {
diagnostics: &[EqwalizerDiagnostic],
) -> Result<()> {
let line_index = self.analysis.line_index(file_id)?;
// Pass include_Tests = false so that errors for tests files that are not opted-in are tagged as arc_types::Severity::Disabled
let eqwalizer_enabled = self.analysis.is_eqwalizer_enabled(file_id, false).unwrap();
let file_path = &self.loaded.vfs.file_path(file_id);
let root_path = &self
.analysis
@ -235,12 +235,8 @@ impl Reporter for JsonReporter<'_> {
.root_dir;
let relative_path = get_relative_path(root_path, file_path);
for diagnostic in diagnostics {
let diagnostic = convert::eqwalizer_to_arc_diagnostic(
diagnostic,
&line_index,
relative_path,
eqwalizer_enabled,
);
let diagnostic =
convert::eqwalizer_to_arc_diagnostic(diagnostic, &line_index, relative_path);
let diagnostic = serde_json::to_string(&diagnostic)?;
writeln!(self.cli, "{diagnostic}")?;
}
@ -258,6 +254,7 @@ impl Reporter for JsonReporter<'_> {
"ELP".to_string(),
diagnostic.msg.clone(),
None,
None,
);
let diagnostic = serde_json::to_string(&diagnostic)?;
writeln!(self.cli, "{diagnostic}")?;
@ -281,6 +278,7 @@ impl Reporter for JsonReporter<'_> {
"ELP".to_string(),
description,
None,
None,
);
let diagnostic = serde_json::to_string(&diagnostic)?;
writeln!(self.cli, "{diagnostic}")?;
@ -376,3 +374,28 @@ pub(crate) fn add_stat(stat: String) {
let mut stats = STATS.lock();
stats.push(stat);
}
pub(crate) fn print_memory_usage(
mut host: AnalysisHost,
vfs: Vfs,
cli: &mut dyn Cli,
) -> Result<()> {
let mem = host.per_query_memory_usage();
let before = profile::memory_usage();
drop(vfs);
let vfs = before.allocated - profile::memory_usage().allocated;
let before = profile::memory_usage();
drop(host);
let unaccounted = before.allocated - profile::memory_usage().allocated;
let remaining = profile::memory_usage().allocated;
for (name, bytes, entries) in mem {
writeln!(cli, "{bytes:>8} {entries:>6} {name}")?;
}
writeln!(cli, "{vfs:>8} VFS")?;
writeln!(cli, "{unaccounted:>8} Unaccounted")?;
writeln!(cli, "{remaining:>8} Remaining")?;
Ok(())
}

View file

@ -15,6 +15,7 @@ use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::sync::Arc;
use std::time::SystemTime;
use anyhow::Result;
use elp::build::load;
@ -29,6 +30,7 @@ use elp_ide::elp_ide_db::elp_base_db::SourceDatabaseExt;
use elp_ide::elp_ide_db::elp_base_db::SourceRoot;
use elp_ide::elp_ide_db::elp_base_db::SourceRootId;
use elp_ide::elp_ide_db::elp_base_db::VfsPath;
use elp_log::telemetry;
use elp_project_model::DiscoverConfig;
use elp_project_model::buck::BuckQueryConfig;
use paths::Utf8PathBuf;
@ -155,10 +157,9 @@ impl ShellCommand {
}
"eqwalize-app" => {
let include_generated = options.contains(&"--include-generated");
let include_tests = options.contains(&"--include-tests");
if let Some(other) = options
.into_iter()
.find(|&opt| opt != "--include-generated" && opt != "--include-tests")
.find(|&opt| opt != "--include-generated")
{
return Err(ShellError::UnexpectedOption(
"eqwalize-app".into(),
@ -175,7 +176,6 @@ impl ShellCommand {
rebar,
app: app.into(),
include_generated,
include_tests,
bail_on_error: false,
})));
}
@ -183,10 +183,9 @@ impl ShellCommand {
}
"eqwalize-all" => {
let include_generated = options.contains(&"--include-generated");
let include_tests = options.contains(&"--include-tests");
if let Some(other) = options
.into_iter()
.find(|&opt| opt != "--include-generated" && opt != "--include-tests")
.find(|&opt| opt != "--include-generated")
{
return Err(ShellError::UnexpectedOption(
"eqwalize-all".into(),
@ -202,7 +201,6 @@ impl ShellCommand {
rebar,
format: None,
include_generated,
include_tests,
bail_on_error: false,
stats: false,
list_modules: false,
@ -224,10 +222,8 @@ COMMANDS:
eqwalize <modules> Eqwalize specified modules
--clause-coverage Use experimental clause coverage checker
eqwalize-all Eqwalize all modules in the current project
--include-tests Also eqwalize test modules from project
--clause-coverage Use experimental clause coverage checker
eqwalize-app <app> Eqwalize all modules in specified application
--include-tests Also eqwalize test modules from project
--clause-coverage Use experimental clause coverage checker
";
@ -331,6 +327,7 @@ fn update_changes(
}
pub fn run_shell(shell: &Shell, cli: &mut dyn Cli, query_config: &BuckQueryConfig) -> Result<()> {
let start_time = SystemTime::now();
let mut cmd = Command::new("watchman");
let _ = cmd.arg("--version").output().map_err(|_| {
anyhow::Error::msg("`watchman` command not found. install it from https://facebook.github.io/watchman/ to use `elp shell`.")
@ -349,6 +346,7 @@ pub fn run_shell(shell: &Shell, cli: &mut dyn Cli, query_config: &BuckQueryConfi
Mode::Shell,
query_config,
)?;
telemetry::report_elapsed_time("shell operational", start_time);
let mut rl = rustyline::DefaultEditor::new()?;
let mut last_read = watchman.get_clock()?;
write!(cli, "{WELCOME}")?;
@ -403,5 +401,6 @@ pub fn run_shell(shell: &Shell, cli: &mut dyn Cli, query_config: &BuckQueryConfi
}
}
}
telemetry::report_elapsed_time("shell done", start_time);
Ok(())
}

View file

@ -0,0 +1,717 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is dual-licensed under either the MIT license found in the
* LICENSE-MIT file in the root directory of this source tree or the Apache
* License, Version 2.0 found in the LICENSE-APACHE file in the root directory
* of this source tree. You may select, at your option, one of the
* above-listed licenses.
*/
use std::fs;
use std::path::Path;
use std::str;
use std::thread;
use std::time::SystemTime;
use anyhow::Result;
use anyhow::bail;
use crossbeam_channel::unbounded;
use elp::build::load;
use elp::build::types::LoadResult;
use elp::cli::Cli;
use elp::convert;
use elp::memory_usage::MemoryUsage;
use elp::otp_file_to_ignore;
use elp_eqwalizer::Mode;
use elp_ide::Analysis;
use elp_ide::AnalysisHost;
use elp_ide::diagnostics;
use elp_ide::diagnostics::DiagnosticsConfig;
use elp_ide::diagnostics::FallBackToAll;
use elp_ide::diagnostics::LintConfig;
use elp_ide::diagnostics::LintsFromConfig;
use elp_ide::diagnostics::MatchSsr;
use elp_ide::elp_ide_db::LineCol;
use elp_ide::elp_ide_db::elp_base_db::AbsPath;
use elp_ide::elp_ide_db::elp_base_db::FileId;
use elp_ide::elp_ide_db::elp_base_db::IncludeOtp;
use elp_ide::elp_ide_db::elp_base_db::ModuleName;
use elp_ide::elp_ide_db::elp_base_db::ProjectId;
use elp_ide::elp_ide_db::elp_base_db::VfsPath;
use elp_log::telemetry;
use elp_project_model::AppName;
use elp_project_model::AppType;
use elp_project_model::DiscoverConfig;
use elp_project_model::buck::BuckQueryConfig;
use hir::Semantic;
use paths::Utf8PathBuf;
use rayon::prelude::ParallelBridge;
use rayon::prelude::ParallelIterator;
use crate::args::Ssr;
use crate::reporting;
use crate::reporting::print_memory_usage;
fn normalize_ssr_pattern(pattern: &str) -> String {
if pattern.starts_with("ssr:") {
pattern.to_string()
} else {
format!("ssr: {}.", pattern)
}
}
pub fn run_ssr_command(
args: &Ssr,
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
use_color: bool,
) -> Result<()> {
let start_time = SystemTime::now();
let memory_start = MemoryUsage::now();
// Validate all SSR patterns early
let analysis_host = AnalysisHost::default();
let analysis = analysis_host.analysis();
for pattern in &args.ssr_specs {
let normalized_pattern = normalize_ssr_pattern(pattern);
match analysis.validate_ssr_pattern(&normalized_pattern) {
Ok(Ok(())) => {}
Ok(Err(e)) => bail!("invalid SSR pattern '{}': {}", pattern, e),
Err(_cancelled) => bail!("SSR pattern validation was cancelled"),
}
}
// Parse the strategy from CLI arguments
let strategy = args.parse_strategy()?;
// Create the lint config with all SSR patterns
let mut lint_config = LintConfig::default();
for pattern in &args.ssr_specs {
let normalized_pattern = normalize_ssr_pattern(pattern);
let severity = if args.dump_config {
// Set the severity so that squiggles are shown in the VS Code UI
Some(diagnostics::Severity::Information)
} else {
None
};
let ssr_lint = diagnostics::Lint::LintMatchSsr(MatchSsr {
ssr_pattern: normalized_pattern,
message: None,
strategy: Some(strategy),
severity,
});
lint_config.ad_hoc_lints.lints.push(ssr_lint);
}
// Build the diagnostics config
let diagnostics_config = DiagnosticsConfig::default()
.configure_diagnostics(
&lint_config,
&Some("ad-hoc: ssr-match".to_string()),
&None,
FallBackToAll::Yes,
)?
.set_include_generated(args.include_generated)
.set_experimental(false)
.set_use_cli_severity(false);
if args.dump_config {
let result = toml::to_string::<LintsFromConfig>(&diagnostics_config.lints_from_config)?;
// This is a subsection of .elp_lint.toml, add subsection prefix
let result = result.replace("[[lints]]", "[[ad_hoc_lints.lints]]");
writeln!(cli, "\n# Add this to your .elp_lint.toml")?;
writeln!(cli, "{}", result)?;
return Ok(());
}
// Load the project
let mut loaded = load_project(args, cli, query_config)?;
telemetry::report_elapsed_time("ssr operational", start_time);
let r = run_ssr(cli, &mut loaded, &diagnostics_config, args, use_color);
telemetry::report_elapsed_time("ssr done", start_time);
let memory_end = MemoryUsage::now();
let memory_used = memory_end - memory_start;
// Print memory usage at the end if requested and format is normal
if args.is_format_normal() && args.report_system_stats {
print_memory_usage(loaded.analysis_host, loaded.vfs, cli)?;
writeln!(cli, "{}", memory_used)?;
}
r
}
pub fn run_ssr(
cli: &mut dyn Cli,
loaded: &mut LoadResult,
diagnostics_config: &DiagnosticsConfig,
args: &Ssr,
use_color: bool,
) -> Result<()> {
let analysis = loaded.analysis();
let (file_id, name) = match &args.module {
Some(module) => match analysis.module_file_id(loaded.project_id, module)? {
Some(file_id) => {
if args.is_format_normal() {
writeln!(cli, "module specified: {module}")?;
}
(Some(file_id), analysis.module_name(file_id)?)
}
None => panic!("Module not found: {module}"),
},
None => match &args.file {
Some(file_name) => {
if args.is_format_normal() {
writeln!(cli, "file specified: {file_name}")?;
}
let path_buf = Utf8PathBuf::from_path_buf(fs::canonicalize(file_name).unwrap())
.expect("UTF8 conversion failed");
let path = AbsPath::assert(&path_buf);
let path = path.as_os_str().to_str().unwrap();
(
loaded
.vfs
.file_id(&VfsPath::new_real_path(path.to_string()))
.map(|(id, _)| id),
path_buf.as_path().file_name().map(ModuleName::new),
)
}
None => (None, None),
},
};
let mut match_count = 0;
match (file_id, name) {
(None, _) => {
// Streaming case: process all modules
let project_id = loaded.project_id;
do_parse_all_streaming(
cli,
&analysis,
&project_id,
diagnostics_config,
args,
use_color,
loaded,
&mut match_count,
)?;
}
(Some(file_id), Some(name)) => {
if let Some(app) = &args.app
&& let Ok(Some(file_app)) = analysis.file_app_name(file_id)
&& file_app != AppName(app.to_string())
{
panic!("Module {} does not belong to app {}", name.as_str(), app)
}
if let Some(diag) = do_parse_one(&analysis, diagnostics_config, file_id, &name, args)? {
match_count = 1;
print_single_result(cli, loaded, &diag, args, use_color)?;
}
}
(Some(file_id), _) => {
panic!("Could not get name from file_id for {file_id:?}")
}
};
if match_count == 0 {
if args.is_format_normal() {
writeln!(cli, "No matches found")?;
}
} else if args.is_format_normal() {
writeln!(cli, "\nMatches found in {} modules", match_count)?;
}
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn do_parse_all_streaming(
cli: &mut dyn Cli,
analysis: &Analysis,
project_id: &ProjectId,
config: &DiagnosticsConfig,
args: &Ssr,
use_color: bool,
loaded: &mut LoadResult,
match_count: &mut usize,
) -> Result<()> {
let module_index = analysis.module_index(*project_id).unwrap();
let app_name = args.app.as_ref().map(|name| AppName(name.to_string()));
// Create a channel for streaming results
let (tx, rx) = unbounded();
// Spawn a thread to process modules in parallel and send results
let analysis_clone = analysis.clone();
let config_clone = config.clone();
let args_clone = args.clone();
// Collect modules into an owned vector
let modules: Vec<_> = module_index
.iter_own()
.map(|(name, source, file_id)| (name.as_str().to_string(), source, file_id))
.collect();
thread::spawn(move || {
modules
.into_iter()
.par_bridge()
.map_with(
(analysis_clone, tx),
|(db, tx), (module_name, _file_source, file_id)| {
if !otp_file_to_ignore(db, file_id)
&& db.file_app_type(file_id).ok() != Some(Some(AppType::Dep))
&& (app_name.is_none()
|| db.file_app_name(file_id).ok().as_ref() == Some(&app_name))
&& let Ok(Some(result)) =
do_parse_one(db, &config_clone, file_id, &module_name, &args_clone)
{
// Send result through channel
let _ = tx.send(result);
}
},
)
.for_each(|_| {}); // Consume the iterator
// Channel is dropped here, signaling end of results
});
// Process and print results as they arrive from the channel
for result in rx {
*match_count += 1;
print_single_result(cli, loaded, &result, args, use_color)?;
}
Ok(())
}
fn print_single_result(
cli: &mut dyn Cli,
loaded: &mut LoadResult,
result: &(String, FileId, Vec<diagnostics::Diagnostic>),
args: &Ssr,
use_color: bool,
) -> Result<()> {
let (name, file_id, diags) = result;
if args.is_format_json() {
for diag in diags {
let vfs_path = loaded.vfs.file_path(*file_id);
let analysis = loaded.analysis();
let root_path = &analysis
.project_data(*file_id)
.unwrap_or_else(|_err| panic!("could not find project data"))
.unwrap_or_else(|| panic!("could not find project data"))
.root_dir;
let relative_path = reporting::get_relative_path(root_path, vfs_path);
print_diagnostic_json(diag, &analysis, *file_id, relative_path, false, cli)?;
}
} else {
writeln!(cli, " {}: {}", name, diags.len())?;
// Determine if we should show source context
let show_source = args.show_source
|| args.before_context.is_some()
|| args.after_context.is_some()
|| args.context.is_some()
|| args.group_separator.is_some()
|| args.no_group_separator;
let (before_lines, after_lines) = calculate_context_lines(args);
let has_context = before_lines > 0 || after_lines > 0;
let group_separator = should_show_group_separator(args, has_context && show_source);
for (idx, diag) in diags.iter().enumerate() {
// Print group separator before each match (except the first) if showing source with context
if show_source
&& idx > 0
&& let Some(ref sep) = group_separator
{
writeln!(cli, "{}", sep)?;
}
// Get relative path for diagnostic output
let vfs_path = loaded.vfs.file_path(*file_id);
let analysis = loaded.analysis();
let root_path = &analysis
.project_data(*file_id)
.unwrap_or_else(|_err| panic!("could not find project data"))
.unwrap_or_else(|| panic!("could not find project data"))
.root_dir;
let relative_path = reporting::get_relative_path(root_path, vfs_path);
// Only show path when showing source context
let path_to_show = if show_source {
Some(relative_path)
} else {
None
};
print_diagnostic(diag, &loaded.analysis(), *file_id, path_to_show, false, cli)?;
// Only show source context if --show-source or --show-source-markers is set
if show_source {
if use_color {
print_source_with_context(
diag,
&loaded.analysis(),
*file_id,
before_lines,
after_lines,
true,
cli,
)?;
} else {
print_source_with_context_markers(
diag,
&loaded.analysis(),
*file_id,
before_lines,
after_lines,
cli,
)?;
}
writeln!(cli)?;
}
}
}
Ok(())
}
fn load_project(
args: &Ssr,
cli: &mut dyn Cli,
query_config: &BuckQueryConfig,
) -> Result<LoadResult> {
log::info!("Loading project at: {:?}", args.project);
let config = DiscoverConfig::new(args.rebar, &args.profile);
load::load_project_at(
cli,
&args.project,
config,
IncludeOtp::Yes,
Mode::Server,
query_config,
)
}
fn do_parse_one(
db: &Analysis,
config: &DiagnosticsConfig,
file_id: FileId,
name: &str,
args: &Ssr,
) -> Result<Option<(String, FileId, Vec<diagnostics::Diagnostic>)>> {
if !args.include_generated && db.is_generated(file_id)? {
return Ok(None);
}
if !args.include_tests && db.is_test_suite_or_test_helper(file_id)?.unwrap_or(false) {
return Ok(None);
}
// Run only the SSR lint configured in lints_from_config
let diagnostics = db.with_db(|database| {
let sema = Semantic::new(database);
let mut diags = Vec::new();
config
.lints_from_config
.get_diagnostics(&mut diags, &sema, file_id);
diags
})?;
if !diagnostics.is_empty() {
let res = (name.to_string(), file_id, diagnostics);
Ok(Some(res))
} else {
Ok(None)
}
}
fn print_diagnostic(
diag: &diagnostics::Diagnostic,
analysis: &Analysis,
file_id: FileId,
path: Option<&Path>,
use_cli_severity: bool,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
let line_index = analysis.line_index(file_id)?;
let diag_str = diag.print(&line_index, use_cli_severity);
if let Some(path) = path {
writeln!(cli, "{}:{}", path.display(), diag_str)?;
} else {
writeln!(cli, " {}", diag_str)?;
}
Ok(())
}
fn print_diagnostic_json(
diagnostic: &diagnostics::Diagnostic,
analysis: &Analysis,
file_id: FileId,
path: &Path,
use_cli_severity: bool,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
let line_index = analysis.line_index(file_id)?;
let converted_diagnostic =
convert::ide_to_arc_diagnostic(&line_index, path, diagnostic, use_cli_severity);
writeln!(
cli,
"{}",
serde_json::to_string(&converted_diagnostic).unwrap_or_else(|err| panic!(
"print_diagnostics_json failed for '{converted_diagnostic:?}': {err}"
))
)?;
Ok(())
}
/// Print a line with color highlighting
fn print_line_with_color(
line_num: usize,
line_content: &str,
is_match_line: bool,
start: &LineCol,
end: &LineCol,
current_line: u32,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
// Line number in gray
write!(cli, "\x1b[90m{:4} |\x1b[0m ", line_num)?;
if !is_match_line {
// Non-match line: print normally
writeln!(cli, "{}", line_content)?;
} else {
// Match line: highlight the matched portion
if current_line == start.line && current_line == end.line {
// Single-line match
let start_col = start.col_utf16 as usize;
let end_col = end.col_utf16 as usize;
let before = &line_content[..start_col.min(line_content.len())];
let matched =
&line_content[start_col.min(line_content.len())..end_col.min(line_content.len())];
let after = &line_content[end_col.min(line_content.len())..];
write!(cli, "{}", before)?;
write!(cli, "\x1b[91;1m{}\x1b[0m", matched)?; // Red bold
writeln!(cli, "{}", after)?;
} else if current_line == start.line {
// First line of multi-line match
let start_col = start.col_utf16 as usize;
let before = &line_content[..start_col.min(line_content.len())];
let matched = &line_content[start_col.min(line_content.len())..];
write!(cli, "{}", before)?;
writeln!(cli, "\x1b[91;1m{}\x1b[0m", matched)?; // Red bold
} else if current_line == end.line {
// Last line of multi-line match
let end_col = end.col_utf16 as usize;
let matched = &line_content[..end_col.min(line_content.len())];
let after = &line_content[end_col.min(line_content.len())..];
write!(cli, "\x1b[91;1m{}\x1b[0m", matched)?; // Red bold
writeln!(cli, "{}", after)?;
} else {
// Middle line of multi-line match
writeln!(cli, "\x1b[91;1m{}\x1b[0m", line_content)?; // Red bold
}
}
Ok(())
}
/// Calculate context lines from the new grep-style arguments
fn calculate_context_lines(args: &Ssr) -> (usize, usize) {
// -C/--context takes precedence and sets both before and after
if let Some(context) = args.context {
return (context, context);
}
// Otherwise use individual before/after values, defaulting to 0
let before = args.before_context.unwrap_or(0);
let after = args.after_context.unwrap_or(0);
(before, after)
}
/// Determine if a group separator should be shown
fn should_show_group_separator(args: &Ssr, has_context: bool) -> Option<String> {
// If --no-group-separator is set, don't show separator
if args.no_group_separator {
return None;
}
// Only show separators if there's context to separate
if !has_context {
return None;
}
// Use custom separator if provided, otherwise default to "--"
Some(
args.group_separator
.clone()
.unwrap_or_else(|| "--".to_string()),
)
}
/// Print source code context with the specified before/after context lines
fn print_source_with_context(
diag: &diagnostics::Diagnostic,
analysis: &Analysis,
file_id: FileId,
before_lines: usize,
after_lines: usize,
use_color: bool,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
let line_index = analysis.line_index(file_id)?;
let source = &analysis.file_text(file_id)?;
let range = diag.range;
let start = line_index.line_col(range.start());
let end = line_index.line_col(range.end());
let lines: Vec<&str> = source.lines().collect();
let total_lines = lines.len();
// Calculate the range of lines to display
let first_line = start.line.saturating_sub(before_lines as u32) as usize;
let last_line = ((end.line + after_lines as u32 + 1) as usize).min(total_lines);
// Display the source context
for line_idx in first_line..last_line {
let line_num = line_idx + 1;
let line_content = lines.get(line_idx).unwrap_or(&"");
// Check if this line contains part of the match
let is_match_line = line_idx >= start.line as usize && line_idx <= end.line as usize;
if use_color {
print_line_with_color(
line_num,
line_content,
is_match_line,
&start,
&end,
line_idx as u32,
cli,
)?;
} else {
// Just print the line without any highlighting
write!(cli, "{:4} | ", line_num)?;
writeln!(cli, "{}", line_content)?;
}
}
Ok(())
}
/// Print source code context with text markers
fn print_source_with_context_markers(
diag: &diagnostics::Diagnostic,
analysis: &Analysis,
file_id: FileId,
before_lines: usize,
after_lines: usize,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
let line_index = analysis.line_index(file_id)?;
let source = &analysis.file_text(file_id)?;
let range = diag.range;
let start = line_index.line_col(range.start());
let end = line_index.line_col(range.end());
let lines: Vec<&str> = source.lines().collect();
let total_lines = lines.len();
// Calculate the range of lines to display
let first_line = start.line.saturating_sub(before_lines as u32) as usize;
let last_line = ((end.line + after_lines as u32 + 1) as usize).min(total_lines);
// Display the source context
for line_idx in first_line..last_line {
let line_num = line_idx + 1;
let line_content = lines.get(line_idx).unwrap_or(&"");
// Check if this line contains part of the match
let is_match_line = line_idx >= start.line as usize && line_idx <= end.line as usize;
print_line_with_markers(
line_num,
line_content,
is_match_line,
&start,
&end,
line_idx as u32,
cli,
)?;
}
Ok(())
}
/// Print a line with text markers (like diagnostic carets)
fn print_line_with_markers(
line_num: usize,
line_content: &str,
is_match_line: bool,
start: &LineCol,
end: &LineCol,
current_line: u32,
cli: &mut dyn Cli,
) -> Result<(), anyhow::Error> {
// Line number
write!(cli, "{:4} | ", line_num)?;
writeln!(cli, "{}", line_content)?;
if is_match_line {
// Print marker line with ^^^ under the match
write!(cli, " | ")?; // Indent to match line content
if current_line == start.line && current_line == end.line {
// Single-line match
let start_col = start.col_utf16 as usize;
let end_col = end.col_utf16 as usize;
let marker_len = (end_col - start_col).max(1);
// Spaces before the marker
for _ in 0..start_col {
write!(cli, " ")?;
}
// Marker carets
for _ in 0..marker_len {
write!(cli, "^")?;
}
writeln!(cli)?;
} else if current_line == start.line {
// First line of multi-line match
let start_col = start.col_utf16 as usize;
let marker_len = line_content.len().saturating_sub(start_col).max(1);
for _ in 0..start_col {
write!(cli, " ")?;
}
for _ in 0..marker_len {
write!(cli, "^")?;
}
writeln!(cli)?;
} else if current_line == end.line {
// Last line of multi-line match
let end_col = end.col_utf16 as usize;
for _ in 0..end_col {
write!(cli, "^")?;
}
writeln!(cli)?;
} else {
// Middle line of multi-line match
for _ in 0..line_content.len() {
write!(cli, "^")?;
}
writeln!(cli)?;
}
}
Ok(())
}

View file

@ -80,12 +80,7 @@ pub fn load_project_at(
log::info!("Discovered project: {manifest:?}");
let pb = cli.spinner("Loading build info");
let project = Project::load(
&manifest,
elp_config.eqwalizer.clone(),
query_config,
&|_progress| {},
)?;
let project = Project::load(&manifest, &elp_config, query_config, &|_progress| {})?;
pb.finish();
load_project(cli, project, include_otp, eqwalizer_mode)

View file

@ -30,18 +30,13 @@ pub trait Cli: Write + WriteColor {
fn err(&mut self) -> &mut dyn Write;
}
pub struct Real(StandardStream, Stderr);
pub struct StandardCli(StandardStream, Stderr);
impl Default for Real {
fn default() -> Self {
Self(
StandardStream::stdout(ColorChoice::Always),
std::io::stderr(),
)
impl StandardCli {
fn new(color_choice: ColorChoice) -> Self {
Self(StandardStream::stdout(color_choice), std::io::stderr())
}
}
impl Real {
fn progress_with_style(
&self,
len: u64,
@ -59,7 +54,7 @@ impl Real {
}
}
impl Cli for Real {
impl Cli for StandardCli {
fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar {
self.progress_with_style(len, prefix, " {prefix:25!} {bar} {pos}/{len} {wide_msg}")
}
@ -84,6 +79,63 @@ impl Cli for Real {
}
}
impl Write for StandardCli {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.0.flush()
}
}
impl WriteColor for StandardCli {
fn supports_color(&self) -> bool {
self.0.supports_color()
}
fn set_color(&mut self, spec: &ColorSpec) -> std::io::Result<()> {
self.0.set_color(spec)
}
fn reset(&mut self) -> std::io::Result<()> {
self.0.reset()
}
}
pub struct Real(StandardCli);
pub struct NoColor(StandardCli);
impl Default for Real {
fn default() -> Self {
Real(StandardCli::new(ColorChoice::Always))
}
}
impl Default for NoColor {
fn default() -> Self {
NoColor(StandardCli::new(ColorChoice::Never))
}
}
impl Cli for Real {
fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar {
self.0.progress(len, prefix)
}
fn simple_progress(&self, len: u64, prefix: &'static str) -> ProgressBar {
self.0.simple_progress(len, prefix)
}
fn spinner(&self, prefix: &'static str) -> ProgressBar {
self.0.spinner(prefix)
}
fn err(&mut self) -> &mut dyn Write {
self.0.err()
}
}
impl Write for Real {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.write(buf)
@ -108,6 +160,48 @@ impl WriteColor for Real {
}
}
impl Cli for NoColor {
fn progress(&self, len: u64, prefix: &'static str) -> ProgressBar {
self.0.progress(len, prefix)
}
fn simple_progress(&self, len: u64, prefix: &'static str) -> ProgressBar {
self.0.simple_progress(len, prefix)
}
fn spinner(&self, prefix: &'static str) -> ProgressBar {
self.0.spinner(prefix)
}
fn err(&mut self) -> &mut dyn Write {
self.0.err()
}
}
impl Write for NoColor {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.0.flush()
}
}
impl WriteColor for NoColor {
fn supports_color(&self) -> bool {
self.0.supports_color()
}
fn set_color(&mut self, spec: &ColorSpec) -> std::io::Result<()> {
self.0.set_color(spec)
}
fn reset(&mut self) -> std::io::Result<()> {
self.0.reset()
}
}
pub struct Fake(Buffer, Vec<u8>);
impl Default for Fake {

View file

@ -30,7 +30,7 @@ use serde::de::DeserializeOwned;
use serde_json::json;
use crate::from_json;
// @fb-only
// @fb-only: use crate::meta_only;
// Defines the server-side configuration of ELP. We generate *parts*
// of VS Code's `package.json` config from this.
@ -42,6 +42,8 @@ use crate::from_json;
// `new_name | `old_name` so that we keep parsing the old name.
config_data! {
struct ConfigData {
/// Whether to use the expermintal `buck2 targets` quick start process.
buck_quickStart: bool = json! { false },
/// Whether to show experimental ELP diagnostics that might
/// have more false positives than usual.
diagnostics_enableExperimental: bool = json! { false },
@ -89,6 +91,12 @@ config_data! {
/// Whether to show the `Link` lenses. Only applies when
/// `#elp.lens.enable#` is set.
lens_links_enable: bool = json! { false },
/// Whether to enable LogView lens links.
lens_logview_links: bool = json! { false },
/// Whether to enable Scuba lens links.
lens_scuba_links: bool = json! { false },
/// Whether to enable WAM lens links.
lens_wam_links: bool = json! { false },
/// Configure LSP-based logging using env_logger syntax.
log: String = json! { "error" },
/// Whether to show Signature Help.
@ -128,6 +136,9 @@ pub struct LensConfig {
pub buck2_mode: Option<String>,
pub debug: bool,
pub links: bool,
pub logview_links: bool,
pub scuba_links: bool,
pub wam_links: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -169,7 +180,7 @@ impl Config {
return;
}
self.data = ConfigData::from_json(json);
// @fb-only
// @fb-only: meta_only::harmonise_gks(self);
}
pub fn update_gks(&mut self, json: serde_json::Value) {
@ -323,6 +334,9 @@ impl Config {
&& self.data.lens_run_coverage_enable,
debug: self.data.lens_enable && self.data.lens_debug_enable,
links: self.data.lens_enable && self.data.lens_links_enable,
logview_links: self.data.lens_enable && self.data.lens_logview_links,
scuba_links: self.data.lens_enable && self.data.lens_scuba_links,
wam_links: self.data.lens_enable && self.data.lens_wam_links,
}
}
@ -367,14 +381,38 @@ impl Config {
try_or!(self.caps.window.as_ref()?.work_done_progress?, false)
}
pub fn set_buck_quick_start(&mut self, value: bool) {
self.data.buck_quickStart = value;
}
pub fn buck_quick_start(&self) -> bool {
self.data.buck_quickStart
}
pub fn buck_query(&self) -> BuckQueryConfig {
BuckQueryConfig::BuildGeneratedCode
if self.buck_quick_start() {
BuckQueryConfig::BuckTargetsOnly
} else {
BuckQueryConfig::BuildGeneratedCode
}
}
pub fn set_eqwalizer_all(&mut self, value: bool) {
self.data.eqwalizer_all = value;
}
pub fn set_lens_logview_links(&mut self, value: bool) {
self.data.lens_logview_links = value;
}
pub fn set_lens_scuba_links(&mut self, value: bool) {
self.data.lens_scuba_links = value;
}
pub fn set_lens_wam_links(&mut self, value: bool) {
self.data.lens_wam_links = value;
}
pub fn inlay_hints(&self) -> InlayHintsConfig {
InlayHintsConfig {
parameter_hints: self.data.inlayHints_parameterHints_enable,
@ -580,10 +618,15 @@ mod tests {
let s = remove_ws(&schema);
expect![[r#""elp.diagnostics.disabled":{"default":[],"items":{"type":"string"},"markdownDescription":"ListofELPdiagnosticstodisable.","type":"array","uniqueItems":true},"elp.diagnostics.enableExperimental":{"default":false,"markdownDescription":"WhethertoshowexperimentalELPdiagnosticsthatmight\nhavemorefalsepositivesthanusual.","type":"boolean"},"elp.diagnostics.enableOtp":{"default":false,"markdownDescription":"WhethertoreportdiagnosticsforOTPfiles.","type":"boolean"},"elp.diagnostics.onSave.enable":{"default":false,"markdownDescription":"Updatenativediagnosticsonlywhenthefileissaved.","type":"boolean"},"elp.edoc.enable":{"default":false,"markdownDescription":"WhethertoreportEDocdiagnostics.","type":"boolean"},"elp.eqwalizer.all":{"default":false,"markdownDescription":"WhethertoreportEqwalizerdiagnosticsforthewholeprojectandnotonlyforopenedfiles.","type":"boolean"},"elp.eqwalizer.chunkSize":{"default":100,"markdownDescription":"Chunksizetouseforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.eqwalizer.maxTasks":{"default":32,"markdownDescription":"Maximumnumberoftaskstoruninparallelforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.highlightDynamic.enable":{"default":false,"markdownDescription":"Ifenabled,highlightvariableswithtype`dynamic()`whenEqwalizerresultsareavailable.","type":"boolean"},"elp.hoverActions.docLinks.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActionsoftype`docs`.Onlyapplieswhen\n`#elp.hoverActions.enable#`isset.","type":"boolean"},"elp.hoverActions.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActions.","type":"boolean"},"elp.inlayHints.parameterHints.enable":{"default":true,"markdownDescription":"Whethertoshowfunctionparameternameinlayhintsatthecall\nsite.","type":"boolean"},"elp.lens.buck2.mode":{"default":null,"markdownDescription":"Thebuck2modetouseforrunningtestsviathecodelenses.","type":["null","string"]},"elp.lens.debug.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Debug`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.enable":{"default":false,"markdownDescription":"WhethertoshowCodeLensesinErlangfiles.","type":"boolean"},"elp.lens.links.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Link`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.run.coverage.enable":{"default":true,"markdownDescription":"Displaycodecoverageinformationwhenrunningtestsviathe\nCodeLenses.Onlyapplieswhen`#elp.lens.enabled`and\n`#elp.lens.run.enable#`areset.","type":"boolean"},"elp.lens.run.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Run`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.run.interactive.enable":{"default":false,"markdownDescription":"Whethertoshowthe`RunInteractive`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.log":{"default":"error","markdownDescription":"ConfigureLSP-basedloggingusingenv_loggersyntax.","type":"string"},"elp.signatureHelp.enable":{"default":true,"markdownDescription":"WhethertoshowSignatureHelp.","type":"boolean"},"elp.typesOnHover.enable":{"default":false,"markdownDescription":"Displaytypeswhenhoveringoverexpressions.","type":"boolean"},"#]]
expect![[r#""elp.buck.quickStart":{"default":false,"markdownDescription":"Whethertousetheexpermintal`buck2targets`quickstartprocess.","type":"boolean"},"elp.diagnostics.disabled":{"default":[],"items":{"type":"string"},"markdownDescription":"ListofELPdiagnosticstodisable.","type":"array","uniqueItems":true},"elp.diagnostics.enableExperimental":{"default":false,"markdownDescription":"WhethertoshowexperimentalELPdiagnosticsthatmight\nhavemorefalsepositivesthanusual.","type":"boolean"},"elp.diagnostics.enableOtp":{"default":false,"markdownDescription":"WhethertoreportdiagnosticsforOTPfiles.","type":"boolean"},"elp.diagnostics.onSave.enable":{"default":false,"markdownDescription":"Updatenativediagnosticsonlywhenthefileissaved.","type":"boolean"},"elp.edoc.enable":{"default":false,"markdownDescription":"WhethertoreportEDocdiagnostics.","type":"boolean"},"elp.eqwalizer.all":{"default":false,"markdownDescription":"WhethertoreportEqwalizerdiagnosticsforthewholeprojectandnotonlyforopenedfiles.","type":"boolean"},"elp.eqwalizer.chunkSize":{"default":100,"markdownDescription":"Chunksizetouseforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.eqwalizer.maxTasks":{"default":32,"markdownDescription":"Maximumnumberoftaskstoruninparallelforproject-wideeqwalization.","minimum":0,"type":"integer"},"elp.highlightDynamic.enable":{"default":false,"markdownDescription":"Ifenabled,highlightvariableswithtype`dynamic()`whenEqwalizerresultsareavailable.","type":"boolean"},"elp.hoverActions.docLinks.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActionsoftype`docs`.Onlyapplieswhen\n`#elp.hoverActions.enable#`isset.","type":"boolean"},"elp.hoverActions.enable":{"default":false,"markdownDescription":"WhethertoshowHoverActions.","type":"boolean"},"elp.inlayHints.parameterHints.enable":{"default":true,"markdownDescription":"Whethertoshowfunctionparameternameinlayhintsatthecall\nsite.","type":"boolean"},"elp.lens.buck2.mode":{"default":null,"markdownDescription":"Thebuck2modetouseforrunningtestsviathecodelenses.","type":["null","string"]},"elp.lens.debug.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Debug`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.enable":{"default":false,"markdownDescription":"WhethertoshowCodeLensesinErlangfiles.","type":"boolean"},"elp.lens.links.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Link`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.logview.links":{"default":false,"markdownDescription":"WhethertoenableLogViewlenslinks.","type":"boolean"},"elp.lens.run.coverage.enable":{"default":true,"markdownDescription":"Displaycodecoverageinformationwhenrunningtestsviathe\nCodeLenses.Onlyapplieswhen`#elp.lens.enabled`and\n`#elp.lens.run.enable#`areset.","type":"boolean"},"elp.lens.run.enable":{"default":false,"markdownDescription":"Whethertoshowthe`Run`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.run.interactive.enable":{"default":false,"markdownDescription":"Whethertoshowthe`RunInteractive`lenses.Onlyapplieswhen\n`#elp.lens.enable#`isset.","type":"boolean"},"elp.lens.scuba.links":{"default":false,"markdownDescription":"WhethertoenableScubalenslinks.","type":"boolean"},"elp.lens.wam.links":{"default":false,"markdownDescription":"WhethertoenableWAMlenslinks.","type":"boolean"},"elp.log":{"default":"error","markdownDescription":"ConfigureLSP-basedloggingusingenv_loggersyntax.","type":"string"},"elp.signatureHelp.enable":{"default":true,"markdownDescription":"WhethertoshowSignatureHelp.","type":"boolean"},"elp.typesOnHover.enable":{"default":false,"markdownDescription":"Displaytypeswhenhoveringoverexpressions.","type":"boolean"},"#]]
.assert_eq(s.as_str());
expect![[r#"
"elp.buck.quickStart": {
"default": false,
"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.",

View file

@ -26,6 +26,7 @@ use elp_ide::elp_ide_db::assists::AssistContextDiagnostic;
use elp_ide::elp_ide_db::assists::AssistContextDiagnosticCode;
use elp_ide::elp_ide_db::elp_base_db::AbsPath;
use elp_ide::elp_ide_db::elp_base_db::AbsPathBuf;
use elp_ide::elp_ide_db::elp_base_db::FileId;
use elp_ide::elp_ide_db::elp_base_db::VfsPath;
use lsp_types::DiagnosticRelatedInformation;
use lsp_types::Location;
@ -67,11 +68,14 @@ pub fn diagnostic_severity(severity: Severity) -> lsp_types::DiagnosticSeverity
}
}
pub fn ide_to_lsp_diagnostic(
pub fn ide_to_lsp_diagnostic<F>(
line_index: &LineIndex,
url: &Url,
d: &Diagnostic,
) -> lsp_types::Diagnostic {
get_file_info: F,
) -> lsp_types::Diagnostic
where
F: Fn(FileId) -> Option<(LineIndex, Url)>,
{
let code_description = match &d.code_doc_uri {
Some(uri) => match lsp_types::Url::parse(uri) {
Ok(href) => Some(lsp_types::CodeDescription { href }),
@ -90,17 +94,16 @@ pub fn ide_to_lsp_diagnostic(
code_description,
source,
message: d.message.clone(),
related_information: from_related(line_index, url, &d.related_info),
tags: lsp_diagnostic_tags(&d.tag),
related_information: from_related(get_file_info, &d.related_info),
tags: d.tag.as_ref().map(lsp_diagnostic_tags),
data: None,
}
}
fn lsp_diagnostic_tags(d: &DiagnosticTag) -> Option<Vec<lsp_types::DiagnosticTag>> {
fn lsp_diagnostic_tags(d: &DiagnosticTag) -> Vec<lsp_types::DiagnosticTag> {
match d {
DiagnosticTag::None => None,
DiagnosticTag::Unused => Some(vec![lsp_types::DiagnosticTag::UNNECESSARY]),
DiagnosticTag::Deprecated => Some(vec![lsp_types::DiagnosticTag::DEPRECATED]),
DiagnosticTag::Unused => vec![lsp_types::DiagnosticTag::UNNECESSARY],
DiagnosticTag::Deprecated => vec![lsp_types::DiagnosticTag::DEPRECATED],
}
}
@ -123,19 +126,11 @@ pub fn eqwalizer_to_arc_diagnostic(
d: &EqwalizerDiagnostic,
line_index: &LineIndex,
relative_path: &Path,
eqwalizer_enabled: bool,
) -> arc_types::Diagnostic {
let pos = position(line_index, d.range.start());
let line_num = pos.line + 1;
let character = Some(pos.character + 1);
let severity = if eqwalizer_enabled {
arc_types::Severity::Error
} else {
// We use Severity::Disabled so that we have the ability in our arc linter to choose
// to display lints for *new* files with errors that are not opted in (T118466310).
// See comment at the top of eqwalizer_cli.rs for more information.
arc_types::Severity::Disabled
};
let severity = arc_types::Severity::Error;
// formatting: https://fburl.com/max_wiki_link_to_phabricator_rich_text
let explanation = match &d.explanation {
Some(s) => format!("```\n{s}\n```"),
@ -163,25 +158,30 @@ pub fn eqwalizer_to_arc_diagnostic(
name,
message,
d.expression.clone(),
None,
)
}
fn from_related(
line_index: &LineIndex,
url: &Url,
fn from_related<F>(
get_file_info: F,
r: &Option<Vec<RelatedInformation>>,
) -> Option<Vec<DiagnosticRelatedInformation>> {
) -> Option<Vec<DiagnosticRelatedInformation>>
where
F: Fn(elp_ide::elp_ide_db::elp_base_db::FileId) -> Option<(LineIndex, Url)>,
{
r.as_ref().map(|ri| {
ri.iter()
.map(|i| {
.filter_map(|i| {
// Get the line index and URL for the file that contains the related information
let (line_index, uri) = get_file_info(i.file_id)?;
let location = Location {
range: range(line_index, i.range),
uri: url.clone(),
range: range(&line_index, i.range),
uri,
};
DiagnosticRelatedInformation {
Some(DiagnosticRelatedInformation {
location,
message: i.message.clone(),
}
})
})
.collect()
})
@ -251,6 +251,7 @@ pub fn ide_to_arc_diagnostic(
None => message,
};
let severity = diagnostic.severity(use_cli_severity);
let doc_path = diagnostic.code.as_doc_path();
arc_types::Diagnostic::new(
path,
line_num,
@ -259,5 +260,6 @@ pub fn ide_to_arc_diagnostic(
diagnostic.code.as_labeled_code(),
description,
None,
doc_path,
)
}

View file

@ -17,6 +17,7 @@ use std::time::SystemTime;
use anyhow::Result;
use anyhow::bail;
use elp_ide::Cancellable;
use elp_ide::DocResult;
use elp_ide::HighlightedRange;
use elp_ide::NavigationTarget;
use elp_ide::RangeInfo;
@ -32,6 +33,8 @@ use elp_ide::elp_ide_db::elp_base_db::FilePosition;
use elp_ide::elp_ide_db::elp_base_db::FileRange;
use elp_ide::elp_ide_db::elp_base_db::ProjectId;
use elp_log::telemetry;
use elp_log::timeit_with_telemetry;
use elp_syntax::SmolStr;
use itertools::Itertools;
use lsp_server::ErrorCode;
use lsp_types::CallHierarchyIncomingCall;
@ -64,6 +67,7 @@ use crate::convert::lsp_to_assist_context_diagnostic;
use crate::from_proto;
use crate::lsp_ext;
use crate::snapshot::Snapshot;
use crate::snapshot::TelemetryData;
use crate::to_proto;
pub(crate) fn handle_code_action(
@ -339,16 +343,22 @@ fn goto_definition_telemetry(snap: &Snapshot, targets: &[NavigationTarget], star
.iter()
.map(|tgt| snap.file_id_to_url(tgt.file_id))
.collect();
let target_names: Vec<_> = targets.iter().map(|tgt| tgt.name.clone()).collect();
let target_kinds: Vec<_> = targets.iter().map(|tgt| tgt.kind).collect();
#[derive(serde::Serialize)]
struct Data {
targets_include_generated: bool,
target_urls: Vec<Url>,
target_names: Vec<SmolStr>,
target_kinds: Vec<SymbolKind>,
}
let detail = Data {
targets_include_generated,
target_urls,
target_names,
target_kinds,
};
let duration = start.elapsed().map(|e| e.as_millis()).unwrap_or(0) as u32;
let data = serde_json::to_value(detail).unwrap_or_else(|err| {
@ -357,6 +367,24 @@ fn goto_definition_telemetry(snap: &Snapshot, targets: &[NavigationTarget], star
telemetry::send_with_duration("goto_definition".to_string(), data, duration, start);
}
fn send_hover_telemetry(doc_result: &DocResult) {
#[derive(serde::Serialize)]
struct Data {
docs_found: bool,
text: String,
kind: String,
}
let detail = Data {
docs_found: doc_result.doc.is_some(),
text: doc_result.token_text.clone(),
kind: format!("{:?}", doc_result.token_kind),
};
let data = serde_json::to_value(detail).unwrap_or_else(|err| {
serde_json::Value::String(format!("JSON serialization failed: {err}"))
});
telemetry::send("hover".to_string(), data);
}
pub(crate) fn handle_goto_type_definition(
snap: Snapshot,
params: lsp_types::GotoDefinitionParams,
@ -386,10 +414,16 @@ pub(crate) fn handle_references(
params: lsp_types::ReferenceParams,
) -> Result<Option<Vec<lsp_types::Location>>> {
let _p = tracing::info_span!("handle_references").entered();
let _timer = timeit_with_telemetry!(TelemetryData::References {
file_url: params.text_document_position.text_document.uri.clone(),
position: params.text_document_position.position
});
let mut position = from_proto::file_position(&snap, params.text_document_position)?;
position.offset = snap
.analysis
.clamp_offset(position.file_id, position.offset)?;
let refs = match snap.analysis.find_all_refs(position)? {
None => return Ok(None),
Some(it) => it,
@ -413,6 +447,7 @@ pub(crate) fn handle_references(
.chain(decl)
})
.collect();
Ok(Some(locations))
}
@ -449,8 +484,10 @@ pub(crate) fn handle_completion_resolve(
position.offset = snap
.analysis
.clamp_offset(position.file_id, position.offset)?;
if let Ok(Some(res)) = snap.analysis.get_docs_at_position(position) {
let docs = res.0.markdown_text().to_string();
if let Ok(Some(doc_result)) = snap.analysis.get_docs_at_position(position)
&& let Some(doc) = doc_result.doc
{
let docs = doc.markdown_text().to_string();
let documentation =
lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent {
kind: lsp_types::MarkupKind::Markdown,
@ -575,8 +612,13 @@ pub(crate) fn handle_hover(snap: Snapshot, params: HoverParams) -> Result<Option
}
}
if let Some(hover) = snap.analysis.get_docs_at_position(position)? {
docs.push(hover);
if let Some(doc_result) = snap.analysis.get_docs_at_position(position)? {
send_hover_telemetry(&doc_result);
let doc = doc_result.doc;
if let Some(doc) = doc {
let range = doc_result.token_range;
docs.push((doc, Some(range)));
}
}
if let Some(macro_expansion) = snap.analysis.expand_macro(position)? {

View file

@ -37,7 +37,7 @@ pub mod line_endings;
pub mod lsp_ext;
mod mem_docs;
pub mod memory_usage;
// @fb-only
// @fb-only: mod meta_only;
mod op_queue;
mod project_loader;
pub mod reload;
@ -108,7 +108,7 @@ pub fn otp_file_to_ignore(db: &Analysis, file_id: FileId) -> bool {
"redbug_dtop",
]
.iter()
// @fb-only
// @fb-only: .chain(meta_only::FILES_TO_IGNORE.iter())
.map(SmolStr::new)
.collect();
}
@ -159,12 +159,16 @@ pub fn read_lint_config_file(project: &Path, config_file: &Option<String>) -> Re
mod tests {
use elp_ide::FunctionMatch;
use elp_ide::diagnostics::DiagnosticCode;
use elp_ide::diagnostics::ErlangServiceConfig;
use elp_ide::diagnostics::Lint;
use elp_ide::diagnostics::LintsFromConfig;
use elp_ide::diagnostics::MatchSsr;
use elp_ide::diagnostics::ReplaceCall;
use elp_ide::diagnostics::ReplaceCallAction;
use elp_ide::diagnostics::Replacement;
use elp_ide::diagnostics::Severity;
use expect_test::expect;
use fxhash::FxHashMap;
use crate::LintConfig;
@ -185,12 +189,23 @@ mod tests {
perm: vec![1, 2],
}),
}),
Lint::LintMatchSsr(MatchSsr {
ssr_pattern: "ssr: _@A = 10.".to_string(),
message: None,
strategy: None,
severity: None,
}),
],
},
linters: FxHashMap::default(),
erlang_service: ErlangServiceConfig::default(),
};
expect![[r#"
enabled_lints = ["W0011"]
disabled_lints = []
[erlang_service]
warnings_as_errors = false
[[ad_hoc_lints.lints]]
type = "ReplaceCall"
@ -214,6 +229,12 @@ mod tests {
action = "Replace"
type = "ArgsPermutation"
perm = [1, 2]
[[ad_hoc_lints.lints]]
type = "LintMatchSsr"
ssr_pattern = "ssr: _@A = 10."
[linters]
"#]]
.assert_eq(&toml::to_string::<LintConfig>(&lint_config).unwrap());
}
@ -227,4 +248,21 @@ mod tests {
assert_eq!(config.enabled_lints, vec![]);
assert_eq!(config.disabled_lints, vec![]);
}
#[test]
fn serde_read_lint_config_linters_overrides() {
let content = r#"
[linters.no_garbage_collect]
severity = "error"
"#;
let config = toml::from_str::<LintConfig>(content).unwrap();
assert_eq!(
config
.linters
.get(&DiagnosticCode::NoGarbageCollect)
.unwrap()
.severity,
Some(Severity::Error)
);
}
}

View file

@ -148,11 +148,10 @@ impl Runnable {
}
}
pub fn rebar3_test(
pub fn rebar3_ct(
runnable: elp_ide::Runnable,
location: Option<lsp_types::LocationLink>,
workspace_root: PathBuf,
_coverage_enabled: bool,
) -> Self {
Self {
label: "Rebar3".to_string(),
@ -165,6 +164,23 @@ impl Runnable {
}),
}
}
pub fn rebar3_shell(
_runnable: elp_ide::Runnable,
location: Option<lsp_types::LocationLink>,
workspace_root: PathBuf,
) -> Self {
Self {
label: "Rebar3".to_string(),
location,
kind: RunnableKind::Rebar3,
args: RunnableArgs::Rebar3(Rebar3RunnableArgs {
workspace_root,
command: "as".to_string(),
args: vec!["test".to_string(), "shell".to_string()],
}),
}
}
}
#[derive(Serialize, Deserialize, Debug)]

View file

@ -18,6 +18,7 @@ use elp_log::telemetry;
use elp_project_model::ElpConfig;
use elp_project_model::IncludeParentDirs;
use elp_project_model::ProjectManifest;
use elp_project_model::buck::BuckQueryConfig;
use elp_project_model::otp::Otp;
use fxhash::FxHashMap;
use fxhash::FxHashSet;
@ -49,12 +50,15 @@ impl ProjectLoader {
let mut result = false;
for path in paths {
let mut path_it: &AbsPath = path.as_ref();
while let Some(path) = path_it.parent() {
if self.project_roots.remove(path).is_some() {
loop {
if self.project_roots.remove(path_it).is_some() {
result = true;
break;
}
path_it = path;
match path_it.parent() {
Some(parent) => path_it = parent,
None => break,
}
}
}
result
@ -95,12 +99,16 @@ impl ProjectLoader {
path: &AbsPath,
) -> Option<(ElpConfig, Result<ProjectManifest>, ProjectManifest)> {
let mut path_it = path;
while let Some(path) = path_it.parent() {
if self.project_roots.contains_key(path) {
loop {
if self.project_roots.contains_key(path_it) {
return None;
}
path_it = path;
match path_it.parent() {
Some(parent) => path_it = parent,
None => break,
}
}
Some(self.load_manifest(path))
}
@ -114,12 +122,33 @@ impl ProjectLoader {
}
}
/// If using buck quick start, it happens in two stages, first to
/// get the basic project config, then to invoke the generation of
/// any artifacts that will become part of the project.
#[derive(Debug, PartialEq, Eq)]
pub enum BuckGenerated {
/// Initial value
NoLoadDone,
/// After first load (buck targets)
NoGenerated,
/// After second load (elp.bxl)
Generated,
}
pub struct ReloadManager {
/// Files that have changed since the last reload.
changed_files: FxHashSet<AbsPathBuf>,
/// This field is updated when a `changed_files` file is added.
/// It allows us to wait until the last file has been added
/// when a branch switch is done to avoid doing a reload for each.
/// We wait until RELOAD_QUIESCENT_WAIT_TIME has elapsed before doing
/// the reload.
last_change: SystemTime,
/// ReloadManager clients should ensure this is set when a reload
/// task is active, reset when done.
reload_in_progress: bool,
buck_generated: BuckGenerated,
buck_quick_start: bool,
}
/// How long to wait after the last changed file was added before
@ -127,24 +156,76 @@ pub struct ReloadManager {
const RELOAD_QUIESCENT_WAIT_TIME: Duration = Duration::from_millis(500);
impl ReloadManager {
pub fn new() -> ReloadManager {
pub fn new(buck_quick_start: bool) -> ReloadManager {
ReloadManager {
changed_files: FxHashSet::default(),
last_change: SystemTime::now(),
reload_in_progress: false,
buck_generated: BuckGenerated::NoLoadDone,
buck_quick_start,
}
}
/// Used to check if any files are queued, and if so cancel an
/// existing reload
pub fn has_changed_files(&self) -> bool {
!self.changed_files.is_empty()
pub fn ok_to_switch_workspace(&self) -> bool {
if self.buck_quick_start {
// `BuckGenerated::NoLoadDone` or `BuckGenerated::NoGenerated`.
if self.buck_generated == BuckGenerated::NoLoadDone {
// We are doing a 2-stage load, and have just completed the `buck targets` step.
// So time to activate the Project, this is the whole point of the two stage process
true
} else {
self.changed_files.is_empty()
}
} else {
// Do not switch if there are files which will trigger a reload.
// This lets us start that process sooner without wasted effort
// switching when it is going to change anyway.
self.changed_files.is_empty()
}
}
pub fn set_reload_active(&mut self) {
pub fn set_reload_active(&mut self) -> BuckQueryConfig {
self.reload_in_progress = true;
self.get_query_config()
}
pub fn set_reload_done(&mut self) {
pub fn get_query_config(&self) -> BuckQueryConfig {
if self.buck_quick_start {
match self.buck_generated {
BuckGenerated::NoLoadDone => BuckQueryConfig::BuckTargetsOnly,
BuckGenerated::NoGenerated => BuckQueryConfig::BuildGeneratedCode,
BuckGenerated::Generated => BuckQueryConfig::BuildGeneratedCode,
}
} else {
BuckQueryConfig::BuildGeneratedCode
}
}
/// This is called when the `Task::FetchProject` is done in `server.rs`,
/// but only after `switch_workspace_ok` has returned true.
pub fn set_reload_done(&mut self, a_file_per_project: FxHashSet<AbsPathBuf>) {
if self.buck_quick_start {
match &self.buck_generated {
BuckGenerated::NoLoadDone => {
if self.changed_files.is_empty() && !a_file_per_project.is_empty() {
// We have done the initial "buck targets" query on at least one Project,
// move on to doing `elp.bxl`
self.buck_generated = BuckGenerated::NoGenerated;
self.changed_files = a_file_per_project;
} else {
// We already have changed files from another source, so
// need to repeat this step. Do not change state.
}
}
BuckGenerated::NoGenerated => {
self.buck_generated = BuckGenerated::Generated;
}
BuckGenerated::Generated => {}
};
}
self.reload_in_progress = false;
}
@ -174,4 +255,8 @@ impl ReloadManager {
self.last_change = SystemTime::now();
}
}
pub fn set_buck_quickstart(&mut self, buck_quick_start: bool) {
self.buck_quick_start = buck_quick_start;
}
}

View file

@ -9,7 +9,6 @@
*/
use std::cmp;
use std::iter;
use elp_ide::elp_ide_db::elp_base_db::FileSetConfig;
use elp_ide::elp_ide_db::elp_base_db::ProjectApps;
@ -52,14 +51,18 @@ impl ProjectFolders {
.all_apps
.iter()
.flat_map(|(project_id, app)| {
iter::repeat(project_id).zip(app.all_source_and_include_dirs())
})
.filter_map(|(project_id, root)| {
if Some(*project_id) != project_apps.otp_project_id {
Some(format!("{root}/**/*.{{e,h}}rl"))
} else {
None
let mut paths = Vec::new();
// Add all_dirs_to_watch() with project_id check and glob
for root in app.all_dirs_to_watch() {
if Some(*project_id) != project_apps.otp_project_id {
paths.push(format!("{root}/**/*.{{e,h}}rl"));
}
}
// Add all_files_to_watch() directly, no project_id check or glob
for file in app.all_files_to_watch() {
paths.push(file.to_string());
}
paths
})
.collect();

View file

@ -0,0 +1 @@
Project Initialisation Failed: invalid or missing buck 2 configuration

View file

@ -1,18 +1,7 @@
[check_include_separate_1/include/include_with_bug.hrl] 5:14-5:18: E1507: undefined macro 'FOO'
[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.
5:9-5:31::[WeakWarning] [W0037] Unspecific include.
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.
check_include/src/top_includer.erl:14:5-14:11::[Error] [E1508] undefined macro 'THIRD/2'
check_include/src/top_includer.erl:6:1-6:67::[Error] [L0000] Issue in included file
module specified: top_includer

View file

@ -1,4 +1,9 @@
{
"elp.buck.quickStart": {
"default": false,
"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.",

View file

@ -0,0 +1,138 @@
Reporting all diagnostics codes
Diagnostics reported:
app_a/src/app_a.erl:52:3-52:23::[Warning] [W0006] this statement has no effect
app_a/src/app_a.erl:3:10-3:21::[WeakWarning] [W0037] Unspecific include.
app_a/src/app_a.erl:27:3-27:9::[Warning] [W0017] Function 'foo:ok/0' is undefined.
app_a/src/app_a.erl:28:4-28:11::[Warning] [W0017] Function 'mod:foo/0' is undefined.
app_a/src/app_a.erl:72:4-72:11::[Warning] [W0017] Function 'foo:bar/2' is undefined.
app_a/src/app_a.erl:37:11-37:28::[Warning] [W0017] Function 'mod_name:fun_name/2' is undefined.
app_a/src/app_a.erl:58:11-58:24::[WeakWarning] [W0051] Binary string can be written using sigil syntax.
app_a/src/app_a.erl:4:1-4:41::[Warning] [W0020] Unused file: inets/include/httpd.hrl
app_a/src/app_a.erl:39:7-39:28::[Error] [L1267] variable 'A' shadowed in 'named fun'
app_a/src/app_a.erl:55:32-55:35::[Error] [L1295] type uri/0 undefined
app_a/src/app_a.erl:56:20-56:26::[Error] [L1295] type binary/1 undefined
app_a/src/app_a.erl:72:3-72:34::[Error] [L1252] record record undefined
app_a/src/app_a.erl:75:5-75:16::[Error] [L1252] record record undefined
app_a/src/app_a.erl:35:1-35:2::[Warning] [L1230] function g/1 is unused
app_a/src/app_a.erl:35:3-35:4::[Warning] [L1268] variable 'A' is unused
app_a/src/app_a.erl:36:3-36:4::[Warning] [L1268] variable 'F' is unused
app_a/src/app_a.erl:37:3-37:4::[Warning] [L1268] variable 'G' is unused
app_a/src/app_a.erl:38:3-38:4::[Warning] [L1268] variable 'H' is unused
app_a/src/app_a.erl:39:3-39:4::[Warning] [L1268] variable 'I' is unused
app_a/src/app_a.erl:39:7-39:28::[Warning] [L1268] variable 'A' is unused
app_a/src/app_a.erl:41:1-41:2::[Warning] [L1230] function h/0 is unused
app_a/src/app_a.erl:45:1-45:2::[Warning] [L1230] function i/0 is unused
app_a/src/app_a.erl:50:1-50:2::[Warning] [L1230] function j/2 is unused
app_a/src/app_a.erl:50:15-50:16::[Warning] [L1268] variable 'A' is unused
app_a/src/app_a.erl:50:23-50:24::[Warning] [L1268] variable 'B' is unused
app_a/src/app_a.erl:55:1-55:46::[Warning] [L1296] type session(_) is unused
app_a/src/app_a.erl:55:1-55:46::[Warning] [L1313] opaque type session(_) is not exported
app_a/src/app_a.erl:56:7-56:13::[Warning] [L1296] type source(_) is unused
app_a/src/app_a.erl:58:1-58:4::[Warning] [L1230] function map/2 is unused
app_a/src/app_a.erl:60:1-60:9::[Warning] [L1230] function with_dot/0 is unused
app_a/src/app_a.erl:62:1-62:9::[Warning] [L1230] function lang_dir/1 is unused
app_a/src/app_a.erl:66:1-66:7::[Warning] [L1230] function escape/1 is unused
app_a/src/app_a.erl:66:13-66:17::[Warning] [L1268] variable 'T' is unused
app_a/src/app_a.erl:67:9-67:25::[Warning] [L1260] record all_configs_file is unused
app_a/src/app_a.erl:71:1-71:2::[Warning] [L1230] function k/0 is unused
app_a/src/app_a.erl:74:1-74:2::[Warning] [L1230] function l/1 is unused
app_a/src/app_a.erl:77:1-77:2::[Warning] [L1230] function m/0 is unused
app_a/src/broken_parse_trans.erl:10:21-10:22::[Error] [L1256] field b undefined in record a
app_a/src/broken_parse_trans.erl:10:32-10:33::[Error] [L1262] variable 'B' is unbound
app_a/src/cascading.erl:9:5-9:6::[Error] [W0004] Missing ')'
3:10-3:15: function foo/0 undefined
6:10-6:15: function foo/0 undefined
8:7-8:10: spec for undefined function foo/0
app_a/src/diagnostics.erl:3:10-3:27::[WeakWarning] [W0037] Unspecific include.
app_a/src/diagnostics.erl:4:10-4:34::[WeakWarning] [W0037] Unspecific include.
app_a/src/diagnostics.erl:12:8-12:12::[Warning] [W0060] Match on a bound variable
app_a/src/diagnostics.erl:4:1-4:36::[Error] [L0000] Issue in included file
[app_a/include/broken_diagnostics.hrl] 1:8-1:15: P1702: bad attribute
[app_a/include/broken_diagnostics.hrl] 3:6-3:15: P1702: bad attribute
app_a/src/diagnostics.erl:6:31-6:45::[Error] [L1295] type undefined_type/0 undefined
app_a/src/diagnostics.erl:7:1-7:5::[Warning] [L1230] function main/1 is unused
app_a/src/diagnostics.erl:10:1-10:4::[Warning] [L1230] function foo/0 is unused
app_a/src/lint_recursive.erl:23:5-23:14::[Warning] [W0006] this statement has no effect
app_a/src/lint_recursive.erl:6:5-6:7::[Warning] [W0006] this statement has no effect
app_a/src/lint_recursive.erl:14:5-14:12::[Warning] [L1268] variable 'Config1' is unused
app_a/src/lint_recursive.erl:19:5-19:12::[Warning] [L1268] variable 'Config1' is unused
app_a/src/lints.erl:5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
4:1-4:14: Mismatched clause name
app_a/src/lints.erl:4:22-4:23::[Warning] [W0018] Unexpected ';'
app_a/src/lints.erl:2:10-2:25::[Error] [L1227] function head_mismatch/1 undefined
app_a/src/otp27_docstrings.erl:34:9-34:24::[Warning] [W0002] Unused macro (THIS_IS_THE_END)
app_a/src/otp27_docstrings.erl:24:5-24:6::[Warning] [W0060] Match on a bound variable
app_a/src/otp27_docstrings.erl:30:5-30:6::[Warning] [W0060] Match on a bound variable
app_a/src/otp27_sigils.erl:11:6-11:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:12:5-12:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:13:5-13:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:14:5-14:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:15:5-15:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:17:6-17:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:18:5-18:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:19:5-19:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:20:5-20:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:21:5-21:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:23:6-23:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:24:5-24:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:25:5-25:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:26:5-26:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:27:5-27:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:29:6-29:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:30:5-30:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:31:5-31:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:32:5-32:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:33:5-33:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:35:6-35:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:36:5-36:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:37:5-37:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:38:5-38:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:39:5-39:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:41:6-41:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:42:5-42:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:43:5-43:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:44:5-44:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:45:5-45:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:47:6-47:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:48:5-48:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:49:5-49:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:50:5-50:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:51:5-51:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:53:6-53:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:53:6-53:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:54:5-54:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:54:5-54:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:55:5-55:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:55:5-55:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:56:5-56:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:57:5-57:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:59:6-59:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:60:5-60:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:61:5-61:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:62:5-62:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:63:5-63:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:65:6-65:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:66:5-66:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:67:5-67:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:68:5-68:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:69:5-69:24::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:76:5-79:8::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:76:5-79:8::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:80:5-84:9::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:80:5-84:9::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:85:5-89:10::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:85:5-89:10::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:90:5-94:11::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:95:5-99:12::[Warning] [W0006] this statement has no effect
app_a/src/otp27_sigils.erl:102:5-102:24::[WeakWarning] [W0051] Binary string can be written using sigil syntax.
app_a/src/otp27_sigils.erl:128:9-128:24::[Warning] [W0002] Unused macro (THIS_IS_THE_END)
app_a/src/otp27_sigils.erl:112:4-112:5::[Error] [P1711] syntax error before: X
4:15-4:18: function g/0 undefined
74:7-74:8: spec for undefined function g/0
app_a/src/otp27_sigils.erl:71:5-71:6::[Warning] [L1268] variable 'X' is unused
app_a/src/otp_7655.erl:5:1-5:28::[Error] [L1201] no module definition
app_a/src/parse_error_a_cascade.erl:10:20-11:1::[Error] [W0004] Missing 'atom'
6:6-6:11: function bar/0 undefined
app_a/src/suppressed.erl:8:5-8:9::[Warning] [L1268] variable 'Life' is unused
app_a/src/syntax.erl:5:46-5:47::[Error] [P1711] syntax error before: ')'
app_a/src/syntax.erl:11:9-11:10::[Error] [W0004] Missing ')'

View file

@ -1,4 +1,3 @@
module specified: suppressed
Diagnostics reported in 1 modules:
suppressed: 1
7:4-7:8::[Warning] [W0007] match is redundant
Diagnostics reported:
app_a/src/suppressed.erl:8:5-8:9::[Warning] [W0007] match is redundant

View file

@ -1,9 +1,10 @@
module specified: diagnostics
Diagnostics reported in 1 modules:
diagnostics: 6
diagnostics: 7
2:9-2:26::[Hint] [W0037] Unspecific include.
3:0-3:0::[Error] [L0000] Issue in included file
3:0-3:35::[Error] [L0000] Issue in included file
3:9-3:33::[Hint] [W0037] Unspecific include.
5:30-5:44::[Error] [L1295] type undefined_type/0 undefined
6:0-6:4::[Warning] [L1230] function main/1 is unused
9:0-9:3::[Warning] [L1230] function foo/0 is unused
11:7-11:11::[Warning] [W0060] Match on a bound variable

View file

@ -0,0 +1,5 @@
module specified: diagnostics
Diagnostics reported in 1 modules:
diagnostics: 2
3:0-3:35::[Error] [L0000] Issue in included file
5:30-5:44::[Error] [L1295] type undefined_type/0 undefined

View file

@ -1,6 +1,7 @@
{"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"}

View file

@ -1,11 +1,12 @@
module specified: lints
Diagnostics reported in 1 modules:
lints: 1
4:0-4:13::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
Diagnostics reported:
app_a/src/lints.erl:5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
4:1-4:14: Mismatched clause name
---------------------------------------------
Applying fix in module 'lints' for
4:0-4:13::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
5:1-5:14::[Error] [P1700] head mismatch 'head_mismatcX' vs 'head_mismatch'
4:1-4:14: Mismatched clause name
@@ -1,6 +1,6 @@
-module(lints).
-export([head_mismatch/1]).

View file

@ -1 +1 @@
{"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}

View file

@ -1,12 +1,11 @@
module specified: lint_recursive
Diagnostics reported in 1 modules:
lint_recursive: 2
18:4-18:11::[Warning] [W0007] match is redundant
13:4-13:11::[Warning] [W0007] match is redundant
Diagnostics reported:
app_a/src/lint_recursive.erl:19:5-19:12::[Warning] [W0007] match is redundant
app_a/src/lint_recursive.erl:14:5-14:12::[Warning] [W0007] match is redundant
---------------------------------------------
Applying fix in module 'lint_recursive' for
18:4-18:11::[Warning] [W0007] match is redundant
19:5-19:12::[Warning] [W0007] match is redundant
@@ -16,7 +16,7 @@
test_foo2(Config) ->
@ -21,12 +20,12 @@ Applying fix in module 'lint_recursive' for
New filtered diagnostics
lint_recursive: 2
13:4-13:11::[Warning] [W0007] match is redundant
18:4-18:10::[Warning] [W0006] this statement has no effect
14:5-14:12::[Warning] [W0007] match is redundant
19:5-19:11::[Warning] [W0006] this statement has no effect
---------------------------------------------
Applying fix in module 'lint_recursive' for
13:4-13:11::[Warning] [W0007] match is redundant
14:5-14:12::[Warning] [W0007] match is redundant
@@ -11,7 +11,7 @@
%% something/0.
test_foo(Config) ->
@ -41,12 +40,12 @@ Applying fix in module 'lint_recursive' for
New filtered diagnostics
lint_recursive: 2
18:4-18:10::[Warning] [W0006] this statement has no effect
13:4-13:10::[Warning] [W0006] this statement has no effect
19:5-19:11::[Warning] [W0006] this statement has no effect
14:5-14:11::[Warning] [W0006] this statement has no effect
---------------------------------------------
Applying fix in module 'lint_recursive' for
18:4-18:10::[Warning] [W0006] this statement has no effect
19:5-19:11::[Warning] [W0006] this statement has no effect
@@ -16,7 +16,6 @@
test_foo2(Config) ->
@ -60,12 +59,12 @@ Applying fix in module 'lint_recursive' for
New filtered diagnostics
lint_recursive: 2
16:10-16:16::[Warning] [W0010] this variable is unused
13:4-13:10::[Warning] [W0006] this statement has no effect
17:11-17:17::[Warning] [W0010] this variable is unused
14:5-14:11::[Warning] [W0006] this statement has no effect
---------------------------------------------
Applying fix in module 'lint_recursive' for
16:10-16:16::[Warning] [W0010] this variable is unused
17:11-17:17::[Warning] [W0010] this variable is unused
@@ -14,7 +14,7 @@
Config,
clean_mocks().
@ -80,11 +79,11 @@ Applying fix in module 'lint_recursive' for
New filtered diagnostics
lint_recursive: 1
13:4-13:10::[Warning] [W0006] this statement has no effect
14:5-14:11::[Warning] [W0006] this statement has no effect
---------------------------------------------
Applying fix in module 'lint_recursive' for
13:4-13:10::[Warning] [W0006] this statement has no effect
14:5-14:11::[Warning] [W0006] this statement has no effect
@@ -11,7 +11,6 @@
%% something/0.
test_foo(Config) ->
@ -98,11 +97,11 @@ Applying fix in module 'lint_recursive' for
New filtered diagnostics
lint_recursive: 1
11:9-11:15::[Warning] [W0010] this variable is unused
12:10-12:16::[Warning] [W0010] this variable is unused
---------------------------------------------
Applying fix in module 'lint_recursive' for
11:9-11:15::[Warning] [W0010] this variable is unused
12:10-12:16::[Warning] [W0010] this variable is unused
@@ -9,7 +9,7 @@
%% We want to check that the "no effect" statements in test_foo/1 and
%% test_foo2/1 are removed, but not the ones in clean_mocks/0 and

View file

@ -1,4 +1,6 @@
module specified: otp27_docstrings
Diagnostics reported in 1 modules:
otp27_docstrings: 1
otp27_docstrings: 3
23:4-23:5::[Warning] [W0060] Match on a bound variable
29:4-29:5::[Warning] [W0060] Match on a bound variable
33:8-33:23::[Warning] [W0002] Unused macro (THIS_IS_THE_END)

View file

@ -0,0 +1,2 @@
module specified: erlang_diagnostics_errors_gen
No matches found

View file

@ -0,0 +1,5 @@
module specified: erlang_diagnostics_errors_gen
erlang_diagnostics_errors_gen: 1
6:5-6:7::[WeakWarning] [ad-hoc: ssr-match] SSR pattern matched: ssr: ok.
Matches found in 1 modules

View file

@ -1,11 +1,10 @@
Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--include-tests] [--bail-on-error] [--stats] [--list-modules]
Usage: [--project PROJECT] [--as PROFILE] [[--format FORMAT]] [--rebar] [--bail-on-error] [--stats] [--list-modules]
Available options:
--project <PROJECT> Path to directory with project, or to a JSON file (defaults to `.`)
--as <PROFILE> Rebar3 profile to pickup (default is test)
--format <FORMAT> Show diagnostics in JSON format
--rebar Run with rebar
--include-tests Also eqwalize test modules from project
--bail-on-error Exit with a non-zero status code if any errors are found
--stats Print statistics when done
--list-modules When printing statistics, include the list of modules parsed

View file

@ -1,4 +1,4 @@
Usage: [--project PROJECT] [--as PROFILE] [--include-tests] [--rebar] [--bail-on-error] <APP>
Usage: [--project PROJECT] [--as PROFILE] [--rebar] [--bail-on-error] <APP>
Available positional items:
<APP> app name
@ -6,7 +6,6 @@ Available positional items:
Available options:
--project <PROJECT> Path to directory with project, or to a JSON file (defaults to `.`)
--as <PROFILE> Rebar3 profile to pickup (default is test)
--include-tests Also eqwalize test modules from project
--rebar Run with rebar
--bail-on-error Exit with a non-zero status code if any errors are found
-h, --help Prints help information

View file

@ -1,10 +1,9 @@
Usage: [--project PROJECT] [--include-tests] [--bail-on-error] <TARGET>
Usage: [--project PROJECT] [--bail-on-error] <TARGET>
Available positional items:
<TARGET> target, like //erl/chatd/...
Available options:
--project <PROJECT> Path to directory with project, or to a JSON file (defaults to `.`)
--include-tests Also eqwalize test modules from project
--bail-on-error Exit with a non-zero status code if any errors are found
-h, --help Prints help information

View file

@ -1,116 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:46:21
46 │ to_f_any_neg2(F) -> F.
│ ^
│ │
│ F.
Expression has type: 'f0' | fun((atom()) -> pid()) | 'f1'
Context expected type: fun()
Because in the expression's type:
Here the type is a union type with some valid candidates: fun((atom()) -> pid())
However the following candidate: 'f0'
Differs from the expected type: fun()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:49:23
49 │ f_any_to_f0_neg(F) -> F.
│ ^ F.
Expression has type: fun()
Context expected type: 'f0'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:61:31
61 │ when is_function(F, 1) -> F.
│ ^
│ │
│ F.
Expression has type: fun((term()) -> term())
Context expected type: f2()
Because in the expression's type:
Here the type is: fun((term()) -> term())
Context expects type: fun((term(), term()) -> term())
------------------------------ Detailed message ------------------------------
fun((term()) -> term()) is not compatible with f2()
because
fun((term()) -> term()) is not compatible with fun((term(), term()) -> term())
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/any_fun_type.erl:64:1
64 │ a_to_a(a) -> a.
│ ^^^^^^^^^^^^^^ Clause is not covered by spec
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:92:24
92 │ f5_to_f4_cov_neg(F) -> F.
│ ^
│ │
│ F.
Expression has type: f5('a' | 'b')
Context expected type: f4('a')
Because in the expression's type:
fun((term()) ->
Here the type is a union type with some valid candidates: 'a'
However the following candidate: 'b'
Differs from the expected type: 'a'
)
------------------------------ Detailed message ------------------------------
f5('a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a')
because
'a' | 'b' is not compatible with 'a'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:98:20
98 │ apply_f4_neg(F) -> F(a).
│ ^^^^ F('a').
Expression has type: number()
Context expected type: boolean()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:113:22
113 │ fun3_to_f4_neg(F) -> F.
│ ^
│ │
│ F.
Expression has type: fun((term()) -> 'a' | 'b')
Context expected type: f4('a')
Because in the expression's type:
fun((term()) ->
Here the type is a union type with some valid candidates: 'a'
However the following candidate: 'b'
Differs from the expected type: 'a'
)
------------------------------ Detailed message ------------------------------
fun((term()) -> 'a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a')
because
'a' | 'b' is not compatible with 'a'
because
'b' is not compatible with 'a'
7 ERRORS

View file

@ -1,116 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:46:21
46 │ to_f_any_neg2(F) -> F.
│ ^
│ │
│ F.
Expression has type: 'f0' | fun((atom()) -> pid()) | 'f1'
Context expected type: fun()
Because in the expression's type:
Here the type is a union type with some valid candidates: fun((atom()) -> pid())
However the following candidate: 'f0'
Differs from the expected type: fun()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:49:23
49 │ f_any_to_f0_neg(F) -> F.
│ ^ F.
Expression has type: fun()
Context expected type: 'f0'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:61:31
61 │ when is_function(F, 1) -> F.
│ ^
│ │
│ F.
Expression has type: fun((term()) -> term())
Context expected type: f2()
Because in the expression's type:
Here the type is: fun((term()) -> term())
Context expects type: fun((term(), term()) -> term())
------------------------------ Detailed message ------------------------------
fun((term()) -> term()) is not compatible with f2()
because
fun((term()) -> term()) is not compatible with fun((term(), term()) -> term())
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/any_fun_type.erl:64:1
64 │ a_to_a(a) -> a.
│ ^^^^^^^^^^^^^^ Clause is not covered by spec
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:92:24
92 │ f5_to_f4_cov_neg(F) -> F.
│ ^
│ │
│ F.
Expression has type: f5('a' | 'b')
Context expected type: f4('a')
Because in the expression's type:
fun((term()) ->
Here the type is a union type with some valid candidates: 'a'
However the following candidate: 'b'
Differs from the expected type: 'a'
)
------------------------------ Detailed message ------------------------------
f5('a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a')
because
'a' | 'b' is not compatible with 'a'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:98:20
98 │ apply_f4_neg(F) -> F(a).
│ ^^^^ F('a').
Expression has type: number()
Context expected type: boolean()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:113:22
113 │ fun3_to_f4_neg(F) -> F.
│ ^
│ │
│ F.
Expression has type: fun((term()) -> 'a' | 'b')
Context expected type: f4('a')
Because in the expression's type:
fun((term()) ->
Here the type is a union type with some valid candidates: 'a'
However the following candidate: 'b'
Differs from the expected type: 'a'
)
------------------------------ Detailed message ------------------------------
fun((term()) -> 'a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a')
because
'a' | 'b' is not compatible with 'a'
because
'b' is not compatible with 'a'
7 ERRORS

View file

@ -37,12 +37,6 @@ Because in the expression's type:
Here the type is: fun((term()) -> term())
Context expects type: fun((term(), term()) -> term())
------------------------------ Detailed message ------------------------------
fun((term()) -> term()) is not compatible with f2()
because
fun((term()) -> term()) is not compatible with fun((term(), term()) -> term())
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/any_fun_type.erl:64:1
@ -67,16 +61,6 @@ Because in the expression's type:
Differs from the expected type: 'a'
)
------------------------------ Detailed message ------------------------------
f5('a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a')
because
'a' | 'b' is not compatible with 'a'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/any_fun_type.erl:98:20
@ -103,14 +87,4 @@ Because in the expression's type:
Differs from the expected type: 'a'
)
------------------------------ Detailed message ------------------------------
fun((term()) -> 'a' | 'b') is not compatible with f4('a')
because
fun((term()) -> 'a' | 'b') is not compatible with fun((...) -> 'a')
because
'a' | 'b' is not compatible with 'a'
because
'b' is not compatible with 'a'
7 ERRORS

View file

@ -1,24 +0,0 @@
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/apply_none.erl:26:1
26 │ ╭ apply_none1(F)
27 │ │ when is_function(F, 1),
28 │ │ is_function(F, 2) ->
29 │ │ F(a).
│ ╰────────^ Clause is not covered by spec
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/apply_none.erl:32:1
32 │ apply_none2(F) -> F(ok).
│ ^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/apply_none.erl:35:1
35 │ ╭ apply_none3(F) ->
36 │ │ Res = F(ok),
37 │ │ Res.
│ ╰───────^ Clause is not covered by spec
3 ERRORS

View file

@ -1,24 +0,0 @@
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/apply_none.erl:26:1
26 │ ╭ apply_none1(F)
27 │ │ when is_function(F, 1),
28 │ │ is_function(F, 2) ->
29 │ │ F(a).
│ ╰────────^ Clause is not covered by spec
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/apply_none.erl:32:1
32 │ apply_none2(F) -> F(ok).
│ ^^^^^^^^^^^^^^^^^^^^^^^ Clause is not covered by spec
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/apply_none.erl:35:1
35 │ ╭ apply_none3(F) ->
36 │ │ Res = F(ok),
37 │ │ Res.
│ ╰───────^ Clause is not covered by spec
3 ERRORS

View file

@ -1,105 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/approx.erl:36:5
36 │ {X, X}.
│ ^^^^^^ {X, X}.
Expression has type: {dynamic(), dynamic()}
Context expected type: 'ok'
error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id)
┌─ check/src/approx.erl:39:1
39 │ generics_with_unions:type_var_from_nowhere().
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Unknown id: generics_with_unions:type_var_from_nowhere/0
error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type)
┌─ check/src/approx.erl:41:1
41 │ ╭ -spec test_trans_invalid1_neg(
42 │ │ trans_invalid()
43 │ │ ) -> nok.
│ ╰────────^ test_trans_invalid1_neg/1 references type with invalid definition: trans_invalid/0
error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type)
┌─ check/src/approx.erl:47:1
47 │ ╭ -spec test_trans_invalid2_neg(
48 │ │ trans_invalid()
49 │ │ ) -> nok.
│ ╰────────^ test_trans_invalid2_neg/1 references type with invalid definition: trans_invalid/0
error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type)
┌─ check/src/approx.erl:53:1
53 │ ╭ -spec test_trans_invalid3_neg(
54 │ │ trans_invalid()
55 │ │ ) -> nok.
│ ╰────────^ test_trans_invalid3_neg/1 references type with invalid definition: trans_invalid/0
error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type)
┌─ check/src/approx.erl:62:30
62 │ test_opaque_as_fun_neg(X) -> X(ok).
│ ^ X.
Expected fun type with arity 1
Got: misc:o() | fun((term()) -> none())
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/approx.erl:69:3
69 │ Dyn2.
│ ^^^^
│ │
│ Dyn2.
Expression has type: string() | dynamic()
Context expected type: 'anything'
Because in the expression's type:
Here the type is a union type with some valid candidates: dynamic()
However the following candidate: string()
Differs from the expected type: 'anything'
------------------------------ Detailed message ------------------------------
string() | dynamic() is not compatible with 'anything'
because
string() is not compatible with 'anything'
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/approx.erl:74:1
74 │ ╭ dyn_union_1(N, D) ->
75 │ │ Res = case D of
76 │ │ 1 -> N;
77 │ │ 2 -> D
78 │ │ end,
79 │ │ eqwalizer:reveal_type(Res),
80 │ │ Res.
│ ╰─────^ Clause is not covered by spec
error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type)
┌─ check/src/approx.erl:79:25
79 │ eqwalizer:reveal_type(Res),
│ ^^^ dynamic(number())
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/approx.erl:85:1
85 │ ╭ dyn_union_2(N, D) ->
86 │ │ Res = case D of
87 │ │ 2 -> D;
88 │ │ 1 -> N
89 │ │ end,
90 │ │ eqwalizer:reveal_type(Res),
91 │ │ Res.
│ ╰─────^ Clause is not covered by spec
error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type)
┌─ check/src/approx.erl:90:25
90 │ eqwalizer:reveal_type(Res),
│ ^^^ dynamic(number())
11 ERRORS

View file

@ -1,105 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/approx.erl:36:5
36 │ {X, X}.
│ ^^^^^^ {X, X}.
Expression has type: {dynamic(), dynamic()}
Context expected type: 'ok'
error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id)
┌─ check/src/approx.erl:39:1
39 │ generics_with_unions:type_var_from_nowhere().
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Unknown id: generics_with_unions:type_var_from_nowhere/0
error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type)
┌─ check/src/approx.erl:41:1
41 │ ╭ -spec test_trans_invalid1_neg(
42 │ │ trans_invalid()
43 │ │ ) -> nok.
│ ╰────────^ test_trans_invalid1_neg/1 references type with invalid definition: trans_invalid/0
error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type)
┌─ check/src/approx.erl:47:1
47 │ ╭ -spec test_trans_invalid2_neg(
48 │ │ trans_invalid()
49 │ │ ) -> nok.
│ ╰────────^ test_trans_invalid2_neg/1 references type with invalid definition: trans_invalid/0
error: reference_to_invalid_type (See https://fb.me/eqwalizer_errors#reference_to_invalid_type)
┌─ check/src/approx.erl:53:1
53 │ ╭ -spec test_trans_invalid3_neg(
54 │ │ trans_invalid()
55 │ │ ) -> nok.
│ ╰────────^ test_trans_invalid3_neg/1 references type with invalid definition: trans_invalid/0
error: expected_fun_type (See https://fb.me/eqwalizer_errors#expected_fun_type)
┌─ check/src/approx.erl:62:30
62 │ test_opaque_as_fun_neg(X) -> X(ok).
│ ^ X.
Expected fun type with arity 1
Got: misc:o() | fun((term()) -> none())
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/approx.erl:69:3
69 │ Dyn2.
│ ^^^^
│ │
│ Dyn2.
Expression has type: string() | dynamic()
Context expected type: 'anything'
Because in the expression's type:
Here the type is a union type with some valid candidates: dynamic()
However the following candidate: string()
Differs from the expected type: 'anything'
------------------------------ Detailed message ------------------------------
string() | dynamic() is not compatible with 'anything'
because
string() is not compatible with 'anything'
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/approx.erl:74:1
74 │ ╭ dyn_union_1(N, D) ->
75 │ │ Res = case D of
76 │ │ 1 -> N;
77 │ │ 2 -> D
78 │ │ end,
79 │ │ eqwalizer:reveal_type(Res),
80 │ │ Res.
│ ╰─────^ Clause is not covered by spec
error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type)
┌─ check/src/approx.erl:79:25
79 │ eqwalizer:reveal_type(Res),
│ ^^^ dynamic(number())
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/approx.erl:85:1
85 │ ╭ dyn_union_2(N, D) ->
86 │ │ Res = case D of
87 │ │ 2 -> D;
88 │ │ 1 -> N
89 │ │ end,
90 │ │ eqwalizer:reveal_type(Res),
91 │ │ Res.
│ ╰─────^ Clause is not covered by spec
error: reveal_type (See https://fb.me/eqwalizer_errors#reveal_type)
┌─ check/src/approx.erl:90:25
90 │ eqwalizer:reveal_type(Res),
│ ^^^ dynamic(number())
11 ERRORS

View file

@ -60,12 +60,6 @@ Because in the expression's type:
However the following candidate: string()
Differs from the expected type: 'anything'
------------------------------ Detailed message ------------------------------
string() | dynamic() is not compatible with 'anything'
because
string() is not compatible with 'anything'
error: clause_not_covered (See https://fb.me/eqwalizer_errors#clause_not_covered)
┌─ check/src/approx.erl:74:1

View file

@ -1,17 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/as_pat.erl:51:38
51 │ unboxL_neg(BN = #box_n{}) -> unbox_a(BN).
│ ^^ BN.
Expression has type: #box_n{}
Context expected type: #box_a{}
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/as_pat.erl:61:38
61 │ unboxR_neg(#box_n{} = BN) -> unbox_b(BN).
│ ^^ BN.
Expression has type: #box_n{}
Context expected type: #box_b{}
2 ERRORS

View file

@ -1,17 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/as_pat.erl:51:38
51 │ unboxL_neg(BN = #box_n{}) -> unbox_a(BN).
│ ^^ BN.
Expression has type: #box_n{}
Context expected type: #box_a{}
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/as_pat.erl:61:38
61 │ unboxR_neg(#box_n{} = BN) -> unbox_b(BN).
│ ^^ BN.
Expression has type: #box_n{}
Context expected type: #box_b{}
2 ERRORS

View file

@ -1,16 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/auto_imports.erl:22:20
22 │ erlang:error(ok, ok).
│ ^^
│ │
│ 'ok'.
Expression has type: 'ok'
Context expected type: [term()] | 'none'
'ok' is not compatible with [term()] | 'none'
because
'ok' is not compatible with [term()]
1 ERROR

View file

@ -1,16 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/auto_imports.erl:22:20
22 │ erlang:error(ok, ok).
│ ^^
│ │
│ 'ok'.
Expression has type: 'ok'
Context expected type: [term()] | 'none'
'ok' is not compatible with [term()] | 'none'
because
'ok' is not compatible with [term()]
1 ERROR

View file

@ -2,15 +2,8 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types
┌─ check/src/auto_imports.erl:22:20
22 │ erlang:error(ok, ok).
│ ^^
│ │
│ 'ok'.
│ ^^ 'ok'.
Expression has type: 'ok'
Context expected type: [term()] | 'none'
'ok' is not compatible with [term()] | 'none'
because
'ok' is not compatible with [term()]
1 ERROR

View file

@ -1,13 +0,0 @@
error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id)
┌─ check/src/behave.erl:8:20
8 │ -callback foo() -> behave1:test().
│ ^^^^^^^^^^^^^^ Unknown id: behave1:test/0
error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var)
┌─ check/src/behave.erl:10:1
10 │ -type invalid() :: _T.
│ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound.
2 ERRORS

View file

@ -1,13 +0,0 @@
error: unknown_id (See https://fb.me/eqwalizer_errors#unknown_id)
┌─ check/src/behave.erl:8:20
8 │ -callback foo() -> behave1:test().
│ ^^^^^^^^^^^^^^ Unknown id: behave1:test/0
error: unbound_type_var (See https://fb.me/eqwalizer_errors#unbound_type_var)
┌─ check/src/behave.erl:10:1
10 │ -type invalid() :: _T.
│ ^^^^^^^^^^^^^^^^^^^^^ _T: Type variable is unbound.
2 ERRORS

View file

@ -1,65 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:24:17
24 │ test04_neg() -> <<>>.
│ ^^^^ <<..>>.
Expression has type: binary()
Context expected type: [term()]
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:32:20
32 │ test05_neg(A) -> <<A/signed>>.
│ ^ A.
Expression has type: atom()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:35:23
35 │ test06_neg(A, S) -> <<A:S>>.
│ ^ A.
Expression has type: atom()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:38:18
38 │ test07_neg(A) -> [A].
│ ^^^ [A].
Expression has type: [atom()]
Context expected type: binary()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:55:7
55 │ <<"binary"/binary>>.
│ ^^^^^^^^ string_lit.
Expression has type: string()
Context expected type: binary()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:74:9
74 │ <<X:A>> = Bits,
│ ^ A.
Expression has type: atom()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:80:9
80 │ <<X:(self())>> = Bits,
│ ^^^^^^^^ erlang:self().
Expression has type: pid()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:89:7
89 │ <<[]>>.
│ ^^ [].
Expression has type: []
Context expected type: number()
8 ERRORS

View file

@ -1,65 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:24:17
24 │ test04_neg() -> <<>>.
│ ^^^^ <<..>>.
Expression has type: binary()
Context expected type: [term()]
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:32:20
32 │ test05_neg(A) -> <<A/signed>>.
│ ^ A.
Expression has type: atom()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:35:23
35 │ test06_neg(A, S) -> <<A:S>>.
│ ^ A.
Expression has type: atom()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:38:18
38 │ test07_neg(A) -> [A].
│ ^^^ [A].
Expression has type: [atom()]
Context expected type: binary()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:55:7
55 │ <<"binary"/binary>>.
│ ^^^^^^^^ string_lit.
Expression has type: string()
Context expected type: binary()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:74:9
74 │ <<X:A>> = Bits,
│ ^ A.
Expression has type: atom()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:80:9
80 │ <<X:(self())>> = Bits,
│ ^^^^^^^^ erlang:self().
Expression has type: pid()
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/binaries.erl:89:7
89 │ <<[]>>.
│ ^^ [].
Expression has type: []
Context expected type: number()
8 ERRORS

View file

@ -1,31 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/booleans.erl:47:3
47 │ 1 andalso b().
│ ^ 1.
Expression has type: number()
Context expected type: boolean()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/booleans.erl:59:3
59 │ dyn() andalso only_true().
│ ^^^^^^^^^^^^^^^^^^^^^^^^^
│ │
│ _ andalso _.
Expression has type: 'false' | 'true'
Context expected type: 'true'
Because in the expression's type:
Here the type is a union type with some valid candidates: 'true'
However the following candidate: 'false'
Differs from the expected type: 'true'
------------------------------ Detailed message ------------------------------
'false' | 'true' is not compatible with 'true'
because
'false' is not compatible with 'true'
2 ERRORS

View file

@ -1,31 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/booleans.erl:47:3
47 │ 1 andalso b().
│ ^ 1.
Expression has type: number()
Context expected type: boolean()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/booleans.erl:59:3
59 │ dyn() andalso only_true().
│ ^^^^^^^^^^^^^^^^^^^^^^^^^
│ │
│ _ andalso _.
Expression has type: 'false' | 'true'
Context expected type: 'true'
Because in the expression's type:
Here the type is a union type with some valid candidates: 'true'
However the following candidate: 'false'
Differs from the expected type: 'true'
------------------------------ Detailed message ------------------------------
'false' | 'true' is not compatible with 'true'
because
'false' is not compatible with 'true'
2 ERRORS

View file

@ -22,10 +22,4 @@ Because in the expression's type:
However the following candidate: 'false'
Differs from the expected type: 'true'
------------------------------ Detailed message ------------------------------
'false' | 'true' is not compatible with 'true'
because
'false' is not compatible with 'true'
2 ERRORS

View file

@ -1,14 +0,0 @@
error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation)
┌─ check/src/callbacks3_neg.erl:12:1
12 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^
│ │
│ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}, Got: 'wrong_ret'.
'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}
because
'wrong_ret' is not compatible with {'noreply', term()}
1 ERROR

View file

@ -1,14 +0,0 @@
error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation)
┌─ check/src/callbacks3_neg.erl:12:1
12 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^
│ │
│ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}, Got: 'wrong_ret'.
'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}
because
'wrong_ret' is not compatible with {'noreply', term()}
1 ERROR

View file

@ -1,14 +0,0 @@
error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation)
┌─ check/src/callbacks3_neg.erl:12:1
12 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^
│ │
│ Incorrect return type for implementation of gen_server:handle_cast/2. Expected: {'noreply', term()} | {'noreply', term(), gen_server:action()} | {'stop', term(), term()}, Got: 'wrong_ret'.
'wrong_ret' is not compatible with {'noreply', term()} | {'noreply', term(), gen_server:action()} | {'stop', term(), term()}
because
'wrong_ret' is not compatible with {'noreply', term()}
1 ERROR

View file

@ -0,0 +1,27 @@
error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation)
┌─ check/src/callbacks3_neg.erl:13:1
13 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^ Incorrect return type for implementation of gen_server:handle_cast/2.
Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}
Got: 'wrong_ret'
error: incorrect_return_type_in_cb_implementation (See https://fb.me/eqwalizer_errors#incorrect_return_type_in_cb_implementation)
┌─ check/src/callbacks3_neg.erl:13:1
13 │ -behavior(gen_server).
│ ^^^^^^^^^^^^^^^^^^^^^
│ │
│ Incorrect return type for implementation of gen_server:handle_info/2.
Expected: {'noreply', term()} | {'noreply', term(), timeout() | 'hibernate' | {'continue', term()}} | {'stop', term(), term()}
Got: {'noreply', 'ok', 'wrong_atom'}
Because in the expression's type:
{ 'noreply', 'ok',
Here the type is: 'wrong_atom'
Context expects type: 'infinity' | number() | 'hibernate' | {'continue', term()}
No candidate matches in the expected union.
}
2 ERRORS

View file

@ -1,7 +0,0 @@
error: behaviour_does_not_exist (See https://fb.me/eqwalizer_errors#behaviour_does_not_exist)
┌─ check/src/callbacks4_neg.erl:9:1
9 │ -behaviour(nonexistent).
│ ^^^^^^^^^^^^^^^^^^^^^^^ Behaviour does not exist: nonexistent
1 ERROR

View file

@ -1,7 +0,0 @@
error: behaviour_does_not_exist (See https://fb.me/eqwalizer_errors#behaviour_does_not_exist)
┌─ check/src/callbacks4_neg.erl:9:1
9 │ -behaviour(nonexistent).
│ ^^^^^^^^^^^^^^^^^^^^^^^ Behaviour does not exist: nonexistent
1 ERROR

View file

@ -1,7 +0,0 @@
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'.
1 ERROR

View file

@ -1,7 +0,0 @@
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'.
1 ERROR

View file

@ -1,13 +0,0 @@
error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation)
┌─ check/src/callbacks6_neg.erl:8:1
8 │ -behavior(behave).
│ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid/0
error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation)
┌─ check/src/callbacks6_neg.erl:8:1
8 │ -behavior(behave).
│ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid2/0
2 ERRORS

View file

@ -1,13 +0,0 @@
error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation)
┌─ check/src/callbacks6_neg.erl:8:1
8 │ -behavior(behave).
│ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid/0
error: missing_cb_implementation (See https://fb.me/eqwalizer_errors#missing_cb_implementation)
┌─ check/src/callbacks6_neg.erl:8:1
8 │ -behavior(behave).
│ ^^^^^^^^^^^^^^^^^ Missing implementation for behave callback use_invalid2/0
2 ERRORS

View file

@ -1,140 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:13:24
13 │ {true, true} -> aa(X, Y);
│ ^ X.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:13:27
13 │ {true, true} -> aa(X, Y);
│ ^ Y.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:14:20
14 │ {true, _} -> a(X);
│ ^ X.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:15:20
15 │ {_, true} -> a(Y);
│ ^ Y.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:16:10
16 │ _ -> not-ok
│ ^^^^^^ not _.
Expression has type: boolean()
Context expected type: 'ok' | 'not_ok'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:16:13
16 │ _ -> not-ok
│ ^^^ - _.
Expression has type: number()
Context expected type: boolean()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:16:14
16 │ _ -> not-ok
│ ^^ 'ok'.
Expression has type: 'ok'
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:124:14
124 │ false -> {p, X}
│ ^^^^^^
│ │
│ {'p', X}.
Expression has type: {'p', none() | pid() | reference()}
Context expected type: {'a', atom()} | {'p', pid()}
Because in the expression's type:
{ 'p',
Here the type is a union type with some valid candidates: pid()
However the following candidate: reference()
Differs from the expected type: pid()
}
------------------------------ Detailed message ------------------------------
{'p', none() | pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()}
because
at tuple index 2:
{'p', none() | pid() | reference()} is not compatible with {'p', pid()}
because
none() | pid() | reference() is not compatible with pid()
because
reference() is not compatible with pid()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:144:10
144 │ _ -> X
│ ^
│ │
│ X.
Expression has type: 'undefined' | none() | 'restarting'
Context expected type: {'p', pid()} | 'undefined'
Because in the expression's type:
Here the type is a union type with some valid candidates: 'undefined'
However the following candidate: 'restarting'
Differs from the expected type: {'p', pid()} | 'undefined'
------------------------------ Detailed message ------------------------------
'undefined' | none() | 'restarting' is not compatible with {'p', pid()} | 'undefined'
because
'restarting' is not compatible with {'p', pid()} | 'undefined'
because
'restarting' is not compatible with {'p', pid()}
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:174:16
174 │ lists:nth(1, L).
│ ^
│ │
│ L.
Expression has type: #{dynamic() => dynamic()} | none()
Context expected type: [T]
Because in the expression's type:
Here the type is: #{dynamic() => dynamic()}
Context expects type: [T]
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:174:16
174 │ lists:nth(1, L).
│ ^
│ │
│ L.
Expression has type: #{dynamic() => dynamic()} | none()
Context expected type: [dynamic()]
Because in the expression's type:
Here the type is: #{dynamic() => dynamic()}
Context expects type: [dynamic()]
11 ERRORS

View file

@ -1,140 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:13:24
13 │ {true, true} -> aa(X, Y);
│ ^ X.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:13:27
13 │ {true, true} -> aa(X, Y);
│ ^ Y.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:14:20
14 │ {true, _} -> a(X);
│ ^ X.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:15:20
15 │ {_, true} -> a(Y);
│ ^ Y.
Expression has type: term()
Context expected type: atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:16:10
16 │ _ -> not-ok
│ ^^^^^^ not _.
Expression has type: boolean()
Context expected type: 'ok' | 'not_ok'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:16:13
16 │ _ -> not-ok
│ ^^^ - _.
Expression has type: number()
Context expected type: boolean()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:16:14
16 │ _ -> not-ok
│ ^^ 'ok'.
Expression has type: 'ok'
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:124:14
124 │ false -> {p, X}
│ ^^^^^^
│ │
│ {'p', X}.
Expression has type: {'p', none() | pid() | reference()}
Context expected type: {'a', atom()} | {'p', pid()}
Because in the expression's type:
{ 'p',
Here the type is a union type with some valid candidates: pid()
However the following candidate: reference()
Differs from the expected type: pid()
}
------------------------------ Detailed message ------------------------------
{'p', none() | pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()}
because
at tuple index 2:
{'p', none() | pid() | reference()} is not compatible with {'p', pid()}
because
none() | pid() | reference() is not compatible with pid()
because
reference() is not compatible with pid()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:144:10
144 │ _ -> X
│ ^
│ │
│ X.
Expression has type: 'undefined' | none() | 'restarting'
Context expected type: {'p', pid()} | 'undefined'
Because in the expression's type:
Here the type is a union type with some valid candidates: 'undefined'
However the following candidate: 'restarting'
Differs from the expected type: {'p', pid()} | 'undefined'
------------------------------ Detailed message ------------------------------
'undefined' | none() | 'restarting' is not compatible with {'p', pid()} | 'undefined'
because
'restarting' is not compatible with {'p', pid()} | 'undefined'
because
'restarting' is not compatible with {'p', pid()}
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:174:16
174 │ lists:nth(1, L).
│ ^
│ │
│ L.
Expression has type: #{dynamic() => dynamic()} | none()
Context expected type: [T]
Because in the expression's type:
Here the type is: #{dynamic() => dynamic()}
Context expects type: [T]
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:174:16
174 │ lists:nth(1, L).
│ ^
│ │
│ L.
Expression has type: #{dynamic() => dynamic()} | none()
Context expected type: [dynamic()]
Because in the expression's type:
Here the type is: #{dynamic() => dynamic()}
Context expects type: [dynamic()]
11 ERRORS

View file

@ -61,7 +61,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types
│ ^^^^^^
│ │
│ {'p', X}.
Expression has type: {'p', none() | pid() | reference()}
Expression has type: {'p', pid() | reference()}
Context expected type: {'a', atom()} | {'p', pid()}
@ -72,17 +72,6 @@ Because in the expression's type:
Differs from the expected type: pid()
}
------------------------------ Detailed message ------------------------------
{'p', none() | pid() | reference()} is not compatible with {'a', atom()} | {'p', pid()}
because
at tuple index 2:
{'p', none() | pid() | reference()} is not compatible with {'p', pid()}
because
none() | pid() | reference() is not compatible with pid()
because
reference() is not compatible with pid()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:144:10
@ -90,7 +79,7 @@ error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types
│ ^
│ │
│ X.
Expression has type: 'undefined' | none() | 'restarting'
Expression has type: 'undefined' | 'restarting'
Context expected type: {'p', pid()} | 'undefined'
@ -99,42 +88,20 @@ Because in the expression's type:
However the following candidate: 'restarting'
Differs from the expected type: {'p', pid()} | 'undefined'
------------------------------ Detailed message ------------------------------
'undefined' | none() | 'restarting' is not compatible with {'p', pid()} | 'undefined'
because
'restarting' is not compatible with {'p', pid()} | 'undefined'
because
'restarting' is not compatible with {'p', pid()}
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:174:16
174 │ lists:nth(1, L).
│ ^
│ │
│ L.
Expression has type: #{dynamic() => dynamic()} | none()
│ ^ L.
Expression has type: #{dynamic() => dynamic()}
Context expected type: [T]
Because in the expression's type:
Here the type is: #{dynamic() => dynamic()}
Context expects type: [T]
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/case_predicates.erl:174:16
174 │ lists:nth(1, L).
│ ^
│ │
│ L.
Expression has type: #{dynamic() => dynamic()} | none()
│ ^ L.
Expression has type: #{dynamic() => dynamic()}
Context expected type: [dynamic()]
Because in the expression's type:
Here the type is: #{dynamic() => dynamic()}
Context expects type: [dynamic()]
11 ERRORS

View file

@ -1,9 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/test/check_SUITE.erl:13:11
13 │ fail() -> wrong_ret.
│ ^^^^^^^^^ 'wrong_ret'.
Expression has type: 'wrong_ret'
Context expected type: pid()
1 ERROR

View file

@ -1,9 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/test/check_SUITE.erl:13:11
13 │ fail() -> wrong_ret.
│ ^^^^^^^^^ 'wrong_ret'.
Expression has type: 'wrong_ret'
Context expected type: pid()
1 ERROR

View file

@ -1,300 +0,0 @@
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:11:21
11 │ downcast_neg1(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', c => 'd'}
Context expected type: #{a => 'b'}
Because in the expression's type:
Here the type is: #{c => ...}
Context expects type: #{...}
The expected map has no corresponding key for: c.
------------------------------ Detailed message ------------------------------
key `c` is declared in the former but not in the latter and the latter map has no default association
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:17:21
17 │ downcast_neg2(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', c => 'd'}
Context expected type: #{a => 'b', atom() => number()}
Because in the expression's type:
#{ c =>
Here the type is: 'd'
Context expects type: number()
, ... }
------------------------------ Detailed message ------------------------------
#{a => 'b', c => 'd'} is not compatible with #{a => 'b', atom() => number()}
because
#{a => 'b', c => 'd'} is not compatible with #{a => 'b', atom() => number()}
key `c` is declared in the former but not in the latter and key `c` isn't compatible with the default association of the latter map
because
'd' is not compatible with number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:20:19
20 │ upcast_neg1(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', atom() => atom()}
Context expected type: #{a => 'b', c => 'd'}
Because in the expression's type:
Here the type is: #{atom() => atom()}
Context expects type: #{...} (no default association)
The expected map has no default association while the type of the expression has one.
------------------------------ Detailed message ------------------------------
#{a => 'b', atom() => atom()} is not compatible with #{a => 'b', c => 'd'}
key c is not present in the former map but is incompatible with its default association
because
atom() is not compatible with 'd'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:23:19
23 │ upcast_neg2(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', atom() => number()}
Context expected type: #{a => 'b', c => 'd', atom() => number()}
Because in the expression's type:
#{ atom() =>
Here the type is: number()
Context expects type: 'd'
, ... }
The context introduces a new association c => 'd' which is incompatible with the expression's default association.
------------------------------ Detailed message ------------------------------
#{a => 'b', atom() => number()} is not compatible with #{a => 'b', c => 'd', atom() => number()}
key c is not present in the former map but is incompatible with its default association
because
number() is not compatible with 'd'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:38:21
38 │ downcast_neg3(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', atom() => atom()}
Context expected type: #{a => 'b'}
Because in the expression's type:
Here the type is: #{atom() => atom()}
Context expects type: #{...} (no default association)
The expected map has no default association while the type of the expression has one.
------------------------------ Detailed message ------------------------------
#{a => 'b', atom() => atom()} is not compatible with #{a => 'b'}
because
#{a => 'b', atom() => atom()} is not compatible with #{a => 'b'}
the latter map has no default association while the first map has one
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:44:26
44 │ downcast_dyn_neg_1(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', dynamic(atom()) => atom()}
Context expected type: #{a => 'b'}
Because in the expression's type:
Here the type is: #{dynamic(atom()) => atom()}
Context expects type: #{...} (no default association)
The expected map has no default association while the type of the expression has one.
------------------------------ Detailed message ------------------------------
#{a => 'b', dynamic(atom()) => atom()} is not compatible with #{a => 'b'}
because
#{a => 'b', dynamic(atom()) => atom()} is not compatible with #{a => 'b'}
the latter map has no default association while the first map has one
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:47:26
47 │ downcast_dyn_neg_2(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a => 'b', atom() => dynamic(atom())}
Context expected type: #{a => 'b'}
Because in the expression's type:
Here the type is: #{atom() => dynamic(atom())}
Context expects type: #{...} (no default association)
The expected map has no default association while the type of the expression has one.
------------------------------ Detailed message ------------------------------
#{a => 'b', atom() => dynamic(atom())} is not compatible with #{a => 'b'}
because
#{a => 'b', atom() => dynamic(atom())} is not compatible with #{a => 'b'}
the latter map has no default association while the first map has one
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:56:44
56 │ tuple_key_get_neg(#{{ok, {a, b}} := V}) -> V.
│ ^ V.
Expression has type: 'v'
Context expected type: 'err'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:62:30
62 │ tuple_key_maps_get_neg(M) -> maps:get({ok, {a, b}}, M).
│ ^^^^^^^^^^^^^^^^^^^^^^^^^ maps:get({'ok', {'a', 'b'}}, M).
Expression has type: 'v'
Context expected type: 'err'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:71:32
71 │ get_default_neg1(#{a := V}) -> V.
│ ^ V.
Expression has type: 'b'
Context expected type: number()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:74:34
74 │ get_default_neg2(#{def := V}) -> V.
│ ^ V.
Expression has type: number()
Context expected type: 'b'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:77:41
77 │ match_required_1_neg(#{b := _V} = M) -> M.
│ ^ M.
Expression has type: #{a := number(), b := dynamic(), atom() => dynamic()}
Context expected type: 'ok'
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:80:28
80 │ compat_default_1_neg(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{atom() => binary()}
Context expected type: #{a => binary(), atom() => atom()}
Because in the expression's type:
#{ atom() =>
Here the type is: binary()
Context expects type: atom()
, ... }
------------------------------ Detailed message ------------------------------
#{atom() => binary()} is not compatible with #{a => binary(), atom() => atom()}
the default associations are not compatible
because
binary() is not compatible with atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:83:28
83 │ compat_default_2_neg(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a := 'b', atom() => binary()}
Context expected type: #{a => 'b', {c, d} => atom() | binary(), term() => atom()}
Because in the expression's type:
#{ atom() =>
Here the type is: binary()
Context expects type: atom()
, ... }
------------------------------ Detailed message ------------------------------
#{a := 'b', atom() => binary()} is not compatible with #{a => 'b', {c, d} => atom() | binary(), term() => atom()}
the default associations are not compatible
because
binary() is not compatible with atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:86:28
86 │ compat_default_3_neg(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{a := 'b', atom() => binary()}
Context expected type: #{a => 'b', {c, d} => atom() | binary(), atom() => atom()}
Because in the expression's type:
#{ atom() =>
Here the type is: binary()
Context expects type: atom()
, ... }
------------------------------ Detailed message ------------------------------
#{a := 'b', atom() => binary()} is not compatible with #{a => 'b', {c, d} => atom() | binary(), atom() => atom()}
the default associations are not compatible
because
binary() is not compatible with atom()
error: incompatible_types (See https://fb.me/eqwalizer_errors#incompatible_types)
┌─ check/src/complex_maps.erl:89:29
89 │ dyn_domain_coerce_neg(X) -> X.
│ ^
│ │
│ X.
Expression has type: #{dynamic() => atom()}
Context expected type: #{dynamic() => binary()}
Because in the expression's type:
#{ dynamic() =>
Here the type is: atom()
Context expects type: binary()
, ... }
------------------------------ Detailed message ------------------------------
#{dynamic() => atom()} is not compatible with #{dynamic() => binary()}
the default associations are not compatible
because
atom() is not compatible with binary()
16 ERRORS

Some files were not shown because too many files have changed in this diff Show more