From d61d75d4fa09e05438bd53baaefe9cd5661816b4 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 16 Aug 2024 20:16:57 +0200 Subject: [PATCH] Select stable import name when multiple possible bindings are in scope (#12888) --- ...es__refurb__tests__FURB177_FURB177.py.snap | 20 +++++++++---------- crates/ruff_python_semantic/src/model.rs | 19 ++++++++++++++++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB177_FURB177.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB177_FURB177.py.snap index d7b25377f5f10..a7034cc35a81e 100644 --- a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB177_FURB177.py.snap +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB177_FURB177.py.snap @@ -15,7 +15,7 @@ FURB177.py:5:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for curr 3 3 | 4 4 | # Errors 5 |-_ = Path().resolve() - 5 |+_ = pathlib.Path.cwd() + 5 |+_ = Path.cwd() 6 6 | _ = pathlib.Path().resolve() 7 7 | 8 8 | _ = Path("").resolve() @@ -36,7 +36,7 @@ FURB177.py:6:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for curr 4 4 | # Errors 5 5 | _ = Path().resolve() 6 |-_ = pathlib.Path().resolve() - 6 |+_ = pathlib.Path.cwd() + 6 |+_ = Path.cwd() 7 7 | 8 8 | _ = Path("").resolve() 9 9 | _ = pathlib.Path("").resolve() @@ -56,7 +56,7 @@ FURB177.py:8:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for curr 6 6 | _ = pathlib.Path().resolve() 7 7 | 8 |-_ = Path("").resolve() - 8 |+_ = pathlib.Path.cwd() + 8 |+_ = Path.cwd() 9 9 | _ = pathlib.Path("").resolve() 10 10 | 11 11 | _ = Path(".").resolve() @@ -76,7 +76,7 @@ FURB177.py:9:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for curr 7 7 | 8 8 | _ = Path("").resolve() 9 |-_ = pathlib.Path("").resolve() - 9 |+_ = pathlib.Path.cwd() + 9 |+_ = Path.cwd() 10 10 | 11 11 | _ = Path(".").resolve() 12 12 | _ = pathlib.Path(".").resolve() @@ -96,7 +96,7 @@ FURB177.py:11:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for cur 9 9 | _ = pathlib.Path("").resolve() 10 10 | 11 |-_ = Path(".").resolve() - 11 |+_ = pathlib.Path.cwd() + 11 |+_ = Path.cwd() 12 12 | _ = pathlib.Path(".").resolve() 13 13 | 14 14 | _ = Path("", **kwargs).resolve() @@ -116,7 +116,7 @@ FURB177.py:12:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for cur 10 10 | 11 11 | _ = Path(".").resolve() 12 |-_ = pathlib.Path(".").resolve() - 12 |+_ = pathlib.Path.cwd() + 12 |+_ = Path.cwd() 13 13 | 14 14 | _ = Path("", **kwargs).resolve() 15 15 | _ = pathlib.Path("", **kwargs).resolve() @@ -136,7 +136,7 @@ FURB177.py:14:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for cur 12 12 | _ = pathlib.Path(".").resolve() 13 13 | 14 |-_ = Path("", **kwargs).resolve() - 14 |+_ = pathlib.Path.cwd() + 14 |+_ = Path.cwd() 15 15 | _ = pathlib.Path("", **kwargs).resolve() 16 16 | 17 17 | _ = Path(".", **kwargs).resolve() @@ -156,7 +156,7 @@ FURB177.py:15:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for cur 13 13 | 14 14 | _ = Path("", **kwargs).resolve() 15 |-_ = pathlib.Path("", **kwargs).resolve() - 15 |+_ = pathlib.Path.cwd() + 15 |+_ = Path.cwd() 16 16 | 17 17 | _ = Path(".", **kwargs).resolve() 18 18 | _ = pathlib.Path(".", **kwargs).resolve() @@ -176,7 +176,7 @@ FURB177.py:17:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for cur 15 15 | _ = pathlib.Path("", **kwargs).resolve() 16 16 | 17 |-_ = Path(".", **kwargs).resolve() - 17 |+_ = pathlib.Path.cwd() + 17 |+_ = Path.cwd() 18 18 | _ = pathlib.Path(".", **kwargs).resolve() 19 19 | 20 20 | # OK @@ -196,7 +196,7 @@ FURB177.py:18:5: FURB177 [*] Prefer `Path.cwd()` over `Path().resolve()` for cur 16 16 | 17 17 | _ = Path(".", **kwargs).resolve() 18 |-_ = pathlib.Path(".", **kwargs).resolve() - 18 |+_ = pathlib.Path.cwd() + 18 |+_ = Path.cwd() 19 19 | 20 20 | # OK 21 21 | _ = Path.cwd() diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 7ef179b51a9d9..b7377e83f4629 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -907,7 +907,7 @@ impl<'a> SemanticModel<'a> { self.current_scopes() .enumerate() .find_map(|(scope_index, scope)| { - scope.bindings().find_map(|(name, binding_id)| { + let mut imported_names = scope.bindings().filter_map(|(name, binding_id)| { let binding = &self.bindings[binding_id]; match &binding.kind { // Ex) Given `module="sys"` and `object="exit"`: @@ -987,7 +987,22 @@ impl<'a> SemanticModel<'a> { _ => {} } None - }) + }); + + let first = imported_names.next()?; + if let Some(second) = imported_names.next() { + // Multiple candidates. We need to sort them because `scope.bindings()` is a HashMap + // which doesn't have a stable iteration order. + + let mut imports: Vec<_> = + [first, second].into_iter().chain(imported_names).collect(); + imports.sort_unstable_by_key(|import| import.range.start()); + + // Return the binding that was imported last. + imports.pop() + } else { + Some(first) + } }) }