Delay computation of Definition visibility (#4339)

This commit is contained in:
Charlie Marsh 2023-05-11 13:14:29 -04:00 committed by GitHub
parent ffcf0618c7
commit 72e0ffc1ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 1064 additions and 833 deletions

View file

@ -7,25 +7,12 @@ use ruff_python_ast::helpers::map_callable;
use crate::context::Context;
#[derive(Debug, Clone, Copy)]
pub enum Modifier {
Module,
Class,
Function,
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, is_macro::Is)]
pub enum Visibility {
Public,
Private,
}
#[derive(Debug, Clone, Copy)]
pub struct VisibleScope {
pub modifier: Modifier,
pub visibility: Visibility,
}
/// Returns `true` if a function is a "static method".
pub fn is_staticmethod(ctx: &Context, decorator_list: &[Expr]) -> bool {
decorator_list.iter().any(|expr| {
@ -138,29 +125,45 @@ fn stem(path: &str) -> &str {
}
}
/// Return the `Visibility` of the Python file at `Path` based on its name.
pub fn module_visibility(module_path: Option<&[String]>, path: &Path) -> Visibility {
if let Some(module_path) = module_path {
if module_path.iter().any(|m| is_private_module(m)) {
return Visibility::Private;
}
} else {
// When module_path is None, path is a script outside a package, so just
// check to see if the module name itself is private.
// Ex) `_foo.py` (but not `__init__.py`)
let mut components = path.iter().rev();
if let Some(filename) = components.next() {
let module_name = filename.to_string_lossy();
let module_name = stem(&module_name);
if is_private_module(module_name) {
return Visibility::Private;
}
}
}
Visibility::Public
/// 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)]
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),
}
pub fn function_visibility(stmt: &Stmt) -> Visibility {
impl ModuleSource<'_> {
/// Return the `Visibility` of the module.
pub(crate) fn to_visibility(&self) -> Visibility {
match self {
Self::Path(path) => {
if path.iter().any(|m| is_private_module(m)) {
return Visibility::Private;
}
}
Self::File(path) => {
// Check to see if the filename itself indicates private visibility.
// Ex) `_foo.py` (but not `__init__.py`)
let mut components = path.iter().rev();
if let Some(filename) = components.next() {
let module_name = filename.to_string_lossy();
let module_name = stem(&module_name);
if is_private_module(module_name) {
return Visibility::Private;
}
}
}
}
Visibility::Public
}
}
pub(crate) fn function_visibility(stmt: &Stmt) -> Visibility {
match &stmt.node {
StmtKind::FunctionDef(ast::StmtFunctionDef { name, .. })
| StmtKind::AsyncFunctionDef(ast::StmtAsyncFunctionDef { name, .. }) => {
@ -174,7 +177,7 @@ pub fn function_visibility(stmt: &Stmt) -> Visibility {
}
}
pub fn method_visibility(stmt: &Stmt) -> Visibility {
pub(crate) fn method_visibility(stmt: &Stmt) -> Visibility {
match &stmt.node {
StmtKind::FunctionDef(ast::StmtFunctionDef {
name,
@ -212,7 +215,7 @@ pub fn method_visibility(stmt: &Stmt) -> Visibility {
}
}
pub fn class_visibility(stmt: &Stmt) -> Visibility {
pub(crate) fn class_visibility(stmt: &Stmt) -> Visibility {
match &stmt.node {
StmtKind::ClassDef(ast::StmtClassDef { name, .. }) => {
if name.starts_with('_') {