mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-17 17:10:34 +00:00
Track unresolved references in the semantic model (#5902)
## Summary As part of my continued quest to separate semantic model-building from diagnostic emission, this PR moves our unresolved-reference rules to a deferred pass. So, rather than emitting diagnostics as we encounter unresolved references, we now track those unresolved references on the semantic model (just like resolved references), and after traversal, emit the relevant rules for any unresolved references.
This commit is contained in:
parent
23cde4d1f5
commit
963f240e46
11 changed files with 261 additions and 202 deletions
|
@ -1,13 +1,17 @@
|
|||
use bitflags::bitflags;
|
||||
use ruff_text_size::TextRange;
|
||||
use std::ops::Deref;
|
||||
|
||||
use ruff_index::{newtype_index, IndexSlice, IndexVec};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::context::ExecutionContext;
|
||||
use crate::scope::ScopeId;
|
||||
use crate::Exceptions;
|
||||
|
||||
/// A resolved read reference to a name in a program.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Reference {
|
||||
pub struct ResolvedReference {
|
||||
/// The scope in which the reference is defined.
|
||||
scope_id: ScopeId,
|
||||
/// The range of the reference in the source code.
|
||||
|
@ -16,7 +20,7 @@ pub struct Reference {
|
|||
context: ExecutionContext,
|
||||
}
|
||||
|
||||
impl Reference {
|
||||
impl ResolvedReference {
|
||||
pub const fn scope_id(&self) -> ScopeId {
|
||||
self.scope_id
|
||||
}
|
||||
|
@ -32,21 +36,21 @@ impl Reference {
|
|||
|
||||
/// Id uniquely identifying a read reference in a program.
|
||||
#[newtype_index]
|
||||
pub struct ReferenceId;
|
||||
pub struct ResolvedReferenceId;
|
||||
|
||||
/// The references of a program indexed by [`ReferenceId`].
|
||||
/// The references of a program indexed by [`ResolvedReferenceId`].
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct References(IndexVec<ReferenceId, Reference>);
|
||||
pub(crate) struct ResolvedReferences(IndexVec<ResolvedReferenceId, ResolvedReference>);
|
||||
|
||||
impl References {
|
||||
/// Pushes a new [`Reference`] and returns its [`ReferenceId`].
|
||||
impl ResolvedReferences {
|
||||
/// Pushes a new [`ResolvedReference`] and returns its [`ResolvedReferenceId`].
|
||||
pub(crate) fn push(
|
||||
&mut self,
|
||||
scope_id: ScopeId,
|
||||
range: TextRange,
|
||||
context: ExecutionContext,
|
||||
) -> ReferenceId {
|
||||
self.0.push(Reference {
|
||||
) -> ResolvedReferenceId {
|
||||
self.0.push(ResolvedReference {
|
||||
scope_id,
|
||||
range,
|
||||
context,
|
||||
|
@ -54,8 +58,73 @@ impl References {
|
|||
}
|
||||
}
|
||||
|
||||
impl Deref for References {
|
||||
type Target = IndexSlice<ReferenceId, Reference>;
|
||||
impl Deref for ResolvedReferences {
|
||||
type Target = IndexSlice<ResolvedReferenceId, ResolvedReference>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// An unresolved read reference to a name in a program.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnresolvedReference {
|
||||
/// The range of the reference in the source code.
|
||||
range: TextRange,
|
||||
/// The set of exceptions that were handled when resolution was attempted.
|
||||
exceptions: Exceptions,
|
||||
/// Flags indicating the context in which the reference occurs.
|
||||
flags: UnresolvedReferenceFlags,
|
||||
}
|
||||
|
||||
impl UnresolvedReference {
|
||||
pub const fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
|
||||
pub const fn exceptions(&self) -> Exceptions {
|
||||
self.exceptions
|
||||
}
|
||||
|
||||
pub const fn wildcard_import(&self) -> bool {
|
||||
self.flags
|
||||
.contains(UnresolvedReferenceFlags::WILDCARD_IMPORT)
|
||||
}
|
||||
|
||||
pub fn name<'a>(&self, locator: &Locator<'a>) -> &'a str {
|
||||
locator.slice(self.range)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct UnresolvedReferenceFlags: u8 {
|
||||
/// The unresolved reference appeared in a context that includes a wildcard import.
|
||||
const WILDCARD_IMPORT = 1 << 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct UnresolvedReferences(Vec<UnresolvedReference>);
|
||||
|
||||
impl UnresolvedReferences {
|
||||
/// Pushes a new [`UnresolvedReference`].
|
||||
pub(crate) fn push(
|
||||
&mut self,
|
||||
range: TextRange,
|
||||
exceptions: Exceptions,
|
||||
flags: UnresolvedReferenceFlags,
|
||||
) {
|
||||
self.0.push(UnresolvedReference {
|
||||
range,
|
||||
exceptions,
|
||||
flags,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for UnresolvedReferences {
|
||||
type Target = Vec<UnresolvedReference>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue