mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
Store flags rather than ExecutionContext
on references (#6006)
This commit is contained in:
parent
4b2ec7d562
commit
0bb175f7f6
3 changed files with 92 additions and 61 deletions
|
@ -279,10 +279,9 @@ impl<'a> SemanticModel<'a> {
|
|||
if let Some(binding_id) = self.scopes.global().get(symbol) {
|
||||
if !self.bindings[binding_id].is_unbound() {
|
||||
// Mark the binding as used.
|
||||
let context = self.execution_context();
|
||||
let reference_id =
|
||||
self.resolved_references
|
||||
.push(ScopeId::global(), range, context);
|
||||
.push(ScopeId::global(), range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
|
||||
// Mark any submodule aliases as used.
|
||||
|
@ -291,7 +290,7 @@ impl<'a> SemanticModel<'a> {
|
|||
{
|
||||
let reference_id =
|
||||
self.resolved_references
|
||||
.push(ScopeId::global(), range, context);
|
||||
.push(ScopeId::global(), range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
}
|
||||
|
||||
|
@ -322,13 +321,16 @@ impl<'a> SemanticModel<'a> {
|
|||
|
||||
if let Some(binding_id) = scope.get(symbol) {
|
||||
// Mark the binding as used.
|
||||
let context = self.execution_context();
|
||||
let reference_id = self.resolved_references.push(self.scope_id, range, context);
|
||||
let reference_id = self
|
||||
.resolved_references
|
||||
.push(self.scope_id, range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
|
||||
// Mark any submodule aliases as used.
|
||||
if let Some(binding_id) = self.resolve_submodule(symbol, scope_id, binding_id) {
|
||||
let reference_id = self.resolved_references.push(self.scope_id, range, context);
|
||||
let reference_id =
|
||||
self.resolved_references
|
||||
.push(self.scope_id, range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
}
|
||||
|
||||
|
@ -392,9 +394,9 @@ impl<'a> SemanticModel<'a> {
|
|||
// The `x` in `print(x)` should resolve to the `x` in `x = 1`.
|
||||
BindingKind::UnboundException(Some(binding_id)) => {
|
||||
// Mark the binding as used.
|
||||
let context = self.execution_context();
|
||||
let reference_id =
|
||||
self.resolved_references.push(self.scope_id, range, context);
|
||||
self.resolved_references
|
||||
.push(self.scope_id, range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
|
||||
// Mark any submodule aliases as used.
|
||||
|
@ -402,7 +404,8 @@ impl<'a> SemanticModel<'a> {
|
|||
self.resolve_submodule(symbol, scope_id, binding_id)
|
||||
{
|
||||
let reference_id =
|
||||
self.resolved_references.push(self.scope_id, range, context);
|
||||
self.resolved_references
|
||||
.push(self.scope_id, range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
}
|
||||
|
||||
|
@ -918,17 +921,17 @@ impl<'a> SemanticModel<'a> {
|
|||
|
||||
/// Add a reference to the given [`BindingId`] in the local scope.
|
||||
pub fn add_local_reference(&mut self, binding_id: BindingId, range: TextRange) {
|
||||
let reference_id =
|
||||
self.resolved_references
|
||||
.push(self.scope_id, range, ExecutionContext::Runtime);
|
||||
let reference_id = self
|
||||
.resolved_references
|
||||
.push(self.scope_id, range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
}
|
||||
|
||||
/// Add a reference to the given [`BindingId`] in the global scope.
|
||||
pub fn add_global_reference(&mut self, binding_id: BindingId, range: TextRange) {
|
||||
let reference_id =
|
||||
self.resolved_references
|
||||
.push(ScopeId::global(), range, ExecutionContext::Runtime);
|
||||
let reference_id = self
|
||||
.resolved_references
|
||||
.push(ScopeId::global(), range, self.flags);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
}
|
||||
|
||||
|
@ -965,19 +968,6 @@ impl<'a> SemanticModel<'a> {
|
|||
self.unresolved_references.iter()
|
||||
}
|
||||
|
||||
/// Return the [`ExecutionContext`] of the current scope.
|
||||
pub const fn execution_context(&self) -> ExecutionContext {
|
||||
if self.in_type_checking_block()
|
||||
|| self.in_typing_only_annotation()
|
||||
|| self.in_complex_string_type_definition()
|
||||
|| self.in_simple_string_type_definition()
|
||||
{
|
||||
ExecutionContext::Typing
|
||||
} else {
|
||||
ExecutionContext::Runtime
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the union of all handled exceptions as an [`Exceptions`] bitflag.
|
||||
pub fn exceptions(&self) -> Exceptions {
|
||||
let mut exceptions = Exceptions::empty();
|
||||
|
@ -1011,50 +1001,65 @@ impl<'a> SemanticModel<'a> {
|
|||
self.flags = flags;
|
||||
}
|
||||
|
||||
/// Return the [`ExecutionContext`] of the current scope.
|
||||
pub const fn execution_context(&self) -> ExecutionContext {
|
||||
if self.flags.intersects(SemanticModelFlags::TYPING_CONTEXT) {
|
||||
ExecutionContext::Typing
|
||||
} else {
|
||||
ExecutionContext::Runtime
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a type annotation.
|
||||
pub const fn in_annotation(&self) -> bool {
|
||||
self.in_typing_only_annotation() || self.in_runtime_annotation()
|
||||
self.flags.intersects(SemanticModelFlags::ANNOTATION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a typing-only type annotation.
|
||||
pub const fn in_typing_only_annotation(&self) -> bool {
|
||||
self.flags
|
||||
.contains(SemanticModelFlags::TYPING_ONLY_ANNOTATION)
|
||||
.intersects(SemanticModelFlags::TYPING_ONLY_ANNOTATION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a runtime-required type annotation.
|
||||
pub const fn in_runtime_annotation(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::RUNTIME_ANNOTATION)
|
||||
self.flags
|
||||
.intersects(SemanticModelFlags::RUNTIME_ANNOTATION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a type definition.
|
||||
pub const fn in_type_definition(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::TYPE_DEFINITION)
|
||||
self.flags.intersects(SemanticModelFlags::TYPE_DEFINITION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a string type definition.
|
||||
pub const fn in_string_type_definition(&self) -> bool {
|
||||
self.flags
|
||||
.intersects(SemanticModelFlags::STRING_TYPE_DEFINITION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a "simple" string type definition.
|
||||
pub const fn in_simple_string_type_definition(&self) -> bool {
|
||||
self.flags
|
||||
.contains(SemanticModelFlags::SIMPLE_STRING_TYPE_DEFINITION)
|
||||
.intersects(SemanticModelFlags::SIMPLE_STRING_TYPE_DEFINITION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a "complex" string type definition.
|
||||
pub const fn in_complex_string_type_definition(&self) -> bool {
|
||||
self.flags
|
||||
.contains(SemanticModelFlags::COMPLEX_STRING_TYPE_DEFINITION)
|
||||
.intersects(SemanticModelFlags::COMPLEX_STRING_TYPE_DEFINITION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a `__future__` type definition.
|
||||
pub const fn in_future_type_definition(&self) -> bool {
|
||||
self.flags
|
||||
.contains(SemanticModelFlags::FUTURE_TYPE_DEFINITION)
|
||||
.intersects(SemanticModelFlags::FUTURE_TYPE_DEFINITION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in any kind of deferred type definition.
|
||||
pub const fn in_deferred_type_definition(&self) -> bool {
|
||||
self.in_simple_string_type_definition()
|
||||
|| self.in_complex_string_type_definition()
|
||||
|| self.in_future_type_definition()
|
||||
self.flags
|
||||
.intersects(SemanticModelFlags::DEFERRED_TYPE_DEFINITION)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a forward type reference.
|
||||
|
@ -1073,54 +1078,55 @@ impl<'a> SemanticModel<'a> {
|
|||
/// cast(Thread, x) # Non-forward reference
|
||||
/// ```
|
||||
pub const fn in_forward_reference(&self) -> bool {
|
||||
self.in_simple_string_type_definition()
|
||||
|| self.in_complex_string_type_definition()
|
||||
self.in_string_type_definition()
|
||||
|| (self.in_future_type_definition() && self.in_typing_only_annotation())
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in an exception handler.
|
||||
pub const fn in_exception_handler(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::EXCEPTION_HANDLER)
|
||||
self.flags.intersects(SemanticModelFlags::EXCEPTION_HANDLER)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in an f-string.
|
||||
pub const fn in_f_string(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::F_STRING)
|
||||
self.flags.intersects(SemanticModelFlags::F_STRING)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in boolean test.
|
||||
pub const fn in_boolean_test(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::BOOLEAN_TEST)
|
||||
self.flags.intersects(SemanticModelFlags::BOOLEAN_TEST)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a `typing::Literal` annotation.
|
||||
pub const fn in_literal(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::LITERAL)
|
||||
self.flags.intersects(SemanticModelFlags::LITERAL)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a subscript expression.
|
||||
pub const fn in_subscript(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::SUBSCRIPT)
|
||||
self.flags.intersects(SemanticModelFlags::SUBSCRIPT)
|
||||
}
|
||||
|
||||
/// Return `true` if the model is in a type-checking block.
|
||||
pub const fn in_type_checking_block(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::TYPE_CHECKING_BLOCK)
|
||||
self.flags
|
||||
.intersects(SemanticModelFlags::TYPE_CHECKING_BLOCK)
|
||||
}
|
||||
|
||||
/// Return `true` if the model has traversed past the "top-of-file" import boundary.
|
||||
pub const fn seen_import_boundary(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::IMPORT_BOUNDARY)
|
||||
self.flags.intersects(SemanticModelFlags::IMPORT_BOUNDARY)
|
||||
}
|
||||
|
||||
/// Return `true` if the model has traverse past the `__future__` import boundary.
|
||||
pub const fn seen_futures_boundary(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::FUTURES_BOUNDARY)
|
||||
self.flags.intersects(SemanticModelFlags::FUTURES_BOUNDARY)
|
||||
}
|
||||
|
||||
/// Return `true` if `__future__`-style type annotations are enabled.
|
||||
pub const fn future_annotations(&self) -> bool {
|
||||
self.flags.contains(SemanticModelFlags::FUTURE_ANNOTATIONS)
|
||||
self.flags
|
||||
.intersects(SemanticModelFlags::FUTURE_ANNOTATIONS)
|
||||
}
|
||||
|
||||
/// Return an iterator over all bindings shadowed by the given [`BindingId`], within the
|
||||
|
@ -1370,6 +1376,22 @@ bitflags! {
|
|||
/// ...
|
||||
/// ```
|
||||
const FUTURE_ANNOTATIONS = 1 << 14;
|
||||
|
||||
/// The context is in any type annotation.
|
||||
const ANNOTATION = Self::TYPING_ONLY_ANNOTATION.bits() | Self::RUNTIME_ANNOTATION.bits();
|
||||
|
||||
/// The context is in any string type definition.
|
||||
const STRING_TYPE_DEFINITION = Self::SIMPLE_STRING_TYPE_DEFINITION.bits()
|
||||
| Self::COMPLEX_STRING_TYPE_DEFINITION.bits();
|
||||
|
||||
/// The context is in any deferred type definition.
|
||||
const DEFERRED_TYPE_DEFINITION = Self::SIMPLE_STRING_TYPE_DEFINITION.bits()
|
||||
| Self::COMPLEX_STRING_TYPE_DEFINITION.bits()
|
||||
| Self::FUTURE_TYPE_DEFINITION.bits();
|
||||
|
||||
/// The context is in a typing-only context.
|
||||
const TYPING_CONTEXT = Self::TYPE_CHECKING_BLOCK.bits() | Self::TYPING_ONLY_ANNOTATION.bits() |
|
||||
Self::STRING_TYPE_DEFINITION.bits();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use ruff_python_ast::source_code::Locator;
|
|||
|
||||
use crate::context::ExecutionContext;
|
||||
use crate::scope::ScopeId;
|
||||
use crate::Exceptions;
|
||||
use crate::{Exceptions, SemanticModelFlags};
|
||||
|
||||
/// A resolved read reference to a name in a program.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -16,21 +16,28 @@ pub struct ResolvedReference {
|
|||
scope_id: ScopeId,
|
||||
/// The range of the reference in the source code.
|
||||
range: TextRange,
|
||||
/// The context in which the reference occurs.
|
||||
context: ExecutionContext,
|
||||
/// The model state in which the reference occurs.
|
||||
flags: SemanticModelFlags,
|
||||
}
|
||||
|
||||
impl ResolvedReference {
|
||||
/// The scope in which the reference is defined.
|
||||
pub const fn scope_id(&self) -> ScopeId {
|
||||
self.scope_id
|
||||
}
|
||||
|
||||
/// The range of the reference in the source code.
|
||||
pub const fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
|
||||
/// The [`ExecutionContext`] of the reference.
|
||||
pub const fn context(&self) -> ExecutionContext {
|
||||
self.context
|
||||
if self.flags.intersects(SemanticModelFlags::TYPING_CONTEXT) {
|
||||
ExecutionContext::Typing
|
||||
} else {
|
||||
ExecutionContext::Runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,12 +55,12 @@ impl ResolvedReferences {
|
|||
&mut self,
|
||||
scope_id: ScopeId,
|
||||
range: TextRange,
|
||||
context: ExecutionContext,
|
||||
flags: SemanticModelFlags,
|
||||
) -> ResolvedReferenceId {
|
||||
self.0.push(ResolvedReference {
|
||||
scope_id,
|
||||
range,
|
||||
context,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +85,11 @@ pub struct UnresolvedReference {
|
|||
}
|
||||
|
||||
impl UnresolvedReference {
|
||||
/// Returns the name of the reference.
|
||||
pub fn name<'a>(&self, locator: &Locator<'a>) -> &'a str {
|
||||
locator.slice(self.range)
|
||||
}
|
||||
|
||||
/// The range of the reference in the source code.
|
||||
pub const fn range(&self) -> TextRange {
|
||||
self.range
|
||||
|
@ -93,11 +105,6 @@ impl UnresolvedReference {
|
|||
self.flags
|
||||
.contains(UnresolvedReferenceFlags::WILDCARD_IMPORT)
|
||||
}
|
||||
|
||||
/// Returns the name of the reference.
|
||||
pub fn name<'a>(&self, locator: &Locator<'a>) -> &'a str {
|
||||
locator.slice(self.range)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue