Use CompactString for Identifier (#12101)

This commit is contained in:
Micha Reiser 2024-07-01 10:06:02 +02:00 committed by GitHub
parent db6ee74cbe
commit 5109b50bb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
474 changed files with 4953 additions and 4776 deletions

29
Cargo.lock generated
View file

@ -232,6 +232,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "castaway"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.0.95"
@ -436,6 +445,20 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "compact_str"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"ryu",
"serde",
"static_assertions",
]
[[package]]
name = "console"
version = "0.15.8"
@ -1900,7 +1923,6 @@ dependencies = [
"rustc-hash 2.0.0",
"salsa",
"smallvec",
"smol_str",
"tracing",
]
@ -2259,13 +2281,17 @@ version = "0.0.0"
dependencies = [
"aho-corasick",
"bitflags 2.6.0",
"compact_str",
"is-macro",
"itertools 0.13.0",
"once_cell",
"ruff_cache",
"ruff_macros",
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"schemars",
"serde",
]
@ -2352,6 +2378,7 @@ dependencies = [
"anyhow",
"bitflags 2.6.0",
"bstr",
"compact_str",
"insta",
"memchr",
"ruff_python_ast",

View file

@ -55,6 +55,7 @@ colored = { version = "2.1.0" }
console_error_panic_hook = { version = "0.1.7" }
console_log = { version = "1.0.0" }
countme = { version = "3.0.1" }
compact_str = "0.7.1"
criterion = { version = "0.5.1", default-features = false }
crossbeam = { version = "0.8.4" }
dashmap = { version = "5.5.3" }

View file

@ -1,6 +1,4 @@
use std::fmt::Formatter;
use std::hash::BuildHasherDefault;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use rustc_hash::{FxHashSet, FxHasher};
@ -68,41 +66,3 @@ impl Workspace {
self.open_files.contains(&file_id)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Name(smol_str::SmolStr);
impl Name {
#[inline]
pub fn new(name: &str) -> Self {
Self(smol_str::SmolStr::new(name))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Deref for Name {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl<T> From<T> for Name
where
T: Into<smol_str::SmolStr>,
{
fn from(value: T) -> Self {
Self(value.into())
}
}
impl std::fmt::Display for Name {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}

View file

@ -11,7 +11,6 @@ use crate::files::FileId;
use crate::module::Module;
use crate::module::ModuleName;
use crate::parse::parse;
use crate::Name;
pub(crate) use definitions::Definition;
use definitions::{ImportDefinition, ImportFromDefinition};
pub(crate) use flow_graph::ConstrainedDefinition;
@ -437,7 +436,7 @@ impl SourceOrderVisitor<'_> for SemanticIndexer {
};
let def = Definition::ImportFrom(ImportFromDefinition {
module: module.clone(),
name: Name::new(&alias.name.id),
name: alias.name.id.clone(),
level: *level,
});
self.add_or_update_symbol_with_def(symbol_name, def);

View file

@ -1,7 +1,7 @@
use crate::ast_ids::TypedNodeKey;
use crate::semantic::ModuleName;
use crate::Name;
use ruff_python_ast as ast;
use ruff_python_ast::name::Name;
// TODO storing TypedNodeKey for definitions means we have to search to find them again in the AST;
// this is at best O(log n). If looking up definitions is a bottleneck we should look for

View file

@ -9,11 +9,11 @@ use hashbrown::hash_map::{Keys, RawEntryMut};
use rustc_hash::{FxHashMap, FxHasher};
use ruff_index::{newtype_index, IndexVec};
use ruff_python_ast::name::Name;
use crate::ast_ids::NodeKey;
use crate::module::ModuleName;
use crate::semantic::{Definition, ExpressionId};
use crate::Name;
type Map<K, V> = hashbrown::HashMap<K, V, ()>;

View file

@ -6,7 +6,7 @@ use crate::module::{Module, ModuleName};
use crate::semantic::{
resolve_global_symbol, semantic_index, GlobalSymbolId, ScopeId, ScopeKind, SymbolId,
};
use crate::{FxDashMap, FxIndexSet, Name};
use crate::{FxDashMap, FxIndexSet};
use ruff_index::{newtype_index, IndexVec};
use ruff_python_ast as ast;
use rustc_hash::FxHashMap;
@ -14,6 +14,7 @@ use rustc_hash::FxHashMap;
pub(crate) mod infer;
pub(crate) use infer::{infer_definition_type, infer_symbol_public_type};
use ruff_python_ast::name::Name;
/// unique ID for a type
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -13,7 +13,7 @@ use crate::semantic::{
resolve_global_symbol, semantic_index, ConstrainedDefinition, Definition, GlobalSymbolId,
ImportDefinition, ImportFromDefinition,
};
use crate::{FileId, Name};
use crate::FileId;
// FIXME: Figure out proper dead-lock free synchronisation now that this takes `&db` instead of `&mut db`.
/// Resolve the public-facing type for a symbol (the type seen by other scopes: other modules, or
@ -315,7 +315,7 @@ fn infer_expr_type(db: &dyn SemanticDb, file_id: FileId, expr: &ast::Expr) -> Qu
}
ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
let value_type = infer_expr_type(db, file_id, value)?;
let attr_name = &Name::new(&attr.id);
let attr_name = &attr.id;
value_type
.get_member(db, attr_name)
.map(|ty| ty.unwrap_or(Type::Unknown))
@ -343,6 +343,7 @@ fn infer_expr_type(db: &dyn SemanticDb, file_id: FileId, expr: &ast::Expr) -> Qu
#[cfg(test)]
mod tests {
use ruff_python_ast::name::Name;
use std::path::PathBuf;
use crate::db::tests::TestDb;
@ -351,7 +352,6 @@ mod tests {
resolve_module, set_module_search_paths, ModuleName, ModuleResolutionInputs,
};
use crate::semantic::{infer_symbol_public_type, resolve_global_symbol, Type};
use crate::Name;
// TODO with virtual filesystem we shouldn't have to write files to disk for these
// tests
@ -476,7 +476,7 @@ mod tests {
};
let member_ty = class_id
.get_own_class_member(&case.db, &Name::new("f"))
.get_own_class_member(&case.db, &Name::new_static("f"))
.expect("C.f to resolve");
let Some(Type::Function(func_id)) = member_ty else {

View file

@ -21,7 +21,6 @@ bitflags = { workspace = true }
indexmap = { workspace = true }
salsa = { workspace = true }
smallvec = { workspace = true }
smol_str = { workspace = true }
tracing = { workspace = true }
rustc-hash = { workspace = true }
hashbrown = { workspace = true }

View file

@ -1,6 +1,5 @@
pub mod ast_node_ref;
mod db;
pub mod name;
mod node_key;
pub mod semantic_index;
pub mod types;

View file

@ -1,56 +0,0 @@
use std::ops::Deref;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Name(smol_str::SmolStr);
impl Name {
#[inline]
pub fn new(name: &str) -> Self {
Self(smol_str::SmolStr::new(name))
}
#[inline]
pub fn new_static(name: &'static str) -> Self {
Self(smol_str::SmolStr::new_static(name))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Deref for Name {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl<T> From<T> for Name
where
T: Into<smol_str::SmolStr>,
{
fn from(value: T) -> Self {
Self(value.into())
}
}
impl std::fmt::Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl PartialEq<str> for Name {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<Name> for str {
fn eq(&self, other: &Name) -> bool {
other == self
}
}

View file

@ -5,9 +5,9 @@ use rustc_hash::FxHashMap;
use ruff_db::parsed::ParsedModule;
use ruff_index::IndexVec;
use ruff_python_ast as ast;
use ruff_python_ast::name::Name;
use ruff_python_ast::visitor::{walk_expr, walk_stmt, Visitor};
use crate::name::Name;
use crate::node_key::NodeKey;
use crate::semantic_index::ast_ids::{
AstId, AstIdsBuilder, ScopeAssignmentId, ScopeClassId, ScopeFunctionId, ScopeImportFromId,
@ -133,7 +133,6 @@ impl<'a> SemanticIndexBuilder<'a> {
fn add_or_update_symbol_with_definition(
&mut self,
name: Name,
definition: Definition,
) -> ScopedSymbolId {
let symbol_table = self.current_symbol_table();
@ -168,7 +167,7 @@ impl<'a> SemanticIndexBuilder<'a> {
ast::TypeParam::ParamSpec(ast::TypeParamParamSpec { name, .. }) => name,
ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple { name, .. }) => name,
};
self.add_or_update_symbol(Name::new(name), SymbolFlags::IS_DEFINED);
self.add_or_update_symbol(name.id.clone(), SymbolFlags::IS_DEFINED);
}
}
@ -233,7 +232,7 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
for decorator in &function_def.decorator_list {
self.visit_decorator(decorator);
}
let name = Name::new(&function_def.name.id);
let name = &function_def.name.id;
let function_id = ScopeFunctionId(statement_id);
let definition = Definition::FunctionDef(function_id);
let scope = self.current_scope();
@ -243,7 +242,7 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
);
self.with_type_params(
&name,
name,
&WithTypeParams::FunctionDef {
node: function_def,
id: AstId::new(scope, function_id),
@ -257,7 +256,7 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
builder.push_scope(
NodeWithScopeId::Function(AstId::new(scope, function_id)),
&name,
name,
Some(symbol),
Some(definition),
);
@ -271,7 +270,7 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
self.visit_decorator(decorator);
}
let name = Name::new(&class.name.id);
let name = &class.name.id;
let class_id = ScopeClassId(statement_id);
let definition = Definition::from(class_id);
let scope = self.current_scope();
@ -280,7 +279,7 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
self.add_or_update_symbol_with_definition(name.clone(), definition),
);
self.with_type_params(
&name,
name,
&WithTypeParams::ClassDef {
node: class,
id: AstId::new(scope, class_id),
@ -293,7 +292,7 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
builder.push_scope(
NodeWithScopeId::Class(AstId::new(scope, class_id)),
&name,
name,
Some(id),
Some(definition),
);
@ -306,16 +305,16 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
ast::Stmt::Import(ast::StmtImport { names, .. }) => {
for (i, alias) in names.iter().enumerate() {
let symbol_name = if let Some(asname) = &alias.asname {
asname.id.as_str()
asname.id.clone()
} else {
alias.name.id.split('.').next().unwrap()
Name::new(alias.name.id.split('.').next().unwrap())
};
let def = Definition::Import(ImportDefinition {
import_id: ScopeImportId(statement_id),
alias: u32::try_from(i).unwrap(),
});
self.add_or_update_symbol_with_definition(Name::new(symbol_name), def);
self.add_or_update_symbol_with_definition(symbol_name, def);
}
}
ast::Stmt::ImportFrom(ast::StmtImportFrom {
@ -326,15 +325,15 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
}) => {
for (i, alias) in names.iter().enumerate() {
let symbol_name = if let Some(asname) = &alias.asname {
asname.id.as_str()
&asname.id
} else {
alias.name.id.as_str()
&alias.name.id
};
let def = Definition::ImportFrom(ImportFromDefinition {
import_id: ScopeImportFromId(statement_id),
name: u32::try_from(i).unwrap(),
});
self.add_or_update_symbol_with_definition(Name::new(symbol_name), def);
self.add_or_update_symbol_with_definition(symbol_name.clone(), def);
}
}
ast::Stmt::Assign(node) => {
@ -375,10 +374,10 @@ impl Visitor<'_> for SemanticIndexBuilder<'_> {
};
match self.current_definition {
Some(definition) if flags.contains(SymbolFlags::IS_DEFINED) => {
self.add_or_update_symbol_with_definition(Name::new(id), definition);
self.add_or_update_symbol_with_definition(id.clone(), definition);
}
_ => {
self.add_or_update_symbol(Name::new(id), flags);
self.add_or_update_symbol(id.clone(), flags);
}
}

View file

@ -7,13 +7,12 @@ use rustc_hash::FxHasher;
use salsa::DebugWithDb;
use smallvec::SmallVec;
use ruff_db::vfs::VfsFile;
use ruff_index::{newtype_index, IndexVec};
use crate::name::Name;
use crate::semantic_index::definition::Definition;
use crate::semantic_index::{root_scope, semantic_index, symbol_table, SymbolMap};
use crate::Db;
use ruff_db::vfs::VfsFile;
use ruff_index::{newtype_index, IndexVec};
use ruff_python_ast::name::Name;
#[derive(Eq, PartialEq, Debug)]
pub struct Symbol {

View file

@ -1,11 +1,5 @@
use salsa::DebugWithDb;
use ruff_db::parsed::parsed_module;
use ruff_db::vfs::VfsFile;
use ruff_index::newtype_index;
use ruff_python_ast as ast;
use crate::name::Name;
use crate::semantic_index::ast_ids::{AstIdNode, ScopeAstIdNode};
use crate::semantic_index::symbol::{FileScopeId, PublicSymbolId, ScopeId};
use crate::semantic_index::{
@ -14,6 +8,11 @@ use crate::semantic_index::{
use crate::types::infer::{TypeInference, TypeInferenceBuilder};
use crate::Db;
use crate::FxIndexSet;
use ruff_db::parsed::parsed_module;
use ruff_db::vfs::VfsFile;
use ruff_index::newtype_index;
use ruff_python_ast as ast;
use ruff_python_ast::name::Name;
mod display;
mod infer;

View file

@ -9,7 +9,6 @@ use ruff_index::IndexVec;
use ruff_python_ast as ast;
use ruff_python_ast::{ExprContext, TypeParams};
use crate::name::Name;
use crate::semantic_index::ast_ids::{ScopeAstIdNode, ScopeExpressionId};
use crate::semantic_index::definition::{Definition, ImportDefinition, ImportFromDefinition};
use crate::semantic_index::symbol::{FileScopeId, ScopeId, ScopeKind, ScopedSymbolId, SymbolTable};
@ -199,7 +198,7 @@ impl<'db> TypeInferenceBuilder<'db> {
}
let function_ty = self.function_ty(FunctionType {
name: Name::new(&name.id),
name: name.id.clone(),
decorators: decorator_tys,
});
@ -248,7 +247,7 @@ impl<'db> TypeInferenceBuilder<'db> {
assert_eq!(class_body_scope.kind(), ScopeKind::Class);
let class_ty = self.class_ty(ClassType {
name: Name::new(name),
name: name.id.clone(),
bases,
body_scope: class_body_scope_id.to_scope_id(self.db, self.file_id),
});
@ -398,7 +397,7 @@ impl<'db> TypeInferenceBuilder<'db> {
} = alias;
let ty = module_ty
.member(&self.typing_context(), &Name::new(&name.id))
.member(&self.typing_context(), &name.id)
.unwrap_or(Type::Unknown);
self.definition_tys.insert(
@ -557,7 +556,7 @@ impl<'db> TypeInferenceBuilder<'db> {
let value_ty = self.infer_expression(value);
let member_ty = value_ty
.member(&self.typing_context(), &Name::new(&attr.id))
.member(&self.typing_context(), &attr.id)
.unwrap_or(Type::Unknown);
match ctx {
@ -695,9 +694,9 @@ mod tests {
use ruff_db::vfs::system_path_to_file;
use crate::db::tests::TestDb;
use crate::name::Name;
use crate::types::{public_symbol_ty_by_name, Type, TypingContext};
use red_knot_module_resolver::{set_module_resolution_settings, ModuleResolutionSettings};
use ruff_python_ast::name::Name;
fn setup_db() -> TestDb {
let mut db = TestDb::new();
@ -791,7 +790,7 @@ class C:
};
let context = TypingContext::global(&db);
let member_ty = class_id.class_member(&context, &Name::new("f"));
let member_ty = class_id.class_member(&context, &Name::new_static("f"));
let Some(Type::Function(func_id)) = member_ty else {
panic!("C.f is not a Function");

View file

@ -140,7 +140,7 @@ pub(crate) fn make_redundant_alias<'a>(
.filter_map(|name| {
aliases
.iter()
.find(|alias| alias.asname.is_none() && name == alias.name.id)
.find(|alias| alias.asname.is_none() && *name == alias.name.id)
.map(|alias| Edit::range_replacement(format!("{name} as {name}"), alias.range))
})
.collect()

View file

@ -6,17 +6,17 @@
use std::error::Error;
use anyhow::Result;
use libcst_native::{ImportAlias, Name, NameOrAttribute};
use ruff_python_ast::{self as ast, ModModule, Stmt};
use ruff_python_parser::{Parsed, Tokens};
use ruff_text_size::{Ranged, TextSize};
use libcst_native::{ImportAlias, Name as cstName, NameOrAttribute};
use ruff_diagnostics::Edit;
use ruff_python_ast::imports::{AnyImport, Import, ImportFrom};
use ruff_python_ast::{self as ast, ModModule, Stmt};
use ruff_python_codegen::Stylist;
use ruff_python_parser::{Parsed, Tokens};
use ruff_python_semantic::{ImportedName, SemanticModel};
use ruff_python_trivia::textwrap::indent;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextSize};
use crate::cst::matchers::{match_aliases, match_import_from, match_statement};
use crate::fix;
@ -425,7 +425,7 @@ impl<'a> Importer<'a> {
let import_from = match_import_from(&mut statement)?;
let aliases = match_aliases(import_from)?;
aliases.push(ImportAlias {
name: NameOrAttribute::N(Box::new(Name {
name: NameOrAttribute::N(Box::new(cstName {
value: member,
lpar: vec![],
rpar: vec![],

View file

@ -81,7 +81,7 @@ pub(crate) fn variable_name_task_id(
let ast::ExprStringLiteral { value: task_id, .. } = keyword.value.as_string_literal_expr()?;
// If the target name is the same as the task_id, no violation.
if task_id == id {
if task_id == id.as_str() {
return None;
}

View file

@ -5,6 +5,7 @@ use ruff_diagnostics::Edit;
use ruff_python_ast::helpers::{
pep_604_union, typing_optional, typing_union, ReturnStatementVisitor,
};
use ruff_python_ast::name::Name;
use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::{self as ast, Expr, ExprContext};
use ruff_python_semantic::analyze::terminal::Terminal;
@ -140,7 +141,7 @@ impl AutoPythonType {
)
.ok()?;
let expr = Expr::Name(ast::ExprName {
id: binding,
id: Name::from(binding),
range: TextRange::default(),
ctx: ExprContext::Load,
});
@ -181,7 +182,7 @@ impl AutoPythonType {
semantic,
)
.ok()?;
let expr = typing_optional(element, binding);
let expr = typing_optional(element, Name::from(binding));
Some((expr, vec![optional_edit]))
}
_ => {
@ -198,7 +199,7 @@ impl AutoPythonType {
semantic,
)
.ok()?;
let expr = typing_union(&elements, binding);
let expr = typing_union(&elements, Name::from(binding));
Some((expr, vec![union_edit]))
}
}

View file

@ -1,11 +1,12 @@
//! Rules from [flake8-gettext](https://pypi.org/project/flake8-gettext/).
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr};
pub(crate) mod rules;
pub mod settings;
/// Returns true if the [`Expr`] is an internationalization function call.
pub(crate) fn is_gettext_func_call(func: &Expr, functions_names: &[String]) -> bool {
pub(crate) fn is_gettext_func_call(func: &Expr, functions_names: &[Name]) -> bool {
if let Expr::Name(ast::ExprName { id, .. }) = func {
functions_names.contains(id)
} else {

View file

@ -1,17 +1,18 @@
use crate::display_settings;
use ruff_macros::CacheKey;
use ruff_python_ast::name::Name;
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone, CacheKey)]
pub struct Settings {
pub functions_names: Vec<String>,
pub functions_names: Vec<Name>,
}
pub fn default_func_names() -> Vec<String> {
pub fn default_func_names() -> Vec<Name> {
vec![
"_".to_string(),
"gettext".to_string(),
"ngettext".to_string(),
Name::new_static("_"),
Name::new_static("gettext"),
Name::new_static("ngettext"),
]
}

View file

@ -2,6 +2,7 @@ use ast::ExprContext;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::pep_604_union;
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr};
use ruff_python_semantic::analyze::typing::traverse_union;
use ruff_text_size::{Ranged, TextRange};
@ -26,7 +27,7 @@ use crate::checkers::ast::Checker;
/// ```
#[violation]
pub struct UnnecessaryTypeUnion {
members: Vec<String>,
members: Vec<Name>,
is_pep604_union: bool,
}
@ -83,10 +84,10 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr)
traverse_union(&mut collect_type_exprs, semantic, union);
if type_exprs.len() > 1 {
let type_members: Vec<String> = type_exprs
let type_members: Vec<Name> = type_exprs
.clone()
.into_iter()
.map(|type_expr| checker.locator().slice(type_expr).to_string())
.map(|type_expr| Name::new(checker.locator().slice(type_expr)))
.collect();
let mut diagnostic = Diagnostic::new(
@ -101,7 +102,7 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr)
let content = if let Some(subscript) = subscript {
let types = &Expr::Subscript(ast::ExprSubscript {
value: Box::new(Expr::Name(ast::ExprName {
id: "type".into(),
id: Name::new_static("type"),
ctx: ExprContext::Load,
range: TextRange::default(),
})),
@ -154,7 +155,7 @@ pub(crate) fn unnecessary_type_union<'a>(checker: &mut Checker, union: &'a Expr)
let elts: Vec<Expr> = type_exprs.into_iter().cloned().collect();
let types = Expr::Subscript(ast::ExprSubscript {
value: Box::new(Expr::Name(ast::ExprName {
id: "type".into(),
id: Name::new_static("type"),
ctx: ExprContext::Load,
range: TextRange::default(),
})),

View file

@ -1,4 +1,5 @@
use anyhow::{anyhow, bail, Result};
use ruff_python_ast::name::Name;
use ruff_python_ast::{
self as ast, Arguments, CmpOp, Expr, ExprContext, Identifier, Keyword, Stmt, UnaryOp,
};
@ -379,7 +380,7 @@ impl UnittestAssert {
.ok_or_else(|| anyhow!("Missing argument `cls`"))?;
let msg = args.get("msg").copied();
let node = ast::ExprName {
id: "isinstance".into(),
id: Name::new_static("isinstance"),
ctx: ExprContext::Load,
range: TextRange::default(),
};
@ -417,7 +418,7 @@ impl UnittestAssert {
.ok_or_else(|| anyhow!("Missing argument `regex`"))?;
let msg = args.get("msg").copied();
let node = ast::ExprName {
id: "re".into(),
id: Name::new_static("re"),
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -7,13 +7,13 @@ mod tests {
use std::convert::AsRef;
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::registry::Rule;
use crate::rules::flake8_self;
use crate::test::test_path;
use crate::{assert_messages, settings};
use anyhow::Result;
use ruff_python_ast::name::Name;
use test_case::test_case;
#[test_case(Rule::PrivateMemberAccess, Path::new("SLF001.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
@ -32,7 +32,7 @@ mod tests {
Path::new("flake8_self/SLF001_extended.py"),
&settings::LinterSettings {
flake8_self: flake8_self::settings::Settings {
ignore_names: vec!["_meta".to_string()],
ignore_names: vec![Name::new_static("_meta")],
},
..settings::LinterSettings::for_rule(Rule::PrivateMemberAccess)
},

View file

@ -97,7 +97,7 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) {
.settings
.flake8_self
.ignore_names
.contains(attr.as_ref())
.contains(attr.id())
{
return;
}

View file

@ -2,6 +2,7 @@
use crate::display_settings;
use ruff_macros::CacheKey;
use ruff_python_ast::name::Name;
use std::fmt::{Display, Formatter};
// By default, ignore the `namedtuple` methods and attributes, as well as the
@ -19,13 +20,13 @@ pub const IGNORE_NAMES: [&str; 7] = [
#[derive(Debug, Clone, CacheKey)]
pub struct Settings {
pub ignore_names: Vec<String>,
pub ignore_names: Vec<Name>,
}
impl Default for Settings {
fn default() -> Self {
Self {
ignore_names: IGNORE_NAMES.map(String::from).to_vec(),
ignore_names: IGNORE_NAMES.map(Name::new_static).to_vec(),
}
}
}

View file

@ -10,6 +10,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailab
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::helpers::{contains_effect, Truthiness};
use ruff_python_ast::name::Name;
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_codegen::Generator;
use ruff_python_semantic::SemanticModel;
@ -425,7 +426,7 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
let isinstance_call = ast::ExprCall {
func: Box::new(
ast::ExprName {
id: "isinstance".into(),
id: Name::new_static("isinstance"),
ctx: ExprContext::Load,
range: TextRange::default(),
}
@ -469,7 +470,7 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
}
}
fn match_eq_target(expr: &Expr) -> Option<(&str, &Expr)> {
fn match_eq_target(expr: &Expr) -> Option<(&Name, &Expr)> {
let Expr::Compare(ast::ExprCompare {
left,
ops,
@ -482,7 +483,7 @@ fn match_eq_target(expr: &Expr) -> Option<(&str, &Expr)> {
if **ops != [CmpOp::Eq] {
return None;
}
let Expr::Name(ast::ExprName { id, .. }) = left.as_ref() else {
let Expr::Name(ast::ExprName { id, .. }) = &**left else {
return None;
};
let [comparator] = &**comparators else {
@ -507,7 +508,7 @@ pub(crate) fn compare_with_tuple(checker: &mut Checker, expr: &Expr) {
// Given `a == "foo" or a == "bar"`, we generate `{"a": [(0, "foo"), (1,
// "bar")]}`.
let mut id_to_comparators: BTreeMap<&str, Vec<(usize, &Expr)>> = BTreeMap::new();
let mut id_to_comparators: BTreeMap<&Name, Vec<(usize, &Expr)>> = BTreeMap::new();
for (index, value) in values.iter().enumerate() {
if let Some((id, comparator)) = match_eq_target(value) {
id_to_comparators
@ -548,7 +549,7 @@ pub(crate) fn compare_with_tuple(checker: &mut Checker, expr: &Expr) {
parenthesized: true,
};
let node1 = ast::ExprName {
id: id.into(),
id: id.clone(),
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -4,6 +4,7 @@ use ruff_text_size::{Ranged, TextRange};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{is_const_false, is_const_true};
use ruff_python_ast::name::Name;
use ruff_python_ast::parenthesize::parenthesized_range;
use crate::checkers::ast::Checker;
@ -178,7 +179,7 @@ pub(crate) fn if_expr_with_true_false(
&ast::ExprCall {
func: Box::new(
ast::ExprName {
id: "bool".into(),
id: Name::new_static("bool"),
ctx: ExprContext::Load,
range: TextRange::default(),
}

View file

@ -3,6 +3,7 @@ use ruff_text_size::{Ranged, TextRange};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_semantic::ScopeKind;
use crate::checkers::ast::Checker;
@ -272,7 +273,7 @@ pub(crate) fn double_negation(checker: &mut Checker, expr: &Expr, op: UnaryOp, o
)));
} else if checker.semantic().has_builtin_binding("bool") {
let node = ast::ExprName {
id: "bool".into(),
id: Name::new_static("bool"),
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -1,5 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::traversal;
use ruff_python_ast::{self as ast, Arguments, ElifElseClause, Expr, ExprContext, Stmt};
use ruff_python_semantic::analyze::typing::{is_sys_version_block, is_type_checking_block};
@ -226,7 +227,7 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
} else if checker.semantic().has_builtin_binding("bool") {
// Otherwise, we need to wrap the condition in a call to `bool`.
let func_node = ast::ExprName {
id: "bool".into(),
id: Name::new_static("bool"),
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -1,6 +1,7 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::any_over_expr;
use ruff_python_ast::name::Name;
use ruff_python_ast::traversal;
use ruff_python_ast::{
self as ast, Arguments, CmpOp, Comprehension, Expr, ExprContext, Stmt, UnaryOp,
@ -89,7 +90,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) {
// Replace with `any`.
(true, false) => {
let contents = return_stmt(
"any",
Name::new_static("any"),
loop_.test,
loop_.target,
loop_.iter,
@ -177,7 +178,13 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) {
node.into()
}
};
let contents = return_stmt("all", &test, loop_.target, loop_.iter, checker.generator());
let contents = return_stmt(
Name::new_static("all"),
&test,
loop_.target,
loop_.iter,
checker.generator(),
);
// Don't flag if the resulting expression would exceed the maximum line length.
let line_start = checker.locator().line_start(stmt.start());
@ -372,7 +379,7 @@ fn match_sibling_return<'a>(stmt: &'a Stmt, sibling: &'a Stmt) -> Option<Termina
}
/// Generate a return statement for an `any` or `all` builtin comprehension.
fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Generator) -> String {
fn return_stmt(id: Name, test: &Expr, target: &Expr, iter: &Expr, generator: Generator) -> String {
let node = ast::ExprGenerator {
elt: Box::new(test.clone()),
generators: vec![Comprehension {
@ -386,7 +393,7 @@ fn return_stmt(id: &str, test: &Expr, target: &Expr, iter: &Expr, generator: Gen
parenthesized: false,
};
let node1 = ast::ExprName {
id: id.into(),
id,
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -1,9 +1,9 @@
//! Implements helper functions for using vendored/format.rs
use std::convert::TryFrom;
use ruff_python_ast::name::Name;
use ruff_python_literal::format::{
FieldName, FieldType, FormatParseError, FormatPart, FormatString, FromTemplate,
};
use std::convert::TryFrom;
pub(crate) fn error_to_string(err: &FormatParseError) -> String {
match err {
@ -26,7 +26,7 @@ pub(crate) fn error_to_string(err: &FormatParseError) -> String {
pub(crate) struct FormatSummary {
pub(crate) autos: Vec<usize>,
pub(crate) indices: Vec<usize>,
pub(crate) keywords: Vec<String>,
pub(crate) keywords: Vec<Name>,
pub(crate) has_nested_parts: bool,
}
@ -54,7 +54,7 @@ impl TryFrom<&str> for FormatSummary {
match parsed.field_type {
FieldType::Auto => autos.push(autos.len()),
FieldType::Index(i) => indices.push(i),
FieldType::Keyword(k) => keywords.push(k),
FieldType::Keyword(k) => keywords.push(Name::from(k)),
};
let nested = FormatString::from_str(format_spec)?;
@ -66,7 +66,7 @@ impl TryFrom<&str> for FormatSummary {
match parsed.field_type {
FieldType::Auto => autos.push(autos.len()),
FieldType::Index(i) => indices.push(i),
FieldType::Keyword(k) => keywords.push(k),
FieldType::Keyword(k) => keywords.push(Name::from(k)),
};
has_nested_parts = true;
}

View file

@ -4,7 +4,8 @@ use rustc_hash::FxHashSet;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr, Identifier, Keyword};
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr, Keyword};
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
@ -382,7 +383,7 @@ impl Violation for StringDotFormatInvalidFormat {
/// - [Python documentation: `str.format`](https://docs.python.org/3/library/stdtypes.html#str.format)
#[violation]
pub struct StringDotFormatExtraNamedArguments {
missing: Vec<String>,
missing: Vec<Name>,
}
impl Violation for StringDotFormatExtraNamedArguments {
@ -743,13 +744,13 @@ pub(crate) fn string_dot_format_extra_named_arguments(
.iter()
.filter_map(|Keyword { arg, .. }| arg.as_ref());
let missing: Vec<(usize, &str)> = keywords
let missing: Vec<(usize, &Name)> = keywords
.enumerate()
.filter_map(|(index, keyword)| {
if summary.keywords.contains(keyword.as_ref()) {
if summary.keywords.contains(keyword.id()) {
None
} else {
Some((index, keyword.as_str()))
Some((index, &keyword.id))
}
})
.collect();
@ -758,10 +759,7 @@ pub(crate) fn string_dot_format_extra_named_arguments(
return;
}
let names: Vec<String> = missing
.iter()
.map(|(_, name)| (*name).to_string())
.collect();
let names: Vec<Name> = missing.iter().map(|(_, name)| (*name).clone()).collect();
let mut diagnostic = Diagnostic::new(
StringDotFormatExtraNamedArguments { missing: names },
call.range(),
@ -865,7 +863,7 @@ pub(crate) fn string_dot_format_missing_argument(
.iter()
.filter_map(|k| {
let Keyword { arg, .. } = &k;
arg.as_ref().map(Identifier::as_str)
arg.as_ref().map(ruff_python_ast::Identifier::id)
})
.collect();
@ -879,8 +877,8 @@ pub(crate) fn string_dot_format_missing_argument(
summary
.keywords
.iter()
.filter(|k| !keywords.contains(k.as_str()))
.cloned(),
.filter(|k| !keywords.contains(*k))
.map(ToString::to_string),
)
.collect();

View file

@ -1,6 +1,7 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::any_over_body;
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr, StmtFor};
use ruff_python_semantic::analyze::typing::is_set;
use ruff_text_size::Ranged;
@ -41,7 +42,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `set`](https://docs.python.org/3/library/stdtypes.html#set)
#[violation]
pub struct ModifiedIteratingSet {
name: String,
name: Name,
}
impl AlwaysFixableViolation for ModifiedIteratingSet {

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, DiagnosticKind, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_trivia::indentation_at_offset;
use ruff_text_size::{Ranged, TextRange};
@ -101,7 +102,7 @@ fn get_undecorated_methods(checker: &mut Checker, class_stmt: &Stmt, method_type
return;
};
let mut explicit_decorator_calls: HashMap<String, &Stmt> = HashMap::default();
let mut explicit_decorator_calls: HashMap<Name, &Stmt> = HashMap::default();
let (method_name, diagnostic_type): (&str, DiagnosticKind) = match method_type {
MethodType::Classmethod => ("classmethod", NoClassmethodDecorator.into()),
@ -152,7 +153,7 @@ fn get_undecorated_methods(checker: &mut Checker, class_stmt: &Stmt, method_type
..
}) = stmt
{
let Some(decorator_call_statement) = explicit_decorator_calls.get(name.as_str()) else {
let Some(decorator_call_statement) = explicit_decorator_calls.get(name.id()) else {
continue;
};

View file

@ -2,6 +2,7 @@ use ruff_python_ast::{self as ast, Expr};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
@ -42,14 +43,14 @@ impl Violation for RedeclaredAssignedName {
/// PLW0128
pub(crate) fn redeclared_assigned_name(checker: &mut Checker, targets: &Vec<Expr>) {
let mut names: Vec<String> = Vec::new();
let mut names: Vec<Name> = Vec::new();
for target in targets {
check_expr(checker, target, &mut names);
}
}
fn check_expr(checker: &mut Checker, expr: &Expr, names: &mut Vec<String>) {
fn check_expr(checker: &mut Checker, expr: &Expr, names: &mut Vec<Name>) {
match expr {
Expr::Tuple(ast::ExprTuple { elts, .. }) => {
for target in elts {
@ -69,7 +70,7 @@ fn check_expr(checker: &mut Checker, expr: &Expr, names: &mut Vec<String>) {
expr.range(),
));
}
names.push(id.to_string());
names.push(id.clone());
}
_ => {}
}

View file

@ -3,6 +3,7 @@ use log::debug;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::is_dunder;
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Identifier, Keyword, Stmt};
use ruff_python_codegen::Generator;
use ruff_python_semantic::SemanticModel;
@ -148,11 +149,11 @@ fn match_named_tuple_assign<'a>(
}
/// Generate a [`Stmt::AnnAssign`] representing the provided field definition.
fn create_field_assignment_stmt(field: &str, annotation: &Expr) -> Stmt {
fn create_field_assignment_stmt(field: Name, annotation: &Expr) -> Stmt {
ast::StmtAnnAssign {
target: Box::new(
ast::ExprName {
id: field.into(),
id: field,
ctx: ExprContext::Load,
range: TextRange::default(),
}
@ -191,7 +192,10 @@ fn create_fields_from_fields_arg(fields: &Expr) -> Option<Vec<Stmt>> {
if is_dunder(field.to_str()) {
return None;
}
Some(create_field_assignment_stmt(field.to_str(), annotation))
Some(create_field_assignment_stmt(
Name::new(field.to_str()),
annotation,
))
})
.collect()
}
@ -205,7 +209,7 @@ fn create_fields_from_keywords(keywords: &[Keyword]) -> Option<Vec<Stmt>> {
keyword
.arg
.as_ref()
.map(|field| create_field_assignment_stmt(field.as_str(), &keyword.value))
.map(|field| create_field_assignment_stmt(field.id.clone(), &keyword.value))
})
.collect()
}

View file

@ -4,7 +4,7 @@ use ruff_text_size::{Ranged, TextRange};
use crate::fix::edits::pad;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::UnqualifiedName;
use ruff_python_ast::name::{Name, UnqualifiedName};
use ruff_python_semantic::SemanticModel;
use crate::checkers::ast::Checker;
@ -116,7 +116,7 @@ fn tuple_diagnostic(checker: &mut Checker, tuple: &ast::ExprTuple, aliases: &[&E
.all(|elt| !semantic.match_builtin_expr(elt, "OSError"))
{
let node = ast::ExprName {
id: "OSError".into(),
id: Name::new_static("OSError"),
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -4,7 +4,7 @@ use ruff_text_size::{Ranged, TextRange};
use crate::fix::edits::pad;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::UnqualifiedName;
use ruff_python_ast::name::{Name, UnqualifiedName};
use ruff_python_semantic::SemanticModel;
use crate::checkers::ast::Checker;
@ -128,7 +128,7 @@ fn tuple_diagnostic(checker: &mut Checker, tuple: &ast::ExprTuple, aliases: &[&E
.all(|elt| !semantic.match_builtin_expr(elt, "TimeoutError"))
{
let node = ast::ExprName {
id: "TimeoutError".into(),
id: Name::new_static("TimeoutError"),
ctx: ExprContext::Load,
range: TextRange::default(),
};

View file

@ -2,6 +2,7 @@ use itertools::Itertools;
use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::{
self as ast,
visitor::{self, Visitor},
@ -104,7 +105,7 @@ pub(crate) fn non_pep695_type_alias_type(checker: &mut Checker, stmt: &StmtAssig
return;
};
if name.value.to_str() != target_name.id {
if &name.value != target_name.id.as_str() {
return;
}
@ -143,7 +144,7 @@ pub(crate) fn non_pep695_type_alias_type(checker: &mut Checker, stmt: &StmtAssig
checker.diagnostics.push(create_diagnostic(
checker.generator(),
stmt.range(),
&target_name.id,
target_name.id.clone(),
value,
&vars,
Applicability::Safe,
@ -199,7 +200,7 @@ pub(crate) fn non_pep695_type_alias(checker: &mut Checker, stmt: &StmtAnnAssign)
checker.diagnostics.push(create_diagnostic(
checker.generator(),
stmt.range(),
name,
name.clone(),
value,
&vars,
// The fix is only safe in a type stub because new-style aliases have different runtime behavior
@ -217,7 +218,7 @@ pub(crate) fn non_pep695_type_alias(checker: &mut Checker, stmt: &StmtAnnAssign)
fn create_diagnostic(
generator: Generator,
stmt_range: TextRange,
name: &str,
name: Name,
value: &Expr,
vars: &[TypeVar],
applicability: Applicability,
@ -270,7 +271,7 @@ fn create_diagnostic(
range: TextRange::default(),
name: Box::new(Expr::Name(ExprName {
range: TextRange::default(),
id: name.to_string(),
id: name,
ctx: ast::ExprContext::Load,
})),
type_params,

View file

@ -1,13 +1,14 @@
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr};
use ruff_python_codegen::Generator;
use ruff_python_semantic::{BindingId, ResolvedReference, SemanticModel};
use ruff_text_size::{Ranged, TextRange};
/// Format a code snippet to call `name.method()`.
pub(super) fn generate_method_call(name: &str, method: &str, generator: Generator) -> String {
pub(super) fn generate_method_call(name: Name, method: &str, generator: Generator) -> String {
// Construct `name`.
let var = ast::ExprName {
id: name.to_string(),
id: name,
ctx: ast::ExprContext::Load,
range: TextRange::default(),
};
@ -38,13 +39,13 @@ pub(super) fn generate_method_call(name: &str, method: &str, generator: Generato
/// Format a code snippet comparing `name` to `None` (e.g., `name is None`).
pub(super) fn generate_none_identity_comparison(
name: &str,
name: Name,
negate: bool,
generator: Generator,
) -> String {
// Construct `name`.
let var = ast::ExprName {
id: name.to_string(),
id: name,
ctx: ast::ExprContext::Load,
range: TextRange::default(),
};
@ -77,12 +78,12 @@ pub(super) enum OpenMode {
}
impl OpenMode {
pub(super) fn pathlib_method(self) -> String {
pub(super) fn pathlib_method(self) -> Name {
match self {
OpenMode::ReadText => "read_text".to_string(),
OpenMode::ReadBytes => "read_bytes".to_string(),
OpenMode::WriteText => "write_text".to_string(),
OpenMode::WriteBytes => "write_bytes".to_string(),
OpenMode::ReadText => Name::new_static("read_text"),
OpenMode::ReadBytes => Name::new_static("read_bytes"),
OpenMode::WriteText => Name::new_static("write_text"),
OpenMode::WriteBytes => Name::new_static("write_bytes"),
}
}
}

View file

@ -70,7 +70,7 @@ pub(crate) fn delete_full_slice(checker: &mut Checker, delete: &ast::StmtDelete)
// Fix is only supported for single-target deletions.
if delete.targets.len() == 1 {
let replacement = generate_method_call(&name.id, "clear", checker.generator());
let replacement = generate_method_call(name.id.clone(), "clear", checker.generator());
diagnostic.set_fix(Fix::unsafe_edit(Edit::replacement(
replacement,
delete.start(),

View file

@ -66,7 +66,7 @@ pub(crate) fn isinstance_type_none(checker: &mut Checker, call: &ast::ExprCall)
};
let mut diagnostic = Diagnostic::new(IsinstanceTypeNone, call.range());
let replacement =
generate_none_identity_comparison(object_name, false, checker.generator());
generate_none_identity_comparison(object_name.clone(), false, checker.generator());
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
pad(replacement, call.range(), checker.locator()),
call.range(),

View file

@ -3,6 +3,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::helpers::any_over_expr;
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr};
use ruff_text_size::{Ranged, TextRange};
@ -165,7 +166,12 @@ pub(crate) fn reimplemented_starmap(checker: &mut Checker, target: &StarmapCandi
// - For list and set comprehensions, we'd want to wrap it with `list` and `set`
// correspondingly.
let main_edit = Edit::range_replacement(
target.try_make_suggestion(starmap_name, &comprehension.iter, func, checker)?,
target.try_make_suggestion(
Name::from(starmap_name),
&comprehension.iter,
func,
checker,
)?,
target.range(),
);
Ok(Fix::safe_edits(import_edit, [main_edit]))
@ -231,7 +237,7 @@ impl StarmapCandidate<'_> {
/// Try to produce a fix suggestion transforming this node into a call to `starmap`.
pub(crate) fn try_make_suggestion(
&self,
name: String,
name: Name,
iter: &Expr,
func: &Expr,
checker: &Checker,
@ -260,7 +266,7 @@ impl StarmapCandidate<'_> {
// ```python
// list(itertools.starmap(foo, iter))
// ```
try_construct_call(name, iter, func, "list", checker)
try_construct_call(name, iter, func, Name::new_static("list"), checker)
}
Self::SetComp(_) => {
// For set comprehensions, we replace:
@ -272,7 +278,7 @@ impl StarmapCandidate<'_> {
// ```python
// set(itertools.starmap(foo, iter))
// ```
try_construct_call(name, iter, func, "set", checker)
try_construct_call(name, iter, func, Name::new_static("set"), checker)
}
}
}
@ -280,15 +286,15 @@ impl StarmapCandidate<'_> {
/// Try constructing the call to `itertools.starmap` and wrapping it with the given builtin.
fn try_construct_call(
name: String,
name: Name,
iter: &Expr,
func: &Expr,
builtin: &str,
builtin: Name,
checker: &Checker,
) -> Result<String> {
// We can only do our fix if `builtin` identifier is still bound to
// the built-in type.
if !checker.semantic().has_builtin_binding(builtin) {
if !checker.semantic().has_builtin_binding(&builtin) {
bail!("Can't use built-in `{builtin}` constructor")
}
@ -308,7 +314,7 @@ fn try_construct_call(
}
/// Construct the call to `itertools.starmap` for suggestion.
fn construct_starmap_call(starmap_binding: String, iter: &Expr, func: &Expr) -> ast::ExprCall {
fn construct_starmap_call(starmap_binding: Name, iter: &Expr, func: &Expr) -> ast::ExprCall {
let starmap = ast::ExprName {
id: starmap_binding,
ctx: ast::ExprContext::Load,
@ -326,9 +332,9 @@ fn construct_starmap_call(starmap_binding: String, iter: &Expr, func: &Expr) ->
}
/// Wrap given function call with yet another call.
fn wrap_with_call_to(call: ast::ExprCall, func_name: &str) -> ast::ExprCall {
fn wrap_with_call_to(call: ast::ExprCall, func_name: Name) -> ast::ExprCall {
let name = ast::ExprName {
id: func_name.to_string(),
id: func_name,
ctx: ast::ExprContext::Load,
range: TextRange::default(),
};

View file

@ -86,7 +86,7 @@ pub(crate) fn repeated_global(checker: &mut Checker, mut suite: &[Stmt]) {
Stmt::Nonlocal(stmt) => &stmt.names,
_ => unreachable!(),
})
.map(|identifier| &identifier.id)
.map(ruff_python_ast::Identifier::id)
.format(", ")
),
range,

View file

@ -1,5 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr};
use ruff_python_semantic::analyze::typing::is_list;
use ruff_python_semantic::{Binding, SemanticModel};
@ -61,7 +62,7 @@ pub(crate) fn slice_copy(checker: &mut Checker, subscript: &ast::ExprSubscript)
return;
};
let mut diagnostic = Diagnostic::new(SliceCopy, subscript.range());
let replacement = generate_method_call(name, "copy", checker.generator());
let replacement = generate_method_call(name.clone(), "copy", checker.generator());
diagnostic.set_fix(Fix::safe_edit(Edit::replacement(
replacement,
subscript.start(),
@ -74,7 +75,7 @@ pub(crate) fn slice_copy(checker: &mut Checker, subscript: &ast::ExprSubscript)
fn match_list_full_slice<'a>(
subscript: &'a ast::ExprSubscript,
semantic: &SemanticModel,
) -> Option<&'a str> {
) -> Option<&'a Name> {
// Check that it is `obj[:]`.
if !matches!(
subscript.slice.as_ref(),

View file

@ -1,5 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, CmpOp, Expr};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;
@ -33,7 +34,7 @@ use crate::rules::refurb::helpers::generate_none_identity_comparison;
/// - [Python documentation: Identity comparisons](https://docs.python.org/3/reference/expressions.html#is-not)
#[violation]
pub struct TypeNoneComparison {
object: String,
object: Name,
comparison: Comparison,
}
@ -94,14 +95,14 @@ pub(crate) fn type_none_comparison(checker: &mut Checker, compare: &ast::ExprCom
// Get the name of the other object (or `None` if both were `None`).
let other_arg_name = match other_arg {
Expr::Name(ast::ExprName { id, .. }) => id.as_str(),
Expr::NoneLiteral { .. } => "None",
Expr::Name(ast::ExprName { id, .. }) => id.clone(),
Expr::NoneLiteral { .. } => Name::new_static("None"),
_ => return,
};
let mut diagnostic = Diagnostic::new(
TypeNoneComparison {
object: other_arg_name.to_string(),
object: other_arg_name.clone(),
comparison,
},
compare.range(),

View file

@ -3,6 +3,7 @@ use std::fmt;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast as ast;
use ruff_python_ast::name::Name;
use ruff_python_ast::{Arguments, Expr, Int};
use ruff_python_codegen::Generator;
use ruff_python_semantic::analyze::typing::{is_dict, is_list, is_set, is_tuple};
@ -189,7 +190,7 @@ pub(crate) fn unnecessary_enumerate(checker: &mut Checker, stmt_for: &ast::StmtF
)
}) {
let replace_iter = Edit::range_replacement(
generate_range_len_call(&sequence.id, checker.generator()),
generate_range_len_call(sequence.id.clone(), checker.generator()),
stmt_for.iter.range(),
);
@ -229,10 +230,10 @@ impl fmt::Display for EnumerateSubset {
/// Format a code snippet to call `range(len(name))`, where `name` is the given
/// sequence name.
fn generate_range_len_call(name: &str, generator: Generator) -> String {
fn generate_range_len_call(name: Name, generator: Generator) -> String {
// Construct `name`.
let var = ast::ExprName {
id: name.to_string(),
id: name,
ctx: ast::ExprContext::Load,
range: TextRange::default(),
};
@ -240,7 +241,7 @@ fn generate_range_len_call(name: &str, generator: Generator) -> String {
let len = ast::ExprCall {
func: Box::new(
ast::ExprName {
id: "len".to_string(),
id: Name::new_static("len"),
ctx: ast::ExprContext::Load,
range: TextRange::default(),
}
@ -257,7 +258,7 @@ fn generate_range_len_call(name: &str, generator: Generator) -> String {
let range = ast::ExprCall {
func: Box::new(
ast::ExprName {
id: "range".to_string(),
id: Name::new_static("range"),
ctx: ast::ExprContext::Load,
range: TextRange::default(),
}

View file

@ -5,6 +5,7 @@ use anyhow::Result;
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr, Operator, ParameterWithDefault, Parameters};
use ruff_python_parser::typing::parse_type_annotation;
use ruff_text_size::{Ranged, TextRange};
@ -145,7 +146,7 @@ fn generate_fix(checker: &Checker, conversion_type: ConversionType, expr: &Expr)
let new_expr = Expr::Subscript(ast::ExprSubscript {
range: TextRange::default(),
value: Box::new(Expr::Name(ast::ExprName {
id: binding,
id: Name::new(binding),
ctx: ast::ExprContext::Store,
range: TextRange::default(),
})),

View file

@ -1,5 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr};
use ruff_python_semantic::analyze::typing::is_mutable_expr;
@ -99,7 +100,7 @@ pub(crate) fn mutable_fromkeys_value(checker: &mut Checker, call: &ast::ExprCall
fn generate_dict_comprehension(keys: &Expr, value: &Expr, generator: Generator) -> String {
// Construct `key`.
let key = ast::ExprName {
id: "key".to_string(),
id: Name::new_static("key"),
ctx: ast::ExprContext::Load,
range: TextRange::default(),
};

View file

@ -13,6 +13,8 @@ license = { workspace = true }
[lib]
[dependencies]
ruff_cache = { workspace = true, optional = true }
ruff_macros = { workspace = true, optional = true }
ruff_python_trivia = { workspace = true }
ruff_source_file = { workspace = true }
ruff_text_size = { workspace = true }
@ -23,10 +25,16 @@ is-macro = { workspace = true }
itertools = { workspace = true }
once_cell = { workspace = true }
rustc-hash = { workspace = true }
schemars = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
compact_str = { workspace = true }
[features]
serde = ["dep:serde", "ruff_text_size/serde"]
serde = ["dep:serde", "ruff_text_size/serde", "dep:ruff_cache", "compact_str/serde", "dep:ruff_macros", "dep:schemars"]
[lints]
workspace = true
[package.metadata.cargo-shear]
# Used via `CacheKey` macro expansion.
ignored = ["ruff_cache"]

View file

@ -7,7 +7,7 @@ use ruff_python_trivia::{indentation_at_offset, CommentRanges, SimpleTokenKind,
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::name::{QualifiedName, QualifiedNameBuilder};
use crate::name::{Name, QualifiedName, QualifiedNameBuilder};
use crate::parenthesize::parenthesized_range;
use crate::statement_visitor::StatementVisitor;
use crate::visitor::Visitor;
@ -1403,7 +1403,7 @@ pub fn pep_604_union(elts: &[Expr]) -> Expr {
}
/// Format the expression as a `typing.Optional`-style optional.
pub fn typing_optional(elt: Expr, binding: String) -> Expr {
pub fn typing_optional(elt: Expr, binding: Name) -> Expr {
Expr::Subscript(ast::ExprSubscript {
value: Box::new(Expr::Name(ast::ExprName {
id: binding,
@ -1417,8 +1417,8 @@ pub fn typing_optional(elt: Expr, binding: String) -> Expr {
}
/// Format the expressions as a `typing.Union`-style union.
pub fn typing_union(elts: &[Expr], binding: String) -> Expr {
fn tuple(elts: &[Expr], binding: String) -> Expr {
pub fn typing_union(elts: &[Expr], binding: Name) -> Expr {
fn tuple(elts: &[Expr], binding: Name) -> Expr {
match elts {
[] => Expr::Tuple(ast::ExprTuple {
elts: vec![],

View file

@ -1,9 +1,213 @@
use std::borrow::{Borrow, Cow};
use std::fmt::{Debug, Display, Formatter, Write};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use crate::{nodes, Expr};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, ruff_macros::CacheKey)
)]
pub struct Name(compact_str::CompactString);
impl Name {
#[inline]
pub fn empty() -> Self {
Self(compact_str::CompactString::default())
}
#[inline]
pub fn new(name: impl AsRef<str>) -> Self {
Self(compact_str::CompactString::new(name))
}
#[inline]
pub fn new_static(name: &'static str) -> Self {
// TODO(Micha): Use CompactString::const_new once we upgrade to 0.8 https://github.com/ParkMyCar/compact_str/pull/336
Self(compact_str::CompactString::from(name))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Debug for Name {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Name({:?})", self.as_str())
}
}
impl AsRef<str> for Name {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Deref for Name {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl Borrow<str> for Name {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<'a> From<&'a str> for Name {
#[inline]
fn from(s: &'a str) -> Self {
Name(s.into())
}
}
impl From<String> for Name {
#[inline]
fn from(s: String) -> Self {
Name(s.into())
}
}
impl<'a> From<&'a String> for Name {
#[inline]
fn from(s: &'a String) -> Self {
Name(s.into())
}
}
impl<'a> From<Cow<'a, str>> for Name {
#[inline]
fn from(cow: Cow<'a, str>) -> Self {
Name(cow.into())
}
}
impl From<Box<str>> for Name {
#[inline]
fn from(b: Box<str>) -> Self {
Name(b.into())
}
}
impl From<compact_str::CompactString> for Name {
#[inline]
fn from(value: compact_str::CompactString) -> Self {
Self(value)
}
}
impl From<Name> for compact_str::CompactString {
#[inline]
fn from(name: Name) -> Self {
name.0
}
}
impl FromIterator<char> for Name {
fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl std::fmt::Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl PartialEq<str> for Name {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<Name> for str {
#[inline]
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl PartialEq<&str> for Name {
#[inline]
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<Name> for &str {
#[inline]
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl PartialEq<String> for Name {
fn eq(&self, other: &String) -> bool {
self == other.as_str()
}
}
impl PartialEq<Name> for String {
#[inline]
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl PartialEq<&String> for Name {
#[inline]
fn eq(&self, other: &&String) -> bool {
self.as_str() == *other
}
}
impl PartialEq<Name> for &String {
#[inline]
fn eq(&self, other: &Name) -> bool {
other == self
}
}
#[cfg(feature = "serde")]
impl schemars::JsonSchema for Name {
fn is_referenceable() -> bool {
String::is_referenceable()
}
fn schema_name() -> String {
String::schema_name()
}
fn schema_id() -> std::borrow::Cow<'static, str> {
String::schema_id()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(gen)
}
fn _schemars_private_non_optional_json_schema(
gen: &mut schemars::gen::SchemaGenerator,
) -> schemars::schema::Schema {
String::_schemars_private_non_optional_json_schema(gen)
}
fn _schemars_private_is_option() -> bool {
String::_schemars_private_is_option()
}
}
/// A representation of a qualified name, like `typing.List`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QualifiedName<'a>(SegmentsVec<'a>);

View file

@ -12,6 +12,7 @@ use itertools::Itertools;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::name::Name;
use crate::{
int,
str::Quote,
@ -1762,12 +1763,6 @@ impl PartialEq<str> for StringLiteralValue {
}
}
impl PartialEq<String> for StringLiteralValue {
fn eq(&self, other: &String) -> bool {
self == other.as_str()
}
}
impl fmt::Display for StringLiteralValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.to_str())
@ -2740,10 +2735,16 @@ impl From<ExprStarred> for Expr {
#[derive(Clone, Debug, PartialEq)]
pub struct ExprName {
pub range: TextRange,
pub id: String,
pub id: Name,
pub ctx: ExprContext,
}
impl ExprName {
pub fn id(&self) -> &Name {
&self.id
}
}
impl From<ExprName> for Expr {
fn from(payload: ExprName) -> Self {
Expr::Name(payload)
@ -3763,19 +3764,23 @@ impl IpyEscapeKind {
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Identifier {
pub id: String,
pub id: Name,
pub range: TextRange,
}
impl Identifier {
#[inline]
pub fn new(id: impl Into<String>, range: TextRange) -> Self {
pub fn new(id: impl Into<Name>, range: TextRange) -> Self {
Self {
id: id.into(),
range,
}
}
pub fn id(&self) -> &Name {
&self.id
}
pub fn is_valid(&self) -> bool {
!self.id.is_empty()
}
@ -3798,7 +3803,7 @@ impl PartialEq<str> for Identifier {
impl PartialEq<String> for Identifier {
#[inline]
fn eq(&self, other: &String) -> bool {
&self.id == other
self.id == other
}
}
@ -3817,22 +3822,15 @@ impl AsRef<str> for Identifier {
}
}
impl AsRef<String> for Identifier {
#[inline]
fn as_ref(&self) -> &String {
&self.id
}
}
impl std::fmt::Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.id, f)
}
}
impl From<Identifier> for String {
impl From<Identifier> for Name {
#[inline]
fn from(identifier: Identifier) -> String {
fn from(identifier: Identifier) -> Name {
identifier.id
}
}

View file

@ -19,6 +19,7 @@ ruff_text_size = { workspace = true }
bitflags = { workspace = true }
bstr = { workspace = true }
compact_str = { workspace = true }
memchr = { workspace = true }
rustc-hash = { workspace = true }
static_assertions = { workspace = true }

View file

@ -12,6 +12,7 @@ use std::str::FromStr;
use unicode_ident::{is_xid_continue, is_xid_start};
use unicode_normalization::UnicodeNormalization;
use ruff_python_ast::name::Name;
use ruff_python_ast::{Int, IpyEscapeKind, StringFlags};
use ruff_python_trivia::is_python_whitespace;
use ruff_text_size::{TextLen, TextRange, TextSize};
@ -643,7 +644,7 @@ impl<'src> Lexer<'src> {
let text = self.token_text();
if !is_ascii {
self.current_value = TokenValue::Name(text.nfkc().collect::<String>().into_boxed_str());
self.current_value = TokenValue::Name(text.nfkc().collect::<Name>());
return TokenKind::Name;
}
@ -687,7 +688,7 @@ impl<'src> Lexer<'src> {
"with" => TokenKind::With,
"yield" => TokenKind::Yield,
_ => {
self.current_value = TokenValue::Name(text.to_string().into_boxed_str());
self.current_value = TokenValue::Name(Name::new(text));
TokenKind::Name
}
}

View file

@ -4,6 +4,7 @@ use std::ops::Deref;
use bitflags::bitflags;
use rustc_hash::{FxBuildHasher, FxHashSet};
use ruff_python_ast::name::Name;
use ruff_python_ast::{
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, FStringElements,
IpyEscapeKind, Number, Operator, UnaryOp,
@ -477,14 +478,11 @@ impl<'src> Parser<'src> {
let TokenValue::Name(name) = self.bump_value(TokenKind::Name) else {
unreachable!();
};
return ast::Identifier {
id: name.into_string(),
range,
};
return ast::Identifier { id: name, range };
}
if self.current_token_kind().is_soft_keyword() {
let id = self.src_text(range).to_string();
let id = Name::new(self.src_text(range));
self.bump_soft_keyword_as_name();
return ast::Identifier { id, range };
}
@ -499,7 +497,7 @@ impl<'src> Parser<'src> {
range,
);
let id = self.src_text(range).to_string();
let id = Name::new(self.src_text(range));
self.bump_any();
ast::Identifier { id, range }
} else {
@ -509,7 +507,7 @@ impl<'src> Parser<'src> {
);
ast::Identifier {
id: String::new(),
id: Name::empty(),
range: self.missing_node_range(),
}
}
@ -597,7 +595,7 @@ impl<'src> Parser<'src> {
);
Expr::Name(ast::ExprName {
range: self.missing_node_range(),
id: String::new(),
id: Name::empty(),
ctx: ExprContext::Invalid,
})
}
@ -719,7 +717,7 @@ impl<'src> Parser<'src> {
&parsed_expr,
);
ast::Identifier {
id: String::new(),
id: Name::empty(),
range: parsed_expr.range(),
}
};
@ -793,7 +791,7 @@ impl<'src> Parser<'src> {
value: Box::new(value),
slice: Box::new(Expr::Name(ast::ExprName {
range: slice_range,
id: String::new(),
id: Name::empty(),
ctx: ExprContext::Invalid,
})),
ctx: ExprContext::Load,

View file

@ -1,3 +1,4 @@
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr, ExprContext, Number, Operator, Pattern, Singleton};
use ruff_text_size::{Ranged, TextSize};
@ -510,7 +511,7 @@ impl<'src> Parser<'src> {
);
let invalid_node = Expr::Name(ast::ExprName {
range: self.missing_node_range(),
id: String::new(),
id: Name::empty(),
ctx: ExprContext::Invalid,
});
Pattern::MatchValue(ast::PatternMatchValue {
@ -616,7 +617,7 @@ impl<'src> Parser<'src> {
} else {
Box::new(Expr::Name(ast::ExprName {
range: ident.range(),
id: String::new(),
id: Name::empty(),
ctx: ExprContext::Invalid,
}))
}
@ -667,7 +668,7 @@ impl<'src> Parser<'src> {
&pattern,
);
ast::Identifier {
id: String::new(),
id: Name::empty(),
range: parser.missing_node_range(),
}
};

View file

@ -1,3 +1,4 @@
use ruff_python_ast::name::Name;
use ruff_python_ast::{self as ast, Expr, ExprContext, Pattern};
use ruff_text_size::{Ranged, TextLen, TextRange};
@ -110,7 +111,7 @@ pub(super) fn pattern_to_expr(pattern: Pattern) -> Expr {
range,
value: Box::new(Expr::Name(ast::ExprName {
range: TextRange::new(range.end() - "_".text_len(), range.end()),
id: "_".to_string(),
id: Name::new_static("_"),
ctx: ExprContext::Store,
})),
ctx: ExprContext::Store,
@ -124,7 +125,7 @@ pub(super) fn pattern_to_expr(pattern: Pattern) -> Expr {
}) => match (pattern, name) {
(Some(_), Some(_)) => Expr::Name(ast::ExprName {
range,
id: String::new(),
id: Name::empty(),
ctx: ExprContext::Invalid,
}),
(Some(pattern), None) => pattern_to_expr(*pattern),
@ -135,7 +136,7 @@ pub(super) fn pattern_to_expr(pattern: Pattern) -> Expr {
}),
(None, None) => Expr::Name(ast::ExprName {
range,
id: "_".to_string(),
id: Name::new_static("_"),
ctx: ExprContext::Store,
}),
},

View file

@ -1,11 +1,11 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: expr
expression: parsed.expr()
---
Name(
ExprName {
range: 0..5,
id: "first",
id: Name("first"),
ctx: Load,
},
)

View file

@ -1,6 +1,6 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: parse_ast
expression: parsed.syntax()
---
Module(
ModModule {
@ -15,7 +15,7 @@ Module(
left: Name(
ExprName {
range: 27..28,
id: "a",
id: Name("a"),
ctx: Load,
},
),
@ -23,7 +23,7 @@ Module(
right: Name(
ExprName {
range: 39..40,
id: "b",
id: Name("b"),
ctx: Load,
},
),
@ -128,7 +128,7 @@ Module(
is_async: false,
decorator_list: [],
name: Identifier {
id: "foo",
id: Name("foo"),
range: 570..573,
},
type_params: None,
@ -152,7 +152,7 @@ Module(
left: Name(
ExprName {
range: 598..599,
id: "a",
id: Name("a"),
ctx: Load,
},
),
@ -163,7 +163,7 @@ Module(
Name(
ExprName {
range: 619..620,
id: "b",
id: Name("b"),
ctx: Load,
},
),
@ -204,7 +204,7 @@ Module(
target: Name(
ExprName {
range: 715..716,
id: "a",
id: Name("a"),
ctx: Store,
},
),
@ -214,7 +214,7 @@ Module(
func: Name(
ExprName {
range: 720..725,
id: "range",
id: Name("range"),
ctx: Load,
},
),
@ -253,7 +253,7 @@ Module(
Name(
ExprName {
range: 739..741,
id: "p1",
id: Name("p1"),
ctx: Store,
},
),
@ -273,14 +273,14 @@ Module(
target: Name(
ExprName {
range: 749..751,
id: "p2",
id: Name("p2"),
ctx: Store,
},
),
annotation: Name(
ExprName {
range: 753..756,
id: "str",
id: Name("str"),
ctx: Load,
},
),
@ -303,7 +303,7 @@ Module(
Name(
ExprName {
range: 764..767,
id: "foo",
id: Name("foo"),
ctx: Store,
},
),
@ -331,7 +331,7 @@ Module(
Name(
ExprName {
range: 792..795,
id: "foo",
id: Name("foo"),
ctx: Store,
},
),

View file

@ -1,6 +1,6 @@
---
source: crates/ruff_python_parser/src/parser/tests.rs
expression: parse_ast
expression: suite
---
[
Assign(
@ -10,7 +10,7 @@ expression: parse_ast
Name(
ExprName {
range: 0..1,
id: "x",
id: Name("x"),
ctx: Store,
},
),

View file

@ -1,7 +1,9 @@
use compact_str::CompactString;
use std::fmt::Display;
use rustc_hash::{FxBuildHasher, FxHashSet};
use ruff_python_ast::name::Name;
use ruff_python_ast::{
self as ast, ExceptHandler, Expr, ExprContext, IpyEscapeKind, Operator, Stmt, WithItem,
};
@ -623,7 +625,7 @@ impl<'src> Parser<'src> {
let range = self.node_range(start);
return ast::Alias {
name: ast::Identifier {
id: "*".into(),
id: Name::new_static("*"),
range,
},
asname: None,
@ -669,7 +671,7 @@ impl<'src> Parser<'src> {
fn parse_dotted_name(&mut self) -> ast::Identifier {
let start = self.node_start();
let mut dotted_name = self.parse_identifier().id;
let mut dotted_name: CompactString = self.parse_identifier().id.into();
let mut progress = ParserProgress::default();
while self.eat(TokenKind::Dot) {
@ -686,7 +688,7 @@ impl<'src> Parser<'src> {
// import a.b.c
// import a . b . c
ast::Identifier {
id: dotted_name,
id: Name::from(dotted_name),
range: self.node_range(start),
}
}

View file

@ -7,7 +7,7 @@ expression: lex_source(source)
[
(
Name(
"a_variable",
Name("a_variable"),
),
0..10,
),

View file

@ -7,7 +7,7 @@ expression: lex_source(source)
[
(
Name(
"x",
Name("x"),
),
3..4,
),

View file

@ -7,7 +7,7 @@ expression: "lex_source_with_offset(source, TextSize::new(7))"
[
(
Name(
"y",
Name("y"),
),
7..8,
),
@ -17,7 +17,7 @@ expression: "lex_source_with_offset(source, TextSize::new(7))"
),
(
Name(
"z",
Name("z"),
),
11..12,
),

View file

@ -7,7 +7,7 @@ expression: "lex_source_with_offset(source, TextSize::new(11))"
[
(
Name(
"z",
Name("z"),
),
11..12,
),

View file

@ -11,7 +11,7 @@ expression: lex_source(source)
),
(
Name(
"first",
Name("first"),
),
3..8,
),
@ -33,7 +33,7 @@ expression: lex_source(source)
),
(
Name(
"second",
Name("second"),
),
17..23,
),
@ -63,7 +63,7 @@ expression: lex_source(source)
),
(
Name(
"foo",
Name("foo"),
),
42..45,
),

View file

@ -11,7 +11,7 @@ expression: double_dedent_with_eol(MAC_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -41,7 +41,7 @@ expression: double_dedent_with_eol(MAC_EOL)
),
(
Name(
"x",
Name("x"),
),
15..16,
),

View file

@ -11,7 +11,7 @@ expression: double_dedent_with_tabs_eol(MAC_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -41,7 +41,7 @@ expression: double_dedent_with_tabs_eol(MAC_EOL)
),
(
Name(
"x",
Name("x"),
),
15..16,
),

View file

@ -11,7 +11,7 @@ expression: double_dedent_with_tabs_eol(UNIX_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -41,7 +41,7 @@ expression: double_dedent_with_tabs_eol(UNIX_EOL)
),
(
Name(
"x",
Name("x"),
),
15..16,
),

View file

@ -11,7 +11,7 @@ expression: double_dedent_with_tabs_eol(WINDOWS_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -41,7 +41,7 @@ expression: double_dedent_with_tabs_eol(WINDOWS_EOL)
),
(
Name(
"x",
Name("x"),
),
16..17,
),

View file

@ -11,7 +11,7 @@ expression: double_dedent_with_eol(UNIX_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -41,7 +41,7 @@ expression: double_dedent_with_eol(UNIX_EOL)
),
(
Name(
"x",
Name("x"),
),
15..16,
),

View file

@ -11,7 +11,7 @@ expression: double_dedent_with_eol(WINDOWS_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -41,7 +41,7 @@ expression: double_dedent_with_eol(WINDOWS_EOL)
),
(
Name(
"x",
Name("x"),
),
16..17,
),

View file

@ -27,7 +27,7 @@ expression: lex_source(source)
),
(
Name(
"foo",
Name("foo"),
),
10..13,
),
@ -50,7 +50,7 @@ expression: lex_source(source)
),
(
Name(
"bar",
Name("bar"),
),
28..31,
),
@ -73,7 +73,7 @@ expression: lex_source(source)
),
(
Name(
"three",
Name("three"),
),
36..41,
),

View file

@ -35,7 +35,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
39..40,
),

View file

@ -18,7 +18,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
3..4,
),
@ -28,7 +28,7 @@ expression: lex_source(source)
),
(
Name(
"s",
Name("s"),
),
5..6,
),
@ -51,7 +51,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
9..10,
),
@ -65,7 +65,7 @@ expression: lex_source(source)
),
(
Name(
"r",
Name("r"),
),
12..13,
),
@ -88,7 +88,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
16..17,
),

View file

@ -27,7 +27,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
4..5,
),
@ -50,7 +50,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
10..11,
),

View file

@ -27,7 +27,7 @@ expression: lex_source(source)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),
@ -64,7 +64,7 @@ expression: lex_source(source)
),
(
Name(
"foo",
Name("foo"),
),
15..18,
),

View file

@ -27,7 +27,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
5..6,
),
@ -50,7 +50,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
11..12,
),

View file

@ -31,7 +31,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
14..15,
),
@ -49,7 +49,7 @@ expression: lex_source(source)
),
(
Name(
"y",
Name("y"),
),
38..39,
),

View file

@ -93,7 +93,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
81..82,
),

View file

@ -27,7 +27,7 @@ expression: lex_source(source)
),
(
Name(
"BULLET",
Name("BULLET"),
),
6..12,
),

View file

@ -47,7 +47,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
14..15,
),
@ -68,7 +68,7 @@ expression: lex_source(source)
),
(
Name(
"wow",
Name("wow"),
),
21..24,
),

View file

@ -18,7 +18,7 @@ expression: lex_source(source)
),
(
Name(
"foo",
Name("foo"),
),
3..6,
),
@ -45,7 +45,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
10..11,
),
@ -59,7 +59,7 @@ expression: lex_source(source)
),
(
Name(
"s",
Name("s"),
),
13..14,
),
@ -95,7 +95,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
21..22,
),
@ -118,7 +118,7 @@ expression: lex_source(source)
),
(
Name(
"y",
Name("y"),
),
25..26,
),
@ -222,7 +222,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
46..47,
),
@ -254,7 +254,7 @@ expression: lex_source(source)
),
(
Name(
"pop",
Name("pop"),
),
53..56,
),

View file

@ -31,7 +31,7 @@ expression: lex_source(source)
),
(
Name(
"pwd",
Name("pwd"),
),
8..11,
),

View file

@ -22,7 +22,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
10..11,
),
@ -36,7 +36,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
13..14,
),
@ -80,7 +80,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
29..30,
),
@ -94,7 +94,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
32..33,
),

View file

@ -31,7 +31,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
12..13,
),
@ -98,7 +98,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
35..36,
),
@ -165,7 +165,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
78..79,
),
@ -236,7 +236,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
97..98,
),
@ -259,7 +259,7 @@ expression: lex_source(source)
),
(
Name(
"b",
Name("b"),
),
109..110,
),

View file

@ -18,7 +18,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
3..4,
),
@ -58,7 +58,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
12..13,
),
@ -95,7 +95,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
21..22,
),
@ -109,7 +109,7 @@ expression: lex_source(source)
),
(
Name(
"y",
Name("y"),
),
24..25,
),
@ -150,7 +150,7 @@ expression: lex_source(source)
),
(
Name(
"x",
Name("x"),
),
34..35,
),

View file

@ -11,7 +11,7 @@ expression: indentation_with_eol(MAC_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),

View file

@ -11,7 +11,7 @@ expression: indentation_with_eol(UNIX_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),

View file

@ -11,7 +11,7 @@ expression: indentation_with_eol(WINDOWS_EOL)
),
(
Name(
"foo",
Name("foo"),
),
4..7,
),

View file

@ -7,7 +7,7 @@ expression: lex_jupyter_source(source)
[
(
Name(
"pwd",
Name("pwd"),
),
0..3,
),
@ -28,7 +28,7 @@ expression: lex_jupyter_source(source)
),
(
Name(
"foo",
Name("foo"),
),
11..14,
),
@ -49,7 +49,7 @@ expression: lex_jupyter_source(source)
),
(
Name(
"bar",
Name("bar"),
),
31..34,
),
@ -70,7 +70,7 @@ expression: lex_jupyter_source(source)
),
(
Name(
"baz",
Name("baz"),
),
51..54,
),

View file

@ -11,7 +11,7 @@ expression: lex_jupyter_source(source)
),
(
Name(
"foo",
Name("foo"),
),
6..9,
),
@ -33,7 +33,7 @@ expression: lex_jupyter_source(source)
),
(
Name(
"bar",
Name("bar"),
),
20..23,
),

View file

@ -7,7 +7,7 @@ expression: newline_in_brackets_eol(MAC_EOL)
[
(
Name(
"x",
Name("x"),
),
0..1,
),

View file

@ -7,7 +7,7 @@ expression: newline_in_brackets_eol(UNIX_EOL)
[
(
Name(
"x",
Name("x"),
),
0..1,
),

View file

@ -7,7 +7,7 @@ expression: newline_in_brackets_eol(WINDOWS_EOL)
[
(
Name(
"x",
Name("x"),
),
0..1,
),

View file

@ -1,6 +1,6 @@
---
source: crates/ruff_python_parser/src/string.rs
expression: parse_ast
expression: suite
---
[
Assign(
@ -10,7 +10,7 @@ expression: parse_ast
Name(
ExprName {
range: 0..4,
id: "bold",
id: Name("bold"),
ctx: Store,
},
),

View file

@ -1,6 +1,6 @@
---
source: crates/ruff_python_parser/src/string.rs
expression: parse_ast
expression: suite
---
[
Expr(
@ -27,7 +27,7 @@ expression: parse_ast
expression: Name(
ExprName {
range: 6..9,
id: "bbb",
id: Name("bbb"),
ctx: Load,
},
),
@ -48,7 +48,7 @@ expression: parse_ast
expression: Name(
ExprName {
range: 14..17,
id: "ddd",
id: Name("ddd"),
ctx: Load,
},
),

View file

@ -1,6 +1,6 @@
---
source: crates/ruff_python_parser/src/string.rs
expression: parse_ast
expression: suite
---
[
Expr(
@ -27,7 +27,7 @@ expression: parse_ast
expression: Name(
ExprName {
range: 5..6,
id: "x",
id: Name("x"),
ctx: Load,
},
),

Some files were not shown because too many files have changed in this diff Show more