Commit graph

3841 commits

Author SHA1 Message Date
Charlie Marsh
c5adbf17da
Ignore non-abstract class attributes when enforcing B024 (#11210)
## Summary

I think the check included here does make sense, but I don't see why we
would allow it if a value is provided for the attribute -- since, in
that case, isn't it _not_ abstract?

Closes: https://github.com/astral-sh/ruff/issues/11208.
2024-04-30 09:01:08 -07:00
Micha Reiser
c6dcf3502b
[red-knot] Use FileId in module resolver to map from file to module (#11212) 2024-04-30 14:09:47 +00:00
Micha Reiser
1e585b8667
[red knot] Introduce LintDb (#11204) 2024-04-30 16:01:46 +02:00
Alex Waygood
21d824abfd
[pylint] Also emit PLR0206 for properties with variadic parameters (#11200) 2024-04-30 11:59:37 +01:00
Micha Reiser
7e28c80354
[red-knot] Refactor program.check scheduling (#11202) 2024-04-30 07:23:41 +00:00
Micha Reiser
bc03d376e8
[red-knot] Add "cheap" program.snapshot (#11172) 2024-04-30 07:13:26 +00:00
Alex Waygood
eb6f562419
red-knot: introduce a StatisticsRecorder trait for the KeyValueCache (#11179)
## Summary

This PR changes the `DebugStatistics` and `ReleaseStatistics` structs so
that they implement a common `StatisticsRecorder` trait, and makes the
`KeyValueCache` struct generic over a type parameter bound to that
trait. The advantage of this approach is that it's much harder for the
`DebugStatistics` and `ReleaseStatistics` structs to accidentally grow
out of sync in the methods that they implement, which was the cause of
the release-build failure recently fixed in #11177.

## Test Plan

`cargo test -p red_knot` and `cargo build --release` both continue to
pass for me locally
2024-04-30 07:14:06 +01:00
Micha Reiser
5561d445d7
linter: Enable test-rules for test build (#11201) 2024-04-30 08:06:47 +02:00
plredmond
c391c8b6cb
Red Knot - Add symbol flags (#11134)
* Adds `Symbol.flag` bitfield. Populates it from (the three renamed)
`add_or_update_symbol*` methods.
* Currently there are these flags supported:
  * `IS_DEFINED` is set in a scope where a variable is defined.
* `IS_USED` is set in a scope where a variable is referenced. (To have
both this and `IS_DEFINED` would require two separate appearances of a
variable in the same scope-- one def and one use.)
* `MARKED_GLOBAL` and `MARKED_NONLOCAL` are **not yet implemented**.
(*TODO: While traversing, if you find these declarations, add these
flags to the variable.*)
* Adds `Symbol.kind` field (commented) and the data structure which will
populate it: `Kind` which is an enum of freevar, cellvar,
implicit_global, and implicit_local. **Not yet populated**. (*TODO: a
second pass over the scope (or the ast?) will observe the
`MARKED_GLOBAL` and `MARKED_NONLOCAL` flags to populate this field. When
that's added, we'll uncomment the field.*)
* Adds a few tests that the `IS_DEFINED` and `IS_USED` fields are
correctly set and/or merged:
* Unit test that subsequent calls to `add_or_update_symbol` will merge
the flag arguments.
* Unit test that in the statement `x = foo`, the variable `foo` is
considered used but not defined.
* Unit test that in the statement `from bar import foo`, the variable
`foo` is considered defined but not used.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2024-04-29 17:07:23 -07:00
Carl Meyer
ce030a467f
[red-knot] resolve base class types (#11178)
## Summary

Resolve base class types, as long as they are simple names.

## Test Plan

cargo test
2024-04-29 16:22:30 -06:00
Dhruv Manilawala
04a922866a
Add basic docs for the parser crate (#11199)
## Summary

This PR adds a basic README for the `ruff_python_parser` crate and
updates the CONTRIBUTING docs with the fuzzer and benchmark section.

Additionally, it also updates some inline documentation within the
parser crate and splits the `parse_program` function into
`parse_single_expression` and `parse_module` which will be called by
matching against the `Mode`.

This PR doesn't go into too much internal detail around the parser logic
due to the following reasons:
1. Where should the docs go? Should it be as a module docs in `lib.rs`
or in README?
2. The parser is still evolving and could include a lot of refactors
with the future work (feedback loop and improved error recovery and
resilience)

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2024-04-29 17:08:07 +00:00
Alex Waygood
87929ad5f1
Add convenience methods for iterating over all parameter nodes in a function (#11174) 2024-04-29 10:36:15 +00:00
Micha Reiser
3474e37836
[red-knot] Unresolved imports lint rule (#11164) 2024-04-28 12:12:49 +02:00
Micha Reiser
00d7c01cfc
[red-knot] Fix absolute imports in module.resolve_name (#11180) 2024-04-27 20:07:07 +02:00
Micha Reiser
983a06cec3
[red-knot] Resolve and check dependencies (#11161) 2024-04-27 15:49:03 +00:00
Alex Waygood
47692027bf
Fix cargo build --release (#11177)
## Summary

`cargo build --release` currently fails to compile on `main`:

<details>

```
error[E0599]: no method named `hit` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:22:29
    |
22  |             self.statistics.hit();
    |                             ^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `hit` not found for this struct

error[E0599]: no method named `miss` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:25:29
    |
25  |             self.statistics.miss();
    |                             ^^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `miss` not found for this struct

error[E0599]: no method named `hit` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:36:33
    |
36  |                 self.statistics.hit();
    |                                 ^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `hit` not found for this struct

error[E0599]: no method named `miss` found for struct `ReleaseStatistics` in the current scope
   --> crates/red_knot/src/cache.rs:41:33
    |
41  |                 self.statistics.miss();
    |                                 ^^^^ method not found in `ReleaseStatistics`
...
145 | pub struct ReleaseStatistics;
    | ---------------------------- method `miss` not found for this struct
```

</details>

This is because in a release build, `CacheStatistics` is a type alias
for `ReleaseStatistics`, and `ReleaseStatistics` doesn't have `hit()` or
`miss()` methods. (In a debug build, `CacheStatistics` is a type alias
for `DebugStatistics`, which _does_ have those methods.)

Possibly we could make this less likely to happen in the future by
making both structs implement a common trait instead of using type
aliases that vary depending on whether it's a debug build or not? For
now, though, this PR just brings the two structs in sync w.r.t. the
methods they expose.

## Test Plan

`cargo build --release` now once again compiles for me locally
2024-04-27 11:45:32 -04:00
Charlie Marsh
ec3243a6e5
Prioritize redefined-while-unused over unused-import (#11173)
## Summary

This PR adds an override to the fixer to ensure that we apply any
`redefined-while-unused` fixes prior to `unused-import`.

Closes https://github.com/astral-sh/ruff/issues/10905.
2024-04-27 11:44:53 -04:00
Carl Meyer
2d6978f236
[red-knot] fix class vs instance (#11175)
## Summary

Clarify the type of an exact class object vs the type of instances of
that class.

## Test Plan

cargo test
2024-04-27 09:09:02 -06:00
Auguste Lalande
2490d2d4af
[ruff] Detect duplicate codes as part of unused-noqa (RUF100) (#10850)
## Summary

Implement duplicate code detection as part of `RUF100`, mirroring the
behavior of `flake8-noqa` (`NQA005`) mentioned in #850. The idea to
merge the rule into `RUF100` was suggested by @MichaReiser
https://github.com/astral-sh/ruff/pull/10325#issuecomment-2025535444.

## Test Plan

Test cases were added to the fixture.
2024-04-27 12:33:44 +00:00
Jelle Zijlstra
59b73fabc1
[pyflakes] Improve invalid-print-syntax documentation (#11171)
This syntax wasn't "deprecated" in Python 3; it was removed.

I started looking at this rule because I was curious how Ruff could even
detect this without a Python 2 parser. Then I realized that
"print >> f, x" is actually valid Python 3 syntax: it creates a tuple
containing a right-shifted version of the print function.
2024-04-27 07:54:04 -04:00
Micha Reiser
61c97a037c
red-knot: Introduce program.check (#11148) 2024-04-27 09:01:20 +00:00
Micha Reiser
7cd065e4a2
Kick off Red-knot (#10849)
Co-authored-by: Carl Meyer <carl@oddbird.net>
Co-authored-by: Carl Meyer <carl@astral.sh>
2024-04-27 08:34:00 +00:00
Carl Meyer
845ba7cf5f
Make ImportFrom level just a u32 (#11170) 2024-04-26 20:38:35 -06:00
Auguste Lalande
5994414739
[ruff] Implement redirected-noqa (RUF101) (#11052)
## Summary

Based on discussion in #10850.

As it stands today `RUF100` will attempt to replace code redirects with
their target codes even though this is not the "goal" of `RUF100`. This
behavior is confusing and inconsistent, since code redirects which don't
otherwise violate `RUF100` will not be updated. The behavior is also
undocumented. Additionally, users who want to use `RUF100` but do not
want to update redirects have no way to opt out.

This PR explicitly detects redirects with a new rule `RUF101` and
patches `RUF100` to keep original codes in fixes and reporting.

## Test Plan

Added fixture.
2024-04-27 02:08:11 +00:00
Jane Lewis
632965d0fa
ruff server: Support a custom TOML configuration file (#11140)
## Summary

Closes #10985.

The server now supports a custom TOML configuration file as a client
setting. The setting must be an absolute path to a file. If the file is
called `pyproject.toml`, the server will attempt to parse it as a
pyproject file - otherwise, it will attempt to parse it as a `ruff.toml`
file, even if the file has a name besides `ruff.toml`.

If an option is set in both the custom TOML configuration file and in
the client settings directly, the latter will be used.

## Test Plan

1. Create a `ruff.toml` file outside of the workspace you are testing.
Set an option that is different from the one in the configuration for
your test workspace.
2. Set the path to the configuration in NeoVim:
```lua
require('lspconfig').ruff.setup {
    init_options = {
      settings = {
        configuration = "absolute/path/to/your/configuration"
      }
    }
}
```
3. Confirm that the option in the configuration file is used, regardless
of what the option is set to in the workspace configuration.
4. Add the same option, with a different value, to the NeoVim
configuration directly. For example:
```lua
require('lspconfig').ruff.setup {
    init_options = {
      settings = {
        configuration = "absolute/path/to/your/configuration",
        lint = {
          select = []
        }
      }
    }
}
```
5. Confirm that the option set in client settings is used, regardless of
the value in either the custom configuration file or in the workspace
configuration.
2024-04-26 23:46:07 +00:00
Dhruv Manilawala
77a72ecd38
Avoid multiline expression if format specifier is present (#11123)
## Summary

This PR fixes the bug where the formatter would format an f-string and
could potentially change the AST.

For a triple-quoted f-string, the element can't be formatted into
multiline if it has a format specifier because otherwise the newline
would be treated as part of the format specifier.

Given the following f-string:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f} ddddddddddddddd eeeeeeee"""
```

The formatter sees that the f-string is already multiline so it assumes
that it can contain line breaks i.e., broken into multiple lines. But,
in this specific case we can't format it as:

```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f
} ddddddddddddddd eeeeeeee"""
```
                     
Because the format specifier string would become ".3f\n", which is not
the original string (`.3f`).

If the original source code already contained a newline, they'll be
preserved. For example:
```python
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {
    variable:.3f
} ddddddddddddddd eeeeeeee"""
```

The above will be formatted as:
```py
f"""aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbb ccccccccccc {variable:.3f
} ddddddddddddddd eeeeeeee"""
```

Note that the newline after `.3f` is part of the format specifier which
needs to be preserved.
The Python version is irrelevant in this case.

fixes: #10040 

## Test Plan

Add some test cases to verify this behavior.
2024-04-26 13:34:38 +00:00
Jane Lewis
16a1f3cbcc
ruff server: Support setting to prioritize project configuration over editor configuration (#11086)
## Summary

This is intended to address
https://github.com/astral-sh/ruff-vscode/issues/425, and is a follow-up
to https://github.com/astral-sh/ruff/pull/11062.

A new client setting is now supported by the server,
`prioritizeFileConfiguration`. This is a boolean setting (default:
`false`) that, if set to `true`, will instruct the configuration
resolver to prioritize file configuration (aka discovered TOML files)
over configuration passed in by the editor.

A corresponding extension PR has been opened, which makes this setting
available for VS Code:
https://github.com/astral-sh/ruff-vscode/pull/457.

## Test Plan

To test this with VS Code, you'll need to check out [the VS Code
PR](https://github.com/astral-sh/ruff-vscode/pull/457) that adds this
setting.

The test process is similar to
https://github.com/astral-sh/ruff/pull/11062, but in scenarios where the
editor configuration would take priority over file configuration, file
configuration should take priority.
2024-04-26 08:17:28 +00:00
Jelle Zijlstra
cd3e319538
Add support for PEP 696 syntax (#11120) 2024-04-26 09:47:29 +02:00
Steve C
c8c227dd5d
[refurb] Implement fstring-number-format (FURB116) (#10921)
## Summary

Adds `FURB116`

See #1348 

## Test Plan

`cargo test`
2024-04-26 01:15:33 +00:00
Charlie Marsh
b15e9e6e05
Include inline instantiations when detecting loggers (#11154)
## Summary

Closes https://github.com/astral-sh/ruff/issues/11031.
2024-04-25 21:00:12 -04:00
Alex Waygood
269014a539
Delete unused methods from Parameters (#11150) 2024-04-25 22:11:24 +01:00
Auguste Lalande
3364ef957d
[pygrep_hooks] Fix blanket-noqa panic when last line has noqa with no newline (PGH004) (#11108)
## Summary

Resolves #11102

The error stems from these lines

f5c7a62aa6/crates/ruff_linter/src/noqa.rs (L697-L702)
I don't really understand the purpose of incrementing the last index,
but it makes the resulting range invalid for indexing into `contents`.

For now I just detect if the index is too high in `blanket_noqa` and
adjust it if necessary.

## Test Plan

Created fixture from issue example.
2024-04-25 14:39:38 -04:00
Jane Lewis
77c93fd63c
Bump version to 0.4.2 (#11151) 2024-04-25 17:31:38 +00:00
Dhruv Manilawala
1c9f5e3001
Display the AST even with syntax errors (#11147)
## Summary

This PR updates the playground to display the AST even if it contains a
syntax error. This could be useful for development and also to give a
quick preview of what error recovery looks like.

Note that not all recovery is correct but this allows us to iterate
quickly on what can be improved.

## Test Plan

Build the playground locally and test it.

<img width="1688" alt="Screenshot 2024-04-25 at 21 02 22"
src="2b94934c-4f2c-4a9a-9693-3d8460ed9d0b">
2024-04-25 21:55:23 +05:30
Dhruv Manilawala
4738e19974
Remove unused lexical error types (#11145) 2024-04-25 15:24:16 +00:00
bersbersbers
f428bd5052
Docs: mention lint.typing-modules in TCH001, TCH002, TCH003 (#11144)
## Summary

Mention `lint.typing-modules` in `TCH001`, `TCH002`, `TCH003`; close
#11142.
2024-04-25 11:23:03 -04:00
Jane Lewis
4690890e9f
ruff server: In 'publish diagnostics' mode, document diagnostics are cleared properly when a file is closed (#11137)
## Summary

Fixes #11114. 

As part of the `onClose` handler, we publish an empty array of
diagnostics for the document being closed, similar to
[`ruff-lsp`](187d7790be/ruff_lsp/server.py (L459-L464)).
This prevent phantom diagnostics from lingering after a document is
closed. We'll only do this if the client doesn't support pull
diagnostics, because otherwise clearing diagnostics is their
responsibility.

## Test Plan

Diagnostics should no longer appear for a document in the Problems tab
after the document is closed.
2024-04-24 19:38:54 -07:00
Sid
cee38f39df
[flake8-blind-expect] Allow raise from in BLE001 (#11131)
## Summary

This allows `raise from` in BLE001.

```python
try:
    ...
except Exception as e:
    raise ValueError from e
```

Fixes #10806

## Test Plan

Test case added.
2024-04-24 11:56:11 -04:00
Alex Waygood
e3fde28146
[flake8-pyi] Allow overloaded __exit__ and __aexit__ definitions (PYI036) (#11057) 2024-04-24 15:48:52 +00:00
Ibraheem Ahmed
1c8849f9a8
Use Matchit to Resolve Per-File Settings (#11111)
## Summary

Continuation of https://github.com/astral-sh/ruff/pull/9444.

> When the formatter is fully cached, it turns out we actually spend
meaningful time mapping from file to `Settings` (since we use a
hierarchical approach to settings). Using `matchit` rather than
`BTreeMap` improves fully-cached performance by anywhere from 2-5%
depending on the project, and since these are all implementation details
of `Resolver`, it's minimally invasive.

`matchit` supports escaping routing characters so this change should now
be fully compatible.

## Test Plan

On my machine I'm seeing a ~3% improvement with this change.

```
hyperfine --warmup 20 -i "./target/release/main format ../airflow" "./target/release/ruff format ../airflow"
Benchmark 1: ./target/release/main format ../airflow
  Time (mean ± σ):      58.1 ms ±   1.4 ms    [User: 63.1 ms, System: 66.5 ms]
  Range (min … max):    56.1 ms …  62.9 ms    49 runs
 
Benchmark 2: ./target/release/ruff format ../airflow
  Time (mean ± σ):      56.6 ms ±   1.5 ms    [User: 57.8 ms, System: 67.7 ms]
  Range (min … max):    54.1 ms …  63.0 ms    51 runs
 
Summary
  ./target/release/ruff format ../airflow ran
    1.03 ± 0.04 times faster than ./target/release/main format ../airflow
```
2024-04-24 10:25:46 -04:00
Alex Waygood
37af6e6147
[flake8-pyi] Allow simple assignments to None in enum class scopes (PYI026) (#11128) 2024-04-24 15:13:55 +01:00
Micha Reiser
92814fd99b
Use crossbeam-channel instead of crossbeam (#11129) 2024-04-24 13:56:55 +00:00
Charlie Marsh
51dec8d95b
[flake8-simplify] Avoid raising SIM911 for non-zip attribute calls (#11126)
## Summary

The `matches!` macro here is slightly off and allows _all_ attribute
calls through.

Closes https://github.com/astral-sh/ruff/issues/11125.
2024-04-24 13:05:17 +00:00
Nolan
7c8c1c71a3
Implement hover menu support for ruff-server; Issue #10595 (#11096)
<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Add support for hover menu to ruff_server, as requested in
[10595](https://github.com/astral-sh/ruff/issues/10595).
Majority of new code is in hover.rs.
I reused the regex from ruff-lsp's implementation. Also reused the
format_rule_text function from ruff/src/commands/rule.rs
Added capability registration in server.rs, and added the handler to
api.rs.

## Test Plan

Tested in NVIM v0.10.0-dev-2582+g2a8cef6bd, configured with lspconfig
using the default options (other than cmd pointing to my test build,
with options "server" and "--preview"). OS: Ubuntu 24.04, kernel
6.8.0-22.

---------

Co-authored-by: Jane Lewis <me@jane.engineering>
2024-04-23 20:16:02 +00:00
Jane Lewis
35ca887e02
ruff server: Ruff configuration from client settings overrides project configuration (#11062)
## Summary

This is a follow-up to https://github.com/astral-sh/ruff/pull/10984 that
implements configuration resolution for editor configuration. By 'editor
configuration', I'm referring to the client settings that correspond to
Ruff configuration/options, like `preview`, `select`, and so on. These
will be combined with 'project configuration' (configuration taken from
project files such as `pyproject.toml`) to generate the final linter and
formatter settings used by `RuffSettings`. Editor configuration takes
priority over project configuration.

In a follow-up pull request, I'll implement a new client setting that
allows project configuration to override editor configuration, as per
[this issue](https://github.com/astral-sh/ruff-vscode/issues/425).

## Review guide

The first commit, e38966d8843becc7234fa7d46009c16af4ba41e9, is just
doing re-arrangement so that we can pass the right things to
`RuffSettings::resolve`. The actual resolution logic is in the second
commit, 0eec9ee75c10e5ec423bd9f5ce1764f4d7a5ad86. It might help to look
at these comments individually since the diff is rather messy.

## Test Plan

For the settings to show up in VS Code, you'll need to checkout this
branch: https://github.com/astral-sh/ruff-vscode/pull/456.

To test that the resolution for a specific setting works as expected,
run through the following scenarios, setting it in project and editor
configuration as needed:

| Set in project configuration? | Set in editor configuration? |
Expected Outcome |

|-------------------------------|--------------------------------------------------|------------------------------------------------------------------------------------------|
| No | No | The editor should behave as if the setting was set to its
default value. |
| Yes | No | The editor should behave as if the setting was set to the
value in project configuration. |
| No | Yes | The editor should behave as if the setting was set to the
value in editor configuration. |
| Yes | Yes (but distinctive from project configuration) | The editor
should behave as if the setting was set to the value in editor
configuration. |

An exception to this is `extendSelect`, which does not have an analog in
TOML configuration. Instead, you should verify that `extendSelect`
amends the `select` setting. If `select` is set in both editor and
project configuration, `extendSelect` will only append to the `select`
value in editor configuration, so make sure to un-set it there if you're
testing `extendSelect` with `select` in project configuration.
2024-04-23 11:19:17 -07:00
Dhruv Manilawala
38d2562f41
Refactor unary expression parsing (#11088)
## Summary

This PR refactors unary expression parsing with the following changes:
* Ability to get `OperatorPrecedence` from a unary operator (`UnaryOp`)
* Implement methods on `TokenKind`
	* Add `as_unary_operator` which returns an `Option<UnaryOp>`
* Add `as_unary_arithmetic_operator` which returns an `Option<UnaryOp>`
(used for pattern parsing)
* Rename `is_unary` to `is_unary_arithmetic_operator` (used in the
linter)

resolves: #10752 

## Test Plan

Verify that the existing test cases pass, no ecosystem changes, run the
Python based fuzzer on 3000 random inputs and run it on dozens of
open-source repositories.
2024-04-23 04:55:02 +00:00
Dhruv Manilawala
7eba967e16
Refactor binary expression parsing (#11073)
## Summary

This PR refactors the binary expression parsing in a way to make it
readable and easy to understand. It draws inspiration from the suggested
edits in the linked messages in #10752.

### Changes

* Ability to get the precedence of an operator
	* From a boolean operator (`BinOp`) to `OperatorPrecedence`
	* From a binary operator (`Operator`) to `OperatorPrecedence`
	* No comparison operator because all of them have the same precedence
* Implement methods on `TokenKind` to convert it to an appropriate
operator enum
	* Add `as_boolean_operator` which returns an `Option<BoolOp>`
	* Add `as_binary_operator` which returns an `Option<Operator>`
* No `as_comparison_operator` because it requires lookahead and I'm not
sure if `token.as_comparison_operator(peek)` is a good way to implement
it
* Introduce `BinaryLikeOperator`
	* Constructed from two tokens using the methods from the second point
* Add `precedence` method using the conversion methods mentioned in the
first point
* Make most of the functions in `TokenKind` private to the module
* Use `self` instead of `&self` for `TokenKind` 

fixes: #11072

## Test Plan

Refer #11088
2024-04-23 04:42:40 +00:00
Dhruv Manilawala
5b81b8368d
Make associativity a property of operator precedence (#11065)
## Summary

This PR does a few things but the main change is that is makes
associativity a property of operator precedence.

1. Rename `Precedence` -> `OperatorPrecedence`
2. Rename `parse_expression_with_precedence` ->
`parse_binary_expression_or_higher`
3. Move `current_binding_power` to `OperatorPrecedence::try_from_tokens`
[^1]
4. Add a `OperatorPrecedence::is_right_associative` method
5. Move from `increment_precedence` to using `<=` / `<` to check if the
parsing loop needs to stop [^2]

[^1]: Another alternative would be to have two separate methods to avoid
lookahead as it's required only for once case (`not in`). So,
`try_from_current_token(current).or_else(|| try_from_next_token(current,
peek))`
[^2]: This will allow us to easily make the refactors mentioned in
#10752

## Test Plan

Make sure the precedence parsing algorithm is still correct by running
the test suite, fuzz testing it and running it against a dozen or so
open-source repositories.
2024-04-23 04:28:46 +00:00
Dhruv Manilawala
c30735d4a7
Add ExpressionContext for expression parsing (#11055)
## Summary

This PR adds a new `ExpressionContext` struct which is used in
expression parsing.

This solves the following problem:
1. Allowing starred expression with different precedence
2. Allowing yield expression in certain context
3. Remove ambiguity with `in` keyword when parsing a `for ... in`
statement

For context, (1) was solved by adding `parse_star_expression_list` and
`parse_star_expression_or_higher` in #10623, (2) was solved by by adding
`parse_yield_expression_or_else` in #10809, and (3) was fixed in #11009.
All of the mentioned functions have been removed in favor of the context
flags.

As mentioned in #11009, an ideal solution would be to implement an
expression context which is what this PR implements. This is passed
around as function parameter and the call stack is used to automatically
reset the context.

### Recovery

How should the parser recover if the target expression is invalid when
an expression can consume the `in` keyword?

1. Should the `in` keyword be part of the target expression?
2. Or, should the expression parsing stop as soon as `in` keyword is
encountered, no matter the expression?

For example:
```python
for yield x in y: ...

# Here, should this be parsed as
for (yield x) in (y): ...
# Or
for (yield x in y): ...
# where the `in iter` part is missing
```

Or, for binary expression parsing:
```python
for x or y in z: ...

# Should this be parsed as
for (x or y) in z: ...
# Or
for (x or y in z): ...
# where the `in iter` part is missing
```

This need not be solved now, but is very easy to change. For context
this PR does the following:
* For binary, comparison, and unary expressions, stop at `in`
* For lambda, yield expressions, consume the `in`

## Test Plan

1. Add test cases for the `for ... in` statement and verify the
snapshots
2. Make sure the existing test suite pass
3. Run the fuzzer for around 3000 generated source code
4. Run the updated logic on a dozen or so open source repositories
(codename "parser-checkouts")
2024-04-23 04:19:05 +00:00
Jane Lewis
62478c3070
ruff server: Support publish diagnostics as a fallback when pull diagnostics aren't supported (#11092)
## Summary

Fixes #11059 

Several major editors don't support [pull
diagnostics](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_pullDiagnostics),
a method of sending diagnostics to the client that was introduced in
version `0.3.17` of the specification. Until now, `ruff server` has only
used pull diagnostics, which resulted in diagnostics not being available
on Neovim and Helix, which don't support pull diagnostics yet (though
Neovim `10.0` will have support for this).

`ruff server` will now utilize the older method of sending diagnostics,
known as 'publish diagnostics', when pull diagnostics aren't supported
by the client. This involves re-linting a document every time it is
opened or modified, and then sending the diagnostics generated from that
lint to the client via the `textDocument/publishDiagnostics`
notification.

## Test Plan

The easiest way to test that this PR works is to check if diagnostics
show up on Neovim `<=0.9`.
2024-04-22 21:06:35 -07:00