//! Definitions within a Python program. In this context, a "definition" is any named entity that //! can be documented, such as a module, class, or function. use std::fmt::Debug; use std::ops::Deref; use std::path::Path; use ruff_index::{newtype_index, IndexSlice, IndexVec}; use ruff_python_ast::name::QualifiedName; use ruff_python_ast::{self as ast, Stmt, StmtFunctionDef}; use ruff_text_size::{Ranged, TextRange}; use crate::analyze::visibility::{ class_visibility, function_visibility, is_property, method_visibility, module_visibility, Visibility, }; use crate::model::all::DunderAllName; use crate::SemanticModel; /// Id uniquely identifying a definition in a program. #[newtype_index] pub struct DefinitionId; impl DefinitionId { /// Returns the ID for the module definition. #[inline] pub const fn module() -> Self { DefinitionId::from_u32(0) } } /// A Python module can either be defined as a module path (i.e., the dot-separated path to the /// module) or, if the module can't be resolved, as a file path (i.e., the path to the file defining /// the module). #[derive(Debug, Copy, Clone)] pub enum ModuleSource<'a> { /// A module path is a dot-separated path to the module. Path(&'a [String]), /// A file path is the path to the file defining the module, often a script outside of a /// package. File(&'a Path), } #[derive(Debug, Copy, Clone, is_macro::Is)] pub enum ModuleKind { /// A Python file that represents a module within a package. Module, /// A Python file that represents the root of a package (i.e., an `__init__.py` file). Package, } /// A Python module. #[derive(Debug, Copy, Clone)] pub struct Module<'a> { pub kind: ModuleKind, pub source: ModuleSource<'a>, pub python_ast: &'a [Stmt], pub name: Option<&'a str>, } impl<'a> Module<'a> { /// Return the fully-qualified path of the module. pub const fn qualified_name(&self) -> Option<&'a [String]> { if let ModuleSource::Path(path) = self.source { Some(path) } else { None } } /// Return the name of the module. pub const fn name(&self) -> Option<&'a str> { self.name } } #[derive(Debug, Copy, Clone, is_macro::Is)] pub enum MemberKind<'a> { /// A class definition within a program. Class(&'a ast::StmtClassDef), /// A nested class definition within a program. NestedClass(&'a ast::StmtClassDef), /// A function definition within a program. Function(&'a ast::StmtFunctionDef), /// A nested function definition within a program. NestedFunction(&'a ast::StmtFunctionDef), /// A method definition within a program. Method(&'a ast::StmtFunctionDef), } /// A member of a Python module. #[derive(Debug)] pub struct Member<'a> { pub kind: MemberKind<'a>, pub parent: DefinitionId, } impl<'a> Member<'a> { /// Return the name of the member. pub fn name(&self) -> &'a str { match self.kind { MemberKind::Class(class) => &class.name, MemberKind::NestedClass(class) => &class.name, MemberKind::Function(function) => &function.name, MemberKind::NestedFunction(function) => &function.name, MemberKind::Method(method) => &method.name, } } /// Return the body of the member. pub fn body(&self) -> &'a [Stmt] { match self.kind { MemberKind::Class(class) => &class.body, MemberKind::NestedClass(class) => &class.body, MemberKind::Function(function) => &function.body, MemberKind::NestedFunction(function) => &function.body, MemberKind::Method(method) => &method.body, } } } impl Ranged for Member<'_> { /// Return the range of the member. fn range(&self) -> TextRange { match self.kind { MemberKind::Class(class) => class.range(), MemberKind::NestedClass(class) => class.range(), MemberKind::Function(function) => function.range(), MemberKind::NestedFunction(function) => function.range(), MemberKind::Method(method) => method.range(), } } } /// A definition within a Python program. #[derive(Debug, is_macro::Is)] pub enum Definition<'a> { Module(Module<'a>), Member(Member<'a>), } impl<'a> Definition<'a> { /// Returns `true` if the [`Definition`] is a method definition. pub const fn is_method(&self) -> bool { matches!( self, Definition::Member(Member { kind: MemberKind::Method(_), .. }) ) } pub fn is_property
(&self, extra_properties: P, semantic: &SemanticModel) -> bool
where
P: IntoIterator