Commit Graph

54 Commits

Author SHA1 Message Date
Micha Reiser d40590c8f9
[ty] Add code action to ignore diagnostic on the current line (#21595) 2025-11-29 15:41:54 +01:00
Micha Reiser 2a5ace6e55
[ty] Implement diagnostic caching (#19605) 2025-07-30 11:04:34 +01:00
Brent Westbrook 77a5c5ac80
Combine `OldDiagnostic` and `Diagnostic` (#19053)
## Summary

This PR is a collaboration with @AlexWaygood from our pairing session
last Friday.

The main goal here is removing `ruff_linter::message::OldDiagnostic` in
favor of
using `ruff_db::diagnostic::Diagnostic` directly. This involved a few
major steps:

- Transferring the fields
- Transferring the methods and trait implementations, where possible
- Converting some constructor methods to free functions
- Moving the `SecondaryCode` struct
- Updating the method names

I'm hoping that some of the methods, especially those in the
`expect_ruff_*`
family, won't be necessary long-term, but I avoided trying to replace
them
entirely for now to keep the already-large diff a bit smaller.

### Related refactors

Alex and I noticed a few refactoring opportunities while looking at the
code,
specifically the very similar implementations for
`create_parse_diagnostic`,
`create_unsupported_syntax_diagnostic`, and
`create_semantic_syntax_diagnostic`.
We combined these into a single generic function, which I then copied
into
`ruff_linter::message` with some small changes and a TODO to combine
them in the
future.

I also deleted the `DisplayParseErrorType` and `TruncateAtNewline` types
for
reporting parse errors. These were added in #4124, I believe to work
around the
error messages from LALRPOP. Removing these didn't affect any tests, so
I think
they were unnecessary now that we fully control the error messages from
the
parser.

On a more minor note, I factored out some calls to the
`OldDiagnostic::filename`
(now `Diagnostic::expect_ruff_filename`) function to avoid repeatedly
allocating
`String`s in some places.

### Snapshot changes

The `show_statistics_syntax_errors` integration test changed because the
`OldDiagnostic::name` method used `syntax-error` instead of
`invalid-syntax`
like in ty. I think this (`--statistics`) is one of the only places we
actually
use this name for syntax errors, so I hope this is okay. An alternative
is to
use `syntax-error` in ty too.

The other snapshot changes are from removing this code, as discussed on

[Discord](https://discord.com/channels/1039017663004942429/1228460843033821285/1388252408848847069):


34052a1185/crates/ruff_linter/src/message/mod.rs (L128-L135)

I think both of these are technically breaking changes, but they only
affect
syntax errors and are very narrow in scope, while also pretty
substantially
simplifying the refactor, so I hope they're okay to include in a patch
release.

## Test plan

Existing tests, with the adjustments mentioned above

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-07-03 13:01:09 -04:00
Brent Westbrook 9925910a29
Add a `ViolationMetadata::rule` method (#18234)
Summary
--

This PR adds a macro-generated method to retrieve the `Rule` associated
with a given `Violation` struct, which makes it substantially cheaper
than parsing from the rule name. The rule is then converted to a
`NoqaCode` for storage on the `Message` (and eventually on the new
diagnostic type). The `ViolationMetadata::rule_name` method was now
unused, so the `rule` method replaces it.

Several types had to be moved from the `ruff_diagnostics` crate to the
`ruff_linter` crate to make this work, namely the `Violation` traits and
the old `Diagnostic` type, which had a constructor generic over a
`Violation`.

It's actually a fairly small PR, minus the hundreds of import changes.
The main changes are in these files:

-
[crates/ruff_linter/src/message/mod.rs](https://github.com/astral-sh/ruff/pull/18234/files#diff-139754ea310d75f28307008d21c771a190038bd106efe3b9267cc2d6c0fa0921)
-
[crates/ruff_diagnostics/src/lib.rs](https://github.com/astral-sh/ruff/pull/18234/files#diff-8e8ea5c586935bf21ea439f24253fcfd5955d2cb130f5377c2fa7bfee3ea3a81)
-
[crates/ruff_linter/src/diagnostic.rs](https://github.com/astral-sh/ruff/pull/18234/files#diff-1d0c9aad90d8f9446079c5be5f284150d97797158715bd9729e6f1f70246297a)
-
[crates/ruff_linter/src/lib.rs](https://github.com/astral-sh/ruff/pull/18234/files#diff-eb93ef7e78a612f5fa9145412c75cf6b1a5cefba1c2233e4a11a880a1ce1fbcc)

Test Plan
--

Existing tests
2025-05-28 09:27:09 -04:00
Brent Westbrook e2c5b83fe1
Inline `DiagnosticKind` into other diagnostic types (#18074)
## Summary

This PR deletes the `DiagnosticKind` type by inlining its three fields
(`name`, `body`, and `suggestion`) into three other diagnostic types:
`Diagnostic`, `DiagnosticMessage`, and `CacheMessage`.

Instead of deferring to an internal `DiagnosticKind`, both `Diagnostic`
and `DiagnosticMessage` now have their own macro-generated `AsRule`
implementations.

This should make both https://github.com/astral-sh/ruff/pull/18051 and
another follow-up PR changing the type of `name` on `CacheMessage`
easier since its type will be able to change separately from
`Diagnostic` and `DiagnosticMessage`.

## Test Plan

Existing tests
2025-05-15 10:27:21 -04:00
Dylan 706d87f239
Show errors for attempted fixes only when passed `--verbose` (#15237)
The default logging level for diagnostics includes logs written using
the `log` crate with level `error`, `warn`, and `info`. An unsuccessful
fix attached to a diagnostic via `try_set_fix` or `try_set_optional_fix`
was logged at level `error`. Note that the user would see these messages
even without passing `--fix`, and possibly also on lines with `noqa`
comments.

This PR changes the logging level here to a `debug`. We also found
ad-hoc instances of error logging in the implementations of several
rules, and have replaced those with either a `debug` or call to
`try_set{_optional}_fix`.

Closes #15229
2025-01-03 08:50:13 -06:00
Micha Reiser b63c2e126b
Upgrade Rust toolchain to 1.83 (#14677) 2024-11-29 12:05:05 +00:00
Micha Reiser 14ba469fc0
Use a derive macro for Violations (#14557)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-11-27 09:41:40 +00:00
Charlie Marsh 95c8f5fd0f
Document comment policy around fix safety (#14300)
## Summary

Closes https://github.com/astral-sh/ruff/issues/9790.
2024-11-13 08:03:58 -05:00
Yury Fedotov feba5031dc
[Minor typo] Fix article in "an fix" (#12797) 2024-08-10 21:22:00 -04:00
Charlie Marsh 7fb5f47efe
Respect `# noqa` directives on `__all__` openers (#10798)
## Summary

Historically, given:

```python
__all__ = [  # noqa: F822
    "Bernoulli",
    "Beta",
    "Binomial",
]
```

The F822 violations would be attached to the `__all__`, so this `# noqa`
would be enforced for _all_ definitions in the list. This changed in
https://github.com/astral-sh/ruff/pull/10525 for the better, in that we
now use the range of each string. But these `# noqa` directives stopped
working.

This PR sets the `__all__` as a parent range in the diagnostic, so that
these directives are respected once again.

Closes https://github.com/astral-sh/ruff/issues/10795.

## Test Plan

`cargo test`
2024-04-06 14:51:17 +00:00
Micha Reiser b49b861b2d
Delete unused `Violation::explanation` method (#10600) 2024-03-26 12:35:27 +01:00
Charlie Marsh d1a7bc38ff
Enable annotation quoting for multi-line expressions (#9142)
Given:

```python
x: DataFrame[
    int
] = 1
```

We currently wrap the annotation in single quotes, which leads to a
syntax error:

```python
x: "DataFrame[
    int
]" = 1
```

There are a few options for what to suggest for users here... Use triple
quotes:

```python
x: """DataFrame[
    int
]""" = 1
```

Or, use an implicit string concatenation (which may require
parentheses):

```python
x: ("DataFrame["
    "int"
"]") = 1
```

The solution I settled on here is to use the `Generator`, which
effectively means we write it out on a single line, like:

```python
x: "DataFrame[int]" = 1
```

It's kind of the "least opinionated" solution, but it does mean we'll
expand to a very long line in some cases.

Closes https://github.com/astral-sh/ruff/issues/9136.
2023-12-15 01:03:09 +00:00
Zanie Blue 7873ca38e5
Update applicability messages for clarity in tests (#8541)
These names are only ever displayed internally right now and we could be
clearer in our test snapshots.

The diff is kind of scary because all of the tests fixtures are updated.
2023-11-07 16:11:43 +00:00
Charlie Marsh 5e2bb8ca07
Add a `Fix` constructor that takes `Applicability` as an argument (#8514)
## Summary

If you want to create an edit with dynamic applicability, you have to
branch and repeat the edit entirely between the two branches. If you
further need the edit itself to be dynamic (e.g., perhaps you have a
single edit in one case, vs. multiple in another), you suddenly have
four branches. This PR just adds an alternate constructor that takes
applicability as an argument, as an escape hatch.
2023-11-06 09:45:10 -05:00
Zanie Blue 739a8aa10e
Add settings for promoting and demoting fixes (#7841)
Adds two configuration-file only settings `extend-safe-fixes` and
`extend-unsafe-fixes` which can be used to promote and demote the
applicability of fixes for rules.

Fixes with `Never` applicability cannot be promoted.
2023-10-10 20:04:21 +00:00
Zanie Blue 0fc76ba276
Rename applicability levels to `Safe`, `Unsafe`, and `Display` (#7843)
After working with the previous change in
https://github.com/astral-sh/ruff/pull/7821 I found the names a bit
unclear and their relationship with the user-facing API muddied. Since
the applicability is exposed to the user directly in our JSON output, I
think it's important that these names align with our configuration
options. I've replaced `Manual` or `Never` with `Display` which captures
our intent for these fixes (only for display). Here, we create room for
future levels, such as `HasPlaceholders`, which wouldn't fit into the
`Always`/`Sometimes`/`Never` levels.

Unlike https://github.com/astral-sh/ruff/pull/7819, this retains the
flat enum structure which is easier to work with.
2023-10-06 20:50:05 -05:00
Zanie Blue 22e18741bd
Update CLI to respect fix applicability (#7769)
Rebase of https://github.com/astral-sh/ruff/pull/5119 authored by
@evanrittenhouse with additional refinements.

## Changes

- Adds `--unsafe-fixes` / `--no-unsafe-fixes` flags to `ruff check`
- Violations with unsafe fixes are not shown as fixable unless opted-in
- Fix applicability is respected now
    - `Applicability::Never` fixes are no longer applied
    - `Applicability::Sometimes` fixes require opt-in
    - `Applicability::Always` fixes are unchanged
- Hints for availability of `--unsafe-fixes` added to `ruff check`
output

## Examples

Check hints at hidden unsafe fixes
```
❯ ruff check example.py --no-cache --select F601,W292
example.py:1:14: F601 Dictionary key literal `'a'` repeated
example.py:2:15: W292 [*] No newline at end of file
Found 2 errors.
[*] 1 fixable with the `--fix` option (1 hidden fix can be enabled with the `--unsafe-fixes` option).
```

We could add an indicator for which violations have hidden fixes in the
future.

Check treats unsafe fixes as applicable with opt-in
```
❯ ruff check example.py --no-cache --select F601,W292 --unsafe-fixes
example.py:1:14: F601 [*] Dictionary key literal `'a'` repeated
example.py:2:15: W292 [*] No newline at end of file
Found 2 errors.
[*] 2 fixable with the --fix option.
```

Also can be enabled in the config file

```
❯ cat ruff.toml
unsafe-fixes = true
```

And opted-out per invocation

```
❯ ruff check example.py --no-cache --select F601,W292 --no-unsafe-fixes
example.py:1:14: F601 Dictionary key literal `'a'` repeated
example.py:2:15: W292 [*] No newline at end of file
Found 2 errors.
[*] 1 fixable with the `--fix` option (1 hidden fix can be enabled with the `--unsafe-fixes` option).
```

Diff does not include unsafe fixes
```
❯ ruff check example.py --no-cache --select F601,W292 --diff
--- example.py
+++ example.py
@@ -1,2 +1,2 @@
 x = {'a': 1, 'a': 1}
-print(('foo'))
+print(('foo'))
\ No newline at end of file

Would fix 1 error.
```

Unless there is opt-in
```
❯ ruff check example.py --no-cache --select F601,W292 --diff --unsafe-fixes
--- example.py
+++ example.py
@@ -1,2 +1,2 @@
-x = {'a': 1}
-print(('foo'))
+x = {'a': 1, 'a': 1}
+print(('foo'))
\ No newline at end of file

Would fix 2 errors.
```

https://github.com/astral-sh/ruff/pull/7790 will improve the diff
messages following this pull request

Similarly, `--fix` and `--fix-only` require the `--unsafe-fixes` flag to
apply unsafe fixes.

## Related

Replaces #5119
Closes https://github.com/astral-sh/ruff/issues/4185
Closes https://github.com/astral-sh/ruff/issues/7214
Closes https://github.com/astral-sh/ruff/issues/4845
Closes https://github.com/astral-sh/ruff/issues/3863
Addresses https://github.com/astral-sh/ruff/issues/6835
Addresses https://github.com/astral-sh/ruff/issues/7019
Needs follow-up https://github.com/astral-sh/ruff/issues/6962
Needs follow-up https://github.com/astral-sh/ruff/issues/4845
Needs follow-up https://github.com/astral-sh/ruff/issues/7436
Needs follow-up https://github.com/astral-sh/ruff/issues/7025
Needs follow-up https://github.com/astral-sh/ruff/issues/6434
Follow-up #7790 
Follow-up https://github.com/astral-sh/ruff/pull/7792

---------

Co-authored-by: Evan Rittenhouse <evanrittenhouse@gmail.com>
2023-10-06 03:41:43 +00:00
Zanie Blue b64f403dc2
Rename applicability levels to always, sometimes, and never (#7821)
Following much discussion for #4181 at
https://github.com/astral-sh/ruff/pull/5119,
https://github.com/astral-sh/ruff/discussions/5476, #7769,
https://github.com/astral-sh/ruff/pull/7819, and in
[Discord](https://discord.com/channels/1039017663004942429/1082324250112823306/1159144114231709746),
this pull request changes `Applicability` from using `Automatic`,
`Suggested`, and `Manual` to `Always`, `Sometimes`, and `Never`.

Also removes `Applicability::Unspecified` (replacing #7792).
2023-10-05 13:43:46 -05:00
Charlie Marsh bdf285225d
Enable formatting for Jupyter notebooks (#7749)
## Summary

This PR enables `ruff format` to format Jupyter notebooks.

Most of the work is contained in a new `format_source` method that
formats a generic `SourceKind`, then returns `Some(transformed)` if the
source required formatting, or `None` otherwise.

Closes https://github.com/astral-sh/ruff/issues/7598.

## Test Plan

Ran `cat foo.py | cargo run -p ruff_cli -- format --stdin-filename
Untitled.ipynb`; verified that the console showed a reasonable error:

```console
warning: Failed to read notebook Untitled.ipynb: Expected a Jupyter Notebook, which must be internally stored as JSON, but this file isn't valid JSON: EOF while parsing a value at line 1 column 0
```

Ran `cat Untitled.ipynb | cargo run -p ruff_cli -- format
--stdin-filename Untitled.ipynb`; verified that the JSON output
contained formatted source code.
2023-10-02 14:44:18 +00:00
konsti 0961f008b8
Rename `FixKind` to `FixAvailability` (#7658)
**Summary** `FixKind` feels to generic, i suggest renaming it to
something like `FixAvailibility`.

Commands used:

```bash
rg FixKind --files-with-matches | xargs sed -i 's/FixKind/FixAvailability/g'
rg fix_kind --files-with-matches | xargs sed -i 's/fix_kind/fix_availability/g'
rg FIX_KIND --files-with-matches | xargs sed -i 's/FIX_KIND/FIX_AVAILABILITY/g'
cargo fmt
```

`rg -i "fix.kind"` doesn't show any matches anymore.
2023-10-02 14:38:25 +00:00
Charlie Marsh 1cf3b5676f
Perform insertions before replacements (#7739)
## Summary

If we have, e.g.:

```python
sum((
            factor.dims for factor in bases
        ), [])
```

We generate three edits: two insertions (for the `operator` and
`functools` imports), and then one replacement (for the `sum` call
itself). We need to ensure that the insertions come before the
replacement; otherwise, the edits will appear overlapping and
out-of-order.

Closes https://github.com/astral-sh/ruff/issues/7718.
2023-10-01 14:53:54 +00:00
konsti 1e173f7909
Rename `Autofix` to `Fix` (#7657)
**Summary** Mostly mechanical symbol rename and search-and-replace, with
small changes to the markdown docs to read better
2023-09-28 10:53:05 +00:00
Charlie Marsh afcd00da56
Create `ruff_notebook` crate (#7039)
## Summary

This PR moves `ruff/jupyter` into its own `ruff_notebook` crate. Beyond
the move itself, there were a few challenges:

1. `ruff_notebook` relies on the source map abstraction. I've moved the
source map into `ruff_diagnostics`, since it doesn't have any
dependencies on its own and is used alongside diagnostics.
2. `ruff_notebook` has a couple tests for end-to-end linting and
autofixing. I had to leave these tests in `ruff` itself.
3. We had code in `ruff/jupyter` that relied on Python lexing, in order
to provide a more targeted error message in the event that a user saves
a `.py` file with a `.ipynb` extension. I removed this in order to avoid
a dependency on the parser, it felt like it wasn't worth retaining just
for that dependency.

## Test Plan

`cargo test`
2023-09-01 13:56:44 +00:00
Charlie Marsh 059757a8c8
Implement `Ranged` on more structs (#6921)
Now that it's in `ruff_text_size`, we can use it in a few places that we
couldn't before.
2023-08-27 19:03:08 +00:00
Charlie Marsh 847432cacf
Avoid attempting to fix PT018 in multi-statement lines (#6829)
## Summary

These fixes will _always_ fail, so we should avoid trying to construct
them in the first place.

Closes https://github.com/astral-sh/ruff/issues/6812.
2023-08-23 19:09:34 -04:00
Charlie Marsh 9b6e008cf1
Remove remaining usages of `try_set_fix` (#6828)
There are just a few remaining usages of this deprecated method.
2023-08-23 22:36:09 +00:00
Charlie Marsh 39c6665ff9
Remove remaining usage of `set_fix_from_edit` (#6827)
This method is deprecated; we have one last usage, so removing it.
2023-08-23 18:25:39 -04:00
Charlie Marsh 4231ed2fc3
Skip partial duplicates when applying multi-edit fixes (#6144)
## Summary

Right now, if we have two fixes that have an overlapping edit, but not
an _identical_ set of edits, they'll conflict, causing us to do another
linter traversal. Here, I've enabled the fixer to support partially
overlapping edits, which (as an example) let's us greatly reduce the
number of iterations required in the test suite.

The most common case here is that in which a bunch of edits need to
import some symbol, and then use that symbol, but in different ways. In
that case, all edits will have a common fix (to import the symbol), but
deviate in some way. With this change, we can do all of those edits in
one pass.

Note that the simplest way to enable this was to store sorted edits on
`Fix`. We don't allow modifying the edits on `Fix` once it's
constructed, so this is an easy change, and allows us to avoid a bunch
of clones and traversals later on.

Closes #5800.
2023-07-29 12:11:57 +00:00
Charlie Marsh 4dee49d6fa
Run nightly Clippy over the Ruff repo (#5670)
## Summary

This is the result of running `cargo +nightly clippy --workspace
--all-targets --all-features -- -D warnings` and fixing all violations.
Just wanted to see if there were any interesting new checks on nightly
👀
2023-07-10 23:44:38 -04:00
Charlie Marsh b8f45c93b4
Use a separate fix-isolation group for every parent node (#4774) 2023-06-02 03:07:55 +00:00
Charlie Marsh 621718784a
Replace deletion-tracking with enforced isolation levels (#4766) 2023-06-02 02:45:56 +00:00
Charlie Marsh 19c4b7bee6
Rename ruff_python_semantic's `Context` struct to `SemanticModel` (#4565) 2023-05-22 02:35:03 +00:00
Charlie Marsh 6b1062ccc3
Enable `pycodestyle` rules under new "nursery" category (#4407) 2023-05-16 21:21:58 +00:00
Jonathan Plasse c10a4535b9
Disallow `unreachable_pub` (#4314) 2023-05-11 18:00:00 -04:00
Micha Reiser a2b8487ae3
Remove functor from autofix title (#4245) 2023-05-10 07:21:15 +00:00
Micha Reiser 8969ad5879
Always generate fixes (#4239) 2023-05-10 07:06:14 +00:00
Zanie Adkins cf7aa26aa4
Add `Applicability` to `Fix` (#4303)
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-05-10 08:42:46 +02:00
konstin 318653c427
Write diagnostic name when failing to create fix (#4309) 2023-05-09 17:46:40 +02:00
Micha Reiser 4d5a339d9e
Remove `Fix::from(Edit)` and add deprecated replacement methods to `Diagnostic`s (#4275) 2023-05-08 10:25:50 +00:00
Zanie Adkins 0801f14046
Refactor `Fix` and `Edit` API (#4198) 2023-05-08 11:57:03 +02:00
Micha Reiser f3e6ddda62
perf(logical-lines): Various small perf improvements (#4022) 2023-04-26 20:10:35 +01:00
Micha Reiser cab65b25da
Replace row/column based `Location` with byte-offsets. (#3931) 2023-04-26 18:11:02 +00:00
Micha Reiser e8aebee3f6
Pretty print `Diagnostic`s in snapshot tests (#3906) 2023-04-11 09:03:00 +00:00
Micha Reiser 210083bdd8
Order `Edit`s by `Location`s (#3905) 2023-04-11 08:56:41 +00:00
Micha Reiser 76c47a9a43
Cheap cloneable LineIndex (#3896) 2023-04-11 07:33:40 +00:00
Micha Reiser 9209e57c5a
Extract message emitters from Printer (#3895) 2023-04-11 07:24:25 +00:00
Micha Reiser 595cd065f3
Reduce explcit clones (#3793) 2023-03-29 15:15:14 +02:00
Charlie Marsh e603382cf0
Allow diagnostics to generate multi-edit fixes (#3709) 2023-03-26 16:45:19 -04:00
Charlie Marsh a66481ed28
Rename setter methods on `Diagnostic` (#3738) 2023-03-26 10:28:30 -04:00