1use std::ops::Deref;
2
3use ruff_db::PythonFile;
4use ruff_db::files::{File, FileRange};
5use ruff_db::parsed::{ParsedModuleRef, parsed_module};
6use ruff_python_ast::find_node::covering_node;
7use ruff_python_ast::name::Name;
8use ruff_python_ast::traversal::suite;
9use ruff_python_ast::{self as ast, AnyNodeRef, Expr};
10use ruff_text_size::{Ranged, TextRange, TextSize};
11use smallvec::SmallVec;
12
13use crate::LoopHeaderId;
14use crate::ProgramFile;
15use crate::ast_node_ref::AstNodeRef;
16use crate::member::ScopedMemberId;
17use crate::node_key::NodeKey;
18use crate::place::ScopedPlaceId;
19use crate::predicate::PatternPredicate;
20use crate::scope::{FileScopeId, ScopeId};
21use crate::symbol::ScopedSymbolId;
22use crate::unpack::{Unpack, UnpackPosition};
23use crate::use_def::BindingWithConstraintsIterator;
24use crate::{Db, Program, SemanticIndex};
25
26#[salsa::tracked(
36 debug,
37 constructor = new_internal,
38 heap_size = ruff_memory_usage::heap_size
39)]
40#[derive(Ord, PartialOrd)]
41pub struct Definition<'db> {
42 #[returns(copy)]
47 pub scope_id: ScopeId<'db>,
48
49 #[returns(copy)]
51 place_info: DefinitionPlace,
52
53 #[no_eq]
56 #[returns(ref)]
57 #[tracked]
58 pub kind: DefinitionKind<'db>,
59}
60
61impl get_size2::GetSize for Definition<'_> {}
63
64impl<'db> Definition<'db> {
65 pub(crate) fn new(
66 db: &'db dyn Db,
67 scope_id: ScopeId<'db>,
68 place: ScopedPlaceId,
69 kind: DefinitionKind<'db>,
70 is_reexported: bool,
71 ) -> Self {
72 Self::new_internal(
73 db,
74 scope_id,
75 DefinitionPlace::new(place, is_reexported),
76 kind,
77 )
78 }
79
80 pub fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
81 self.scope_id(db)
82 }
83
84 pub fn file(self, db: &'db dyn Db) -> File {
85 self.scope_id(db).file(db)
86 }
87
88 pub fn python_file(self, db: &'db dyn Db) -> PythonFile<'db> {
89 self.scope_id(db).python_file(db)
90 }
91
92 pub fn program_file(self, db: &'db dyn Db) -> ProgramFile<'db> {
93 self.scope_id(db).program_file(db)
94 }
95
96 pub fn program(self, db: &'db dyn Db) -> Program<'db> {
97 self.scope_id(db).program(db)
98 }
99
100 pub fn file_scope(self, db: &'db dyn Db) -> FileScopeId {
101 self.scope_id(db).file_scope_id(db)
102 }
103
104 pub fn place(self, db: &'db dyn Db) -> ScopedPlaceId {
105 self.place_info(db).place()
106 }
107
108 pub fn is_reexported(self, db: &'db dyn Db) -> bool {
109 self.place_info(db).is_reexported()
110 }
111
112 pub fn full_range(self, db: &'db dyn Db, module: &ParsedModuleRef) -> FileRange {
113 FileRange::new(self.file(db), self.kind(db).full_range(module))
114 }
115
116 pub fn focus_range(self, db: &'db dyn Db, module: &ParsedModuleRef) -> FileRange {
117 FileRange::new(self.file(db), self.kind(db).target_range(module))
118 }
119
120 pub fn name(self, db: &'db dyn Db) -> Option<String> {
122 let module = parsed_module(db, self.python_file(db)).load(db);
123 let kind = self.kind(db);
124 match kind {
125 DefinitionKind::Function(def) => {
126 let node = def.node(&module);
127 Some(node.name.as_str().to_string())
128 }
129 DefinitionKind::Class(def) => {
130 let node = def.node(&module);
131 Some(node.name.as_str().to_string())
132 }
133 DefinitionKind::TypeAlias(def) => {
134 let node = def.node(&module);
135 Some(
136 node.name
137 .as_name_expr()
138 .expect("type alias name should be a NameExpr")
139 .id
140 .as_str()
141 .to_string(),
142 )
143 }
144 DefinitionKind::Assignment(assignment) => {
145 let target_node = assignment.target.node(&module);
146 target_node
147 .as_name_expr()
148 .map(|name_expr| name_expr.id.as_str().to_string())
149 }
150 _ => None,
151 }
152 }
153
154 pub fn docstring(self, db: &'db dyn Db) -> Option<String> {
158 let module = parsed_module(db, self.python_file(db)).load(db);
159 let kind = self.kind(db);
160
161 match kind {
162 DefinitionKind::Assignment(assign_def) => {
163 let assign_node = assign_def.target(&module);
164 attribute_docstring(&module, assign_node)
165 .map(|docstring_expr| docstring_expr.value.to_str().to_owned())
166 }
167 DefinitionKind::AnnotatedAssignment(assign_def) => {
168 let assign_node = assign_def.target(&module);
169 attribute_docstring(&module, assign_node)
170 .map(|docstring_expr| docstring_expr.value.to_str().to_owned())
171 }
172 DefinitionKind::Function(function_def) => {
173 let function_node = function_def.node(&module);
174 docstring_from_body(&function_node.body)
175 .map(|docstring_expr| docstring_expr.value.to_str().to_owned())
176 }
177 DefinitionKind::Class(class_def) => {
178 let class_node = class_def.node(&module);
179 docstring_from_body(&class_node.body)
180 .map(|docstring_expr| docstring_expr.value.to_str().to_owned())
181 }
182 _ => None,
183 }
184 }
185}
186
187#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, get_size2::GetSize)]
193pub enum DefinitionPlace {
194 Symbol {
195 id: ScopedSymbolId,
196 is_reexported: bool,
197 },
198 Member {
199 id: ScopedMemberId,
200 is_reexported: bool,
201 },
202}
203
204impl DefinitionPlace {
205 fn new(place: ScopedPlaceId, is_reexported: bool) -> Self {
206 match place {
207 ScopedPlaceId::Symbol(id) => Self::Symbol { id, is_reexported },
208 ScopedPlaceId::Member(id) => Self::Member { id, is_reexported },
209 }
210 }
211
212 fn place(self) -> ScopedPlaceId {
213 match self {
214 Self::Symbol { id, .. } => ScopedPlaceId::Symbol(id),
215 Self::Member { id, .. } => ScopedPlaceId::Member(id),
216 }
217 }
218
219 fn is_reexported(self) -> bool {
220 match self {
221 Self::Symbol { is_reexported, .. } | Self::Member { is_reexported, .. } => {
222 is_reexported
223 }
224 }
225 }
226}
227
228pub fn docstring_from_body(body: &[ast::Stmt]) -> Option<&ast::ExprStringLiteral> {
230 let stmt = body.first()?;
231 let ast::StmtExpr {
233 value,
234 range: _,
235 node_index: _,
236 } = stmt.as_expr_stmt()?;
237 value.as_string_literal_expr()
239}
240
241fn attribute_docstring<'a>(
251 module: &'a ParsedModuleRef,
252 assign_lvalue: &Expr,
253) -> Option<&'a ast::ExprStringLiteral> {
254 let covering_node = covering_node(module.syntax().into(), assign_lvalue.range());
256 let assign = covering_node.find_first(AnyNodeRef::is_statement).ok()?;
258 let parent = assign.parent()?;
259 let assign_node = assign.node();
260
261 let parent_body = suite(assign_node, parent)?;
263 let next_stmt = parent_body.next_sibling()?;
264
265 let ast::Stmt::Expr(ast::StmtExpr {
267 value,
268 range: _,
269 node_index: _,
270 }) = next_stmt
271 else {
272 return None;
273 };
274
275 value.as_string_literal_expr()
277}
278
279#[derive(Debug, Default, PartialEq, Eq, get_size2::GetSize)]
281pub struct Definitions<'db> {
282 definitions: smallvec::SmallVec<[Definition<'db>; 1]>,
283}
284
285impl<'db> Definitions<'db> {
286 pub(crate) fn push(&mut self, definition: Definition<'db>) {
287 self.definitions.push(definition);
288 }
289
290 pub(crate) fn into_boxed_slice(self) -> Box<[Definition<'db>]> {
291 self.definitions.into_vec().into_boxed_slice()
292 }
293}
294
295impl<'db> Deref for Definitions<'db> {
296 type Target = [Definition<'db>];
297
298 fn deref(&self) -> &Self::Target {
299 &self.definitions
300 }
301}
302
303impl<'a, 'db> IntoIterator for &'a Definitions<'db> {
304 type Item = &'a Definition<'db>;
305 type IntoIter = std::slice::Iter<'a, Definition<'db>>;
306
307 fn into_iter(self) -> Self::IntoIter {
308 self.definitions.iter()
309 }
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq, get_size2::GetSize)]
313pub enum DefinitionState<'db> {
314 Defined(Definition<'db>),
315 Undefined,
317 Deleted,
320}
321
322impl<'db> DefinitionState<'db> {
323 pub fn is_defined_and(self, f: impl Fn(Definition<'db>) -> bool) -> bool {
324 matches!(self, DefinitionState::Defined(def) if f(def))
325 }
326
327 pub fn is_undefined_or(self, f: impl Fn(Definition<'db>) -> bool) -> bool {
328 matches!(self, DefinitionState::Undefined)
329 || matches!(self, DefinitionState::Defined(def) if f(def))
330 }
331
332 #[allow(unused)]
333 pub fn definition(self) -> Option<Definition<'db>> {
334 match self {
335 DefinitionState::Defined(def) => Some(def),
336 DefinitionState::Deleted | DefinitionState::Undefined => None,
337 }
338 }
339}
340
341#[derive(Copy, Clone, Debug)]
342pub(crate) enum DefinitionNodeRef<'ast, 'db> {
343 Import(ImportDefinitionNodeRef<'ast>),
344 ImportFrom(ImportFromDefinitionNodeRef<'ast>),
345 ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef<'ast>),
346 ImportStar(StarImportDefinitionNodeRef<'ast>),
347 For(ForStmtDefinitionNodeRef<'ast, 'db>),
348 Function(&'ast ast::StmtFunctionDef),
349 Class(&'ast ast::StmtClassDef),
350 TypeAlias(&'ast ast::StmtTypeAlias),
351 NamedExpression(&'ast ast::ExprNamed),
352 Assignment(AssignmentDefinitionNodeRef<'ast, 'db>),
353 AnnotatedAssignment(AnnotatedAssignmentDefinitionNodeRef<'ast>),
354 AugmentedAssignment(&'ast ast::StmtAugAssign),
355 DictKeyAssignment(DictKeyAssignmentNodeRef<'ast, 'db>),
356 Comprehension(ComprehensionDefinitionNodeRef<'ast, 'db>),
357 Parameter(ParameterDefinitionNodeRef<'ast>),
358 LambdaParameter(LambdaParameterDefinitionNodeRef<'ast>),
359 WithItem(WithItemDefinitionNodeRef<'ast, 'db>),
360 MatchPattern(MatchPatternDefinitionNodeRef<'ast, 'db>),
361 ExceptHandler(ExceptHandlerDefinitionNodeRef<'ast>),
362 TypeVar(&'ast ast::TypeParamTypeVar),
363 ParamSpec(&'ast ast::TypeParamParamSpec),
364 TypeVarTuple(&'ast ast::TypeParamTypeVarTuple),
365 LoopHeader(LoopHeaderDefinitionNodeRef<'ast>),
366}
367
368impl<'ast> From<&'ast ast::StmtFunctionDef> for DefinitionNodeRef<'ast, '_> {
369 fn from(node: &'ast ast::StmtFunctionDef) -> Self {
370 Self::Function(node)
371 }
372}
373
374impl<'ast> From<&'ast ast::StmtClassDef> for DefinitionNodeRef<'ast, '_> {
375 fn from(node: &'ast ast::StmtClassDef) -> Self {
376 Self::Class(node)
377 }
378}
379
380impl<'ast> From<&'ast ast::StmtTypeAlias> for DefinitionNodeRef<'ast, '_> {
381 fn from(node: &'ast ast::StmtTypeAlias) -> Self {
382 Self::TypeAlias(node)
383 }
384}
385
386impl<'ast> From<&'ast ast::ExprNamed> for DefinitionNodeRef<'ast, '_> {
387 fn from(node: &'ast ast::ExprNamed) -> Self {
388 Self::NamedExpression(node)
389 }
390}
391
392impl<'ast> From<&'ast ast::StmtAugAssign> for DefinitionNodeRef<'ast, '_> {
393 fn from(node: &'ast ast::StmtAugAssign) -> Self {
394 Self::AugmentedAssignment(node)
395 }
396}
397
398impl<'ast> From<&'ast ast::TypeParamTypeVar> for DefinitionNodeRef<'ast, '_> {
399 fn from(value: &'ast ast::TypeParamTypeVar) -> Self {
400 Self::TypeVar(value)
401 }
402}
403
404impl<'ast> From<&'ast ast::TypeParamParamSpec> for DefinitionNodeRef<'ast, '_> {
405 fn from(value: &'ast ast::TypeParamParamSpec) -> Self {
406 Self::ParamSpec(value)
407 }
408}
409
410impl<'ast> From<&'ast ast::TypeParamTypeVarTuple> for DefinitionNodeRef<'ast, '_> {
411 fn from(value: &'ast ast::TypeParamTypeVarTuple) -> Self {
412 Self::TypeVarTuple(value)
413 }
414}
415
416impl<'ast> From<LoopHeaderDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
417 fn from(value: LoopHeaderDefinitionNodeRef<'ast>) -> Self {
418 Self::LoopHeader(value)
419 }
420}
421
422impl<'ast> From<ImportDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
423 fn from(node_ref: ImportDefinitionNodeRef<'ast>) -> Self {
424 Self::Import(node_ref)
425 }
426}
427
428impl<'ast> From<ImportFromDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
429 fn from(node_ref: ImportFromDefinitionNodeRef<'ast>) -> Self {
430 Self::ImportFrom(node_ref)
431 }
432}
433
434impl<'ast> From<ImportFromSubmoduleDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
435 fn from(node_ref: ImportFromSubmoduleDefinitionNodeRef<'ast>) -> Self {
436 Self::ImportFromSubmodule(node_ref)
437 }
438}
439
440impl<'ast, 'db> From<ForStmtDefinitionNodeRef<'ast, 'db>> for DefinitionNodeRef<'ast, 'db> {
441 fn from(value: ForStmtDefinitionNodeRef<'ast, 'db>) -> Self {
442 Self::For(value)
443 }
444}
445
446impl<'ast, 'db> From<AssignmentDefinitionNodeRef<'ast, 'db>> for DefinitionNodeRef<'ast, 'db> {
447 fn from(node_ref: AssignmentDefinitionNodeRef<'ast, 'db>) -> Self {
448 Self::Assignment(node_ref)
449 }
450}
451
452impl<'ast> From<AnnotatedAssignmentDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
453 fn from(node_ref: AnnotatedAssignmentDefinitionNodeRef<'ast>) -> Self {
454 Self::AnnotatedAssignment(node_ref)
455 }
456}
457
458impl<'ast, 'db> From<DictKeyAssignmentNodeRef<'ast, 'db>> for DefinitionNodeRef<'ast, 'db> {
459 fn from(node_ref: DictKeyAssignmentNodeRef<'ast, 'db>) -> Self {
460 Self::DictKeyAssignment(node_ref)
461 }
462}
463
464impl<'ast, 'db> From<WithItemDefinitionNodeRef<'ast, 'db>> for DefinitionNodeRef<'ast, 'db> {
465 fn from(node_ref: WithItemDefinitionNodeRef<'ast, 'db>) -> Self {
466 Self::WithItem(node_ref)
467 }
468}
469
470impl<'ast, 'db> From<ComprehensionDefinitionNodeRef<'ast, 'db>> for DefinitionNodeRef<'ast, 'db> {
471 fn from(node: ComprehensionDefinitionNodeRef<'ast, 'db>) -> Self {
472 Self::Comprehension(node)
473 }
474}
475
476impl<'ast> From<ParameterDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
477 fn from(node: ParameterDefinitionNodeRef<'ast>) -> Self {
478 Self::Parameter(node)
479 }
480}
481
482impl<'ast> From<LambdaParameterDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
483 fn from(node: LambdaParameterDefinitionNodeRef<'ast>) -> Self {
484 Self::LambdaParameter(node)
485 }
486}
487
488impl<'ast, 'db> From<MatchPatternDefinitionNodeRef<'ast, 'db>> for DefinitionNodeRef<'ast, 'db> {
489 fn from(node: MatchPatternDefinitionNodeRef<'ast, 'db>) -> Self {
490 Self::MatchPattern(node)
491 }
492}
493
494impl<'ast> From<StarImportDefinitionNodeRef<'ast>> for DefinitionNodeRef<'ast, '_> {
495 fn from(node: StarImportDefinitionNodeRef<'ast>) -> Self {
496 Self::ImportStar(node)
497 }
498}
499
500#[derive(Copy, Clone, Debug)]
501pub(crate) struct ImportDefinitionNodeRef<'ast> {
502 pub(crate) node: &'ast ast::StmtImport,
503 pub(crate) alias_index: usize,
504 pub(crate) is_reexported: bool,
505}
506
507#[derive(Copy, Clone, Debug)]
508pub(crate) struct StarImportDefinitionNodeRef<'ast> {
509 pub(crate) node: &'ast ast::StmtImportFrom,
510 pub(crate) symbol_id: ScopedSymbolId,
511}
512
513#[derive(Copy, Clone, Debug)]
514pub(crate) struct ImportFromDefinitionNodeRef<'ast> {
515 pub(crate) node: &'ast ast::StmtImportFrom,
516 pub(crate) alias_index: usize,
517 pub(crate) is_reexported: bool,
518}
519
520#[derive(Copy, Clone, Debug)]
521pub(crate) struct ImportFromSubmoduleDefinitionNodeRef<'ast> {
522 pub(crate) node: &'ast ast::StmtImportFrom,
523 pub(crate) module_index: usize,
524}
525
526#[derive(Copy, Clone, Debug)]
527pub(crate) struct AssignmentDefinitionNodeRef<'ast, 'db> {
528 pub(crate) unpack: Option<Unpack<'db>>,
529 pub(crate) value: &'ast ast::Expr,
530 pub(crate) target: &'ast ast::Expr,
531}
532
533#[derive(Copy, Clone, Debug)]
534pub(crate) struct AnnotatedAssignmentDefinitionNodeRef<'ast> {
535 pub(crate) node: &'ast ast::StmtAnnAssign,
536}
537
538#[derive(Copy, Clone, Debug)]
539pub(crate) struct DictKeyAssignmentNodeRef<'ast, 'db> {
540 pub(crate) key: &'ast ast::Expr,
541 pub(crate) value: &'ast ast::Expr,
542 pub(crate) assignment: Definition<'db>,
543}
544
545#[derive(Copy, Clone, Debug)]
546pub(crate) struct WithItemDefinitionNodeRef<'ast, 'db> {
547 pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
548 pub(crate) item: &'ast ast::WithItem,
549 pub(crate) target: &'ast ast::Expr,
550 pub(crate) is_async: bool,
551}
552
553#[derive(Copy, Clone, Debug)]
554pub(crate) struct ForStmtDefinitionNodeRef<'ast, 'db> {
555 pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
556 pub(crate) node: &'ast ast::StmtFor,
557 pub(crate) target: &'ast ast::Expr,
558}
559
560#[derive(Copy, Clone, Debug)]
561pub(crate) struct ExceptHandlerDefinitionNodeRef<'ast> {
562 pub(crate) handler: &'ast ast::ExceptHandlerExceptHandler,
563 pub(crate) is_star: bool,
564}
565
566#[derive(Copy, Clone, Debug)]
567pub(crate) struct LoopHeaderDefinitionNodeRef<'ast> {
568 pub(crate) loop_stmt: LoopStmtRef<'ast>,
569 pub(crate) place: ScopedPlaceId,
570 pub(crate) loop_header_id: LoopHeaderId,
571}
572
573#[derive(Copy, Clone, Debug)]
574pub(crate) enum LoopStmtRef<'ast> {
575 While(&'ast ast::StmtWhile),
576 For(&'ast ast::StmtFor),
577}
578
579#[derive(Copy, Clone, Debug)]
580pub(crate) struct ComprehensionDefinitionNodeRef<'ast, 'db> {
581 pub(crate) unpack: Option<(UnpackPosition, Unpack<'db>)>,
582 pub(crate) node: &'ast ast::Comprehension,
583 pub(crate) target: &'ast ast::Expr,
584 pub(crate) first: bool,
585}
586
587#[derive(Copy, Clone, Debug)]
588pub(crate) enum ParameterDefinitionNodeRef<'ast> {
589 VariadicPositionalParameter(&'ast ast::Parameter),
590 VariadicKeywordParameter(&'ast ast::Parameter),
591 Parameter(&'ast ast::ParameterWithDefault),
592}
593
594impl ParameterDefinitionNodeRef<'_> {
595 fn into_owned(self, parsed: &ParsedModuleRef) -> ParameterDefinitionNodeKind {
596 match self {
597 Self::VariadicPositionalParameter(parameter) => {
598 ParameterDefinitionNodeKind::VariadicPositionalParameter(AstNodeRef::new(
599 parsed, parameter,
600 ))
601 }
602 Self::VariadicKeywordParameter(parameter) => {
603 ParameterDefinitionNodeKind::VariadicKeywordParameter(AstNodeRef::new(
604 parsed, parameter,
605 ))
606 }
607 Self::Parameter(parameter) => {
608 ParameterDefinitionNodeKind::Parameter(AstNodeRef::new(parsed, parameter))
609 }
610 }
611 }
612
613 fn key(self) -> DefinitionNodeKey {
614 match self {
615 Self::VariadicPositionalParameter(node) => node.into(),
616 Self::VariadicKeywordParameter(node) => node.into(),
617 Self::Parameter(node) => (&node.parameter).into(),
618 }
619 }
620}
621
622#[derive(Copy, Clone, Debug)]
623pub(crate) struct LambdaParameterDefinitionNodeRef<'ast> {
624 pub(crate) index: usize,
625 pub(crate) parameter: ParameterDefinitionNodeRef<'ast>,
626 pub(crate) lambda: &'ast ast::ExprLambda,
627}
628
629#[derive(Copy, Clone, Debug)]
630pub(crate) struct MatchPatternDefinitionNodeRef<'ast, 'db> {
631 pub(crate) pattern: &'ast ast::Pattern,
633 pub(crate) identifier: &'ast ast::Identifier,
635 pub(crate) predicate: PatternPredicate<'db>,
637}
638
639impl<'db> DefinitionNodeRef<'_, 'db> {
640 pub(super) fn into_owned(self, parsed: &ParsedModuleRef) -> DefinitionKind<'db> {
641 match self {
642 DefinitionNodeRef::Import(ImportDefinitionNodeRef {
643 node,
644 alias_index,
645 is_reexported,
646 }) => DefinitionKind::Import(ImportDefinitionKind {
647 node: AstNodeRef::new(parsed, node),
648 alias_index: alias_index
649 .try_into()
650 .expect("import alias index should fit in u32"),
651 is_reexported,
652 }),
653 DefinitionNodeRef::ImportFrom(ImportFromDefinitionNodeRef {
654 node,
655 alias_index,
656 is_reexported,
657 }) => DefinitionKind::ImportFrom(ImportFromDefinitionKind {
658 node: AstNodeRef::new(parsed, node),
659 alias_index: alias_index
660 .try_into()
661 .expect("import-from alias index should fit in u32"),
662 is_reexported,
663 }),
664 DefinitionNodeRef::ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef {
665 node,
666 module_index,
667 }) => DefinitionKind::ImportFromSubmodule(ImportFromSubmoduleDefinitionKind {
668 node: AstNodeRef::new(parsed, node),
669 module_index: module_index
670 .try_into()
671 .expect("import-from submodule index should fit in u32"),
672 }),
673 DefinitionNodeRef::ImportStar(star_import) => {
674 let StarImportDefinitionNodeRef { node, symbol_id } = star_import;
675 DefinitionKind::StarImport(StarImportDefinitionKind {
676 node: AstNodeRef::new(parsed, node),
677 symbol_id,
678 })
679 }
680 DefinitionNodeRef::Function(function) => {
681 DefinitionKind::Function(AstNodeRef::new(parsed, function))
682 }
683 DefinitionNodeRef::Class(class) => {
684 DefinitionKind::Class(AstNodeRef::new(parsed, class))
685 }
686 DefinitionNodeRef::TypeAlias(type_alias) => {
687 DefinitionKind::TypeAlias(AstNodeRef::new(parsed, type_alias))
688 }
689 DefinitionNodeRef::NamedExpression(named) => {
690 DefinitionKind::NamedExpression(AstNodeRef::new(parsed, named))
691 }
692 DefinitionNodeRef::Assignment(AssignmentDefinitionNodeRef {
693 unpack,
694 value,
695 target,
696 }) => DefinitionKind::Assignment(AssignmentDefinitionKind {
697 unpack,
698 value: AstNodeRef::new(parsed, value),
699 target: AstNodeRef::new(parsed, target),
700 }),
701 DefinitionNodeRef::AnnotatedAssignment(AnnotatedAssignmentDefinitionNodeRef {
702 node,
703 }) => DefinitionKind::AnnotatedAssignment(AnnotatedAssignmentDefinitionKind {
704 node: AstNodeRef::new(parsed, node),
705 has_value: node.value.is_some(),
706 }),
707 DefinitionNodeRef::AugmentedAssignment(augmented_assignment) => {
708 DefinitionKind::AugmentedAssignment(AstNodeRef::new(parsed, augmented_assignment))
709 }
710 DefinitionNodeRef::DictKeyAssignment(DictKeyAssignmentNodeRef {
711 key,
712 value,
713 assignment,
714 }) => DefinitionKind::DictKeyAssignment(DictKeyAssignmentKind {
715 key: AstNodeRef::new(parsed, key),
716 value: AstNodeRef::new(parsed, value),
717 assignment,
718 }),
719 DefinitionNodeRef::For(ForStmtDefinitionNodeRef {
720 unpack,
721 node,
722 target,
723 }) => DefinitionKind::For(ForStmtDefinitionKind {
724 unpack: unpack.map(|(_, unpack)| unpack),
725 unpack_position: unpack.map_or(UnpackPosition::First, |(position, _)| position),
726 node: AstNodeRef::new(parsed, node),
727 target: AstNodeRef::new(parsed, target),
728 is_async: node.is_async,
729 }),
730 DefinitionNodeRef::Comprehension(ComprehensionDefinitionNodeRef {
731 unpack,
732 node,
733 target,
734 first,
735 }) => DefinitionKind::Comprehension(ComprehensionDefinitionKind {
736 unpack: unpack.map(|(_, unpack)| unpack),
737 unpack_position: unpack.map_or(UnpackPosition::First, |(position, _)| position),
738 node: AstNodeRef::new(parsed, node),
739 target: AstNodeRef::new(parsed, target),
740 first,
741 is_async: node.is_async,
742 }),
743 DefinitionNodeRef::Parameter(parameter) => {
744 DefinitionKind::Parameter(parameter.into_owned(parsed))
745 }
746 DefinitionNodeRef::LambdaParameter(LambdaParameterDefinitionNodeRef {
747 index,
748 parameter,
749 lambda,
750 }) => DefinitionKind::LambdaParameter(LambdaParameterDefinitionNodeKind {
751 index: index
752 .try_into()
753 .expect("lambda parameter index should fit in u32"),
754 parameter: parameter.into_owned(parsed),
755 lambda: AstNodeRef::new(parsed, lambda),
756 }),
757 DefinitionNodeRef::WithItem(WithItemDefinitionNodeRef {
758 unpack,
759 item,
760 target,
761 is_async,
762 }) => DefinitionKind::WithItem(WithItemDefinitionKind {
763 unpack: unpack.map(|(_, unpack)| unpack),
764 unpack_position: unpack.map_or(UnpackPosition::First, |(position, _)| position),
765 item: AstNodeRef::new(parsed, item),
766 target: AstNodeRef::new(parsed, target),
767 is_async,
768 }),
769 DefinitionNodeRef::MatchPattern(MatchPatternDefinitionNodeRef {
770 pattern,
771 identifier,
772 predicate,
773 }) => DefinitionKind::MatchPattern(MatchPatternDefinitionKind {
774 pattern: AstNodeRef::new(parsed, pattern),
775 identifier: AstNodeRef::new(parsed, identifier),
776 predicate,
777 }),
778 DefinitionNodeRef::ExceptHandler(ExceptHandlerDefinitionNodeRef {
779 handler,
780 is_star,
781 }) => DefinitionKind::ExceptHandler(ExceptHandlerDefinitionKind {
782 handler: AstNodeRef::new(parsed, handler),
783 is_star,
784 }),
785 DefinitionNodeRef::TypeVar(node) => {
786 DefinitionKind::TypeVar(AstNodeRef::new(parsed, node))
787 }
788 DefinitionNodeRef::ParamSpec(node) => {
789 DefinitionKind::ParamSpec(AstNodeRef::new(parsed, node))
790 }
791 DefinitionNodeRef::TypeVarTuple(node) => {
792 DefinitionKind::TypeVarTuple(AstNodeRef::new(parsed, node))
793 }
794 DefinitionNodeRef::LoopHeader(LoopHeaderDefinitionNodeRef {
795 loop_stmt,
796 place,
797 loop_header_id,
798 }) => DefinitionKind::LoopHeader(LoopHeaderDefinitionKind {
799 loop_header_id,
800 loop_stmt: match loop_stmt {
801 LoopStmtRef::While(stmt) => LoopStmtKind::While(AstNodeRef::new(parsed, stmt)),
802 LoopStmtRef::For(stmt) => LoopStmtKind::For(AstNodeRef::new(parsed, stmt)),
803 },
804 place,
805 }),
806 }
807 }
808
809 pub(super) fn key(self) -> DefinitionNodeKey {
810 match self {
811 Self::Import(ImportDefinitionNodeRef {
812 node,
813 alias_index,
814 is_reexported: _,
815 }) => (&node.names[alias_index]).into(),
816 Self::ImportFrom(ImportFromDefinitionNodeRef {
817 node,
818 alias_index,
819 is_reexported: _,
820 }) => (&node.names[alias_index]).into(),
821 Self::ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef { node, .. }) => {
822 node.into()
823 }
824 Self::ImportStar(StarImportDefinitionNodeRef { node, symbol_id: _ }) => node
827 .names
828 .iter()
829 .find(|alias| &alias.name == "*")
830 .expect(
831 "The `StmtImportFrom` node of a `StarImportDefinitionKind` instance \
832 should always have at least one `alias` with the name `*`.",
833 )
834 .into(),
835
836 Self::Function(node) => node.into(),
837 Self::Class(node) => node.into(),
838 Self::TypeAlias(node) => node.into(),
839 Self::NamedExpression(node) => node.into(),
840 Self::Assignment(AssignmentDefinitionNodeRef {
841 value: _,
842 unpack: _,
843 target,
844 }) => DefinitionNodeKey(NodeKey::from_node(target)),
845 Self::AnnotatedAssignment(ann_assign) => ann_assign.node.into(),
846 Self::AugmentedAssignment(node) => node.into(),
847 Self::DictKeyAssignment(node) => DefinitionNodeKey(NodeKey::from_node(node.key)),
848 Self::For(ForStmtDefinitionNodeRef {
849 target,
850 node: _,
851 unpack: _,
852 }) => DefinitionNodeKey(NodeKey::from_node(target)),
853 Self::Comprehension(ComprehensionDefinitionNodeRef { target, .. }) => {
854 DefinitionNodeKey(NodeKey::from_node(target))
855 }
856 Self::LambdaParameter(LambdaParameterDefinitionNodeRef { parameter, .. }) => {
857 parameter.key()
858 }
859 Self::Parameter(parameter) => parameter.key(),
860 Self::WithItem(WithItemDefinitionNodeRef {
861 item: _,
862 unpack: _,
863 is_async: _,
864 target,
865 }) => DefinitionNodeKey(NodeKey::from_node(target)),
866 Self::MatchPattern(MatchPatternDefinitionNodeRef { identifier, .. }) => {
867 identifier.into()
868 }
869 Self::ExceptHandler(ExceptHandlerDefinitionNodeRef { handler, .. }) => handler.into(),
870 Self::TypeVar(node) => node.into(),
871 Self::ParamSpec(node) => node.into(),
872 Self::TypeVarTuple(node) => node.into(),
873 Self::LoopHeader(LoopHeaderDefinitionNodeRef { loop_stmt, .. }) => match loop_stmt {
874 LoopStmtRef::While(stmt) => stmt.into(),
875 LoopStmtRef::For(stmt) => stmt.into(),
876 },
877 }
878 }
879}
880
881#[derive(Clone, Copy, Debug)]
882pub enum DefinitionCategory {
883 Binding,
885 Declaration,
887 DeclarationAndBinding,
889}
890
891impl DefinitionCategory {
892 pub fn is_declaration(self) -> bool {
899 matches!(
900 self,
901 DefinitionCategory::Declaration | DefinitionCategory::DeclarationAndBinding
902 )
903 }
904
905 pub fn is_binding(self) -> bool {
909 matches!(
910 self,
911 DefinitionCategory::Binding | DefinitionCategory::DeclarationAndBinding
912 )
913 }
914}
915
916#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
924pub enum DefinitionKind<'db> {
925 Import(ImportDefinitionKind),
926 ImportFrom(ImportFromDefinitionKind),
927 ImportFromSubmodule(ImportFromSubmoduleDefinitionKind),
928 StarImport(StarImportDefinitionKind),
929 Function(AstNodeRef<ast::StmtFunctionDef>),
930 Class(AstNodeRef<ast::StmtClassDef>),
931 TypeAlias(AstNodeRef<ast::StmtTypeAlias>),
932 NamedExpression(AstNodeRef<ast::ExprNamed>),
933 Assignment(AssignmentDefinitionKind<'db>),
934 AnnotatedAssignment(AnnotatedAssignmentDefinitionKind),
935 AugmentedAssignment(AstNodeRef<ast::StmtAugAssign>),
936 DictKeyAssignment(DictKeyAssignmentKind<'db>),
937 For(ForStmtDefinitionKind<'db>),
938 Comprehension(ComprehensionDefinitionKind<'db>),
939 Parameter(ParameterDefinitionNodeKind),
940 LambdaParameter(LambdaParameterDefinitionNodeKind),
941 WithItem(WithItemDefinitionKind<'db>),
942 MatchPattern(MatchPatternDefinitionKind<'db>),
943 ExceptHandler(ExceptHandlerDefinitionKind),
944 TypeVar(AstNodeRef<ast::TypeParamTypeVar>),
945 ParamSpec(AstNodeRef<ast::TypeParamParamSpec>),
946 TypeVarTuple(AstNodeRef<ast::TypeParamTypeVarTuple>),
947 LoopHeader(LoopHeaderDefinitionKind),
948 NestedBindings(Box<NestedBindingsDefinitionKind>),
950}
951
952impl<'db> DefinitionKind<'db> {
953 pub(crate) fn is_reexported(&self) -> bool {
954 match self {
955 DefinitionKind::Import(import) => import.is_reexported(),
956 DefinitionKind::ImportFrom(import) => import.is_reexported(),
957 DefinitionKind::ImportFromSubmodule(_) => true,
958 _ => true,
959 }
960 }
961
962 pub const fn as_star_import(&self) -> Option<&StarImportDefinitionKind> {
963 match self {
964 DefinitionKind::StarImport(import) => Some(import),
965 _ => None,
966 }
967 }
968
969 pub const fn as_class(&self) -> Option<&AstNodeRef<ast::StmtClassDef>> {
970 match self {
971 DefinitionKind::Class(class) => Some(class),
972 _ => None,
973 }
974 }
975
976 pub fn is_import(&self) -> bool {
977 matches!(
978 self,
979 DefinitionKind::Import(_)
980 | DefinitionKind::ImportFrom(_)
981 | DefinitionKind::StarImport(_)
982 | DefinitionKind::ImportFromSubmodule(_)
983 )
984 }
985
986 pub const fn is_unannotated_assignment(&self) -> bool {
987 matches!(self, DefinitionKind::Assignment(_))
988 }
989
990 pub(crate) fn as_unannotated_assignment(&self) -> Option<AssignmentDefinitionKind<'db>> {
991 match self {
992 DefinitionKind::Assignment(assignment) => Some(assignment.clone()),
993 _ => None,
994 }
995 }
996
997 pub const fn is_function_def(&self) -> bool {
998 matches!(self, DefinitionKind::Function(_))
999 }
1000
1001 pub const fn is_parameter_def(&self) -> bool {
1002 matches!(self, DefinitionKind::Parameter(_))
1003 }
1004
1005 pub const fn is_loop_header(&self) -> bool {
1006 matches!(self, DefinitionKind::LoopHeader(_))
1007 }
1008
1009 pub const fn is_user_visible(&self) -> bool {
1012 !matches!(
1013 self,
1014 DefinitionKind::LoopHeader(_) | DefinitionKind::NestedBindings(_)
1015 )
1016 }
1017
1018 pub fn target_range(&self, module: &ParsedModuleRef) -> TextRange {
1023 match self {
1024 DefinitionKind::Import(import) => import.alias(module).range(),
1025 DefinitionKind::ImportFrom(import) => import.alias(module).range(),
1026 DefinitionKind::ImportFromSubmodule(import) => import.target_range(module),
1027 DefinitionKind::StarImport(import) => import.alias(module).range(),
1028 DefinitionKind::Function(function) => function.node(module).name.range(),
1029 DefinitionKind::Class(class) => class.node(module).name.range(),
1030 DefinitionKind::TypeAlias(type_alias) => type_alias.node(module).name.range(),
1031 DefinitionKind::NamedExpression(named) => named.node(module).target.range(),
1032 DefinitionKind::Assignment(assignment) => assignment.target(module).range(),
1033 DefinitionKind::AnnotatedAssignment(assign) => assign.target(module).range(),
1034 DefinitionKind::AugmentedAssignment(aug_assign) => {
1035 aug_assign.node(module).target.range()
1036 }
1037 DefinitionKind::DictKeyAssignment(dict_key_assignment) => {
1038 dict_key_assignment.key.node(module).range()
1039 }
1040 DefinitionKind::For(for_stmt) => for_stmt.target(module).range(),
1041 DefinitionKind::Comprehension(comp) => comp.target(module).range(),
1042 DefinitionKind::Parameter(parameter) => parameter.target_range(module),
1043 DefinitionKind::LambdaParameter(LambdaParameterDefinitionNodeKind {
1044 parameter,
1045 ..
1046 }) => parameter.target_range(module),
1047 DefinitionKind::WithItem(with_item) => with_item.target(module).range(),
1048 DefinitionKind::MatchPattern(match_pattern) => {
1049 match_pattern.identifier.node(module).range()
1050 }
1051 DefinitionKind::ExceptHandler(handler) => handler
1052 .node(module)
1053 .name
1054 .as_ref()
1055 .map_or_else(|| handler.node(module).range(), Ranged::range),
1056 DefinitionKind::TypeVar(type_var) => type_var.node(module).name.range(),
1057 DefinitionKind::ParamSpec(param_spec) => param_spec.node(module).name.range(),
1058 DefinitionKind::TypeVarTuple(type_var_tuple) => {
1059 type_var_tuple.node(module).name.range()
1060 }
1061 DefinitionKind::LoopHeader(loop_header) => loop_header.range(module),
1062 DefinitionKind::NestedBindings(nested_bindings) => {
1063 nested_bindings.nested_declarations[0].range
1067 }
1068 }
1069 }
1070
1071 pub fn full_range(&self, module: &ParsedModuleRef) -> TextRange {
1073 match self {
1074 DefinitionKind::Import(import) => import.alias(module).range(),
1075 DefinitionKind::ImportFrom(import) => import.alias(module).range(),
1076 DefinitionKind::ImportFromSubmodule(import) => import.module(module).range(),
1077 DefinitionKind::StarImport(import) => import.import(module).range(),
1078 DefinitionKind::Function(function) => function.node(module).range(),
1079 DefinitionKind::Class(class) => class.node(module).range(),
1080 DefinitionKind::TypeAlias(type_alias) => type_alias.node(module).range(),
1081 DefinitionKind::NamedExpression(named) => named.node(module).range(),
1082 DefinitionKind::Assignment(assign) => {
1083 let target_range = assign.target(module).range();
1084 let value_range = assign.value(module).range();
1085 target_range.cover(value_range)
1086 }
1087 DefinitionKind::AnnotatedAssignment(assign) => {
1088 let mut full_range = assign.target(module).range();
1089 full_range = full_range.cover(assign.annotation(module).range());
1090
1091 if let Some(value) = assign.value(module) {
1092 full_range = full_range.cover(value.range());
1093 }
1094
1095 full_range
1096 }
1097 DefinitionKind::AugmentedAssignment(aug_assign) => aug_assign.node(module).range(),
1098 DefinitionKind::DictKeyAssignment(dict_key_assignment) => {
1099 dict_key_assignment.key.node(module).range()
1100 }
1101 DefinitionKind::For(for_stmt) => for_stmt.target(module).range(),
1102 DefinitionKind::Comprehension(comp) => comp.target(module).range(),
1103 DefinitionKind::Parameter(parameter) => parameter.full_range(module),
1104 DefinitionKind::LambdaParameter(LambdaParameterDefinitionNodeKind {
1105 parameter,
1106 ..
1107 }) => parameter.full_range(module),
1108 DefinitionKind::WithItem(with_item) => with_item.target(module).range(),
1109 DefinitionKind::MatchPattern(match_pattern) => {
1110 match_pattern.identifier.node(module).range()
1111 }
1112 DefinitionKind::ExceptHandler(handler) => handler.node(module).range(),
1113 DefinitionKind::TypeVar(type_var) => type_var.node(module).range(),
1114 DefinitionKind::ParamSpec(param_spec) => param_spec.node(module).range(),
1115 DefinitionKind::TypeVarTuple(type_var_tuple) => type_var_tuple.node(module).range(),
1116 DefinitionKind::LoopHeader(loop_header) => loop_header.range(module),
1117 DefinitionKind::NestedBindings(nested_bindings) => {
1118 nested_bindings.nested_declarations[0].range
1122 }
1123 }
1124 }
1125
1126 pub fn category(&self, in_stub: bool, module: &ParsedModuleRef) -> DefinitionCategory {
1127 match self {
1128 DefinitionKind::Function(_)
1130 | DefinitionKind::Class(_)
1131 | DefinitionKind::TypeAlias(_)
1132 | DefinitionKind::Import(_)
1133 | DefinitionKind::ImportFrom(_)
1134 | DefinitionKind::StarImport(_)
1135 | DefinitionKind::TypeVar(_)
1136 | DefinitionKind::ParamSpec(_)
1137 | DefinitionKind::TypeVarTuple(_) => DefinitionCategory::DeclarationAndBinding,
1138 DefinitionKind::Parameter(parameter) => parameter.category(module),
1139 DefinitionKind::LambdaParameter(LambdaParameterDefinitionNodeKind {
1140 parameter,
1141 ..
1142 }) => parameter.category(module),
1143 DefinitionKind::AnnotatedAssignment(ann_assign) => {
1146 if in_stub || ann_assign.has_value() {
1147 DefinitionCategory::DeclarationAndBinding
1148 } else {
1149 DefinitionCategory::Declaration
1150 }
1151 }
1152 DefinitionKind::DictKeyAssignment(_)
1154 | DefinitionKind::NamedExpression(_)
1155 | DefinitionKind::Assignment(_)
1156 | DefinitionKind::AugmentedAssignment(_)
1157 | DefinitionKind::For(_)
1158 | DefinitionKind::Comprehension(_)
1159 | DefinitionKind::WithItem(_)
1160 | DefinitionKind::MatchPattern(_)
1161 | DefinitionKind::ImportFromSubmodule(_)
1162 | DefinitionKind::ExceptHandler(_)
1163 | DefinitionKind::LoopHeader(_)
1164 | DefinitionKind::NestedBindings(_) => DefinitionCategory::Binding,
1165 }
1166 }
1167
1168 pub fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> Option<&'ast ast::Expr> {
1173 match self {
1174 DefinitionKind::Assignment(assignment) => Some(assignment.value(module)),
1175 DefinitionKind::AnnotatedAssignment(assignment) => assignment.value(module),
1176 _ => None,
1177 }
1178 }
1179}
1180
1181#[derive(Copy, Clone, Debug, PartialEq, Hash, get_size2::GetSize)]
1182pub enum TargetKind<'db> {
1183 Sequence(UnpackPosition, Unpack<'db>),
1184 Single,
1186}
1187
1188impl<'db> TargetKind<'db> {
1189 fn from_unpack(unpack: Option<Unpack<'db>>, unpack_position: UnpackPosition) -> Self {
1190 match unpack {
1191 Some(unpack) => TargetKind::Sequence(unpack_position, unpack),
1192 None => TargetKind::Single,
1193 }
1194 }
1195}
1196
1197#[derive(Clone, Debug, get_size2::GetSize)]
1198pub struct StarImportDefinitionKind {
1199 node: AstNodeRef<ast::StmtImportFrom>,
1200 symbol_id: ScopedSymbolId,
1201}
1202
1203impl StarImportDefinitionKind {
1204 pub fn import<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::StmtImportFrom {
1205 self.node.node(module)
1206 }
1207
1208 pub fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
1209 self.node
1212 .node(module)
1213 .names
1214 .iter()
1215 .find(|alias| &alias.name == "*")
1216 .expect(
1217 "The `StmtImportFrom` node of a `StarImportDefinitionKind` instance \
1218 should always have at least one `alias` with the name `*`.",
1219 )
1220 }
1221
1222 pub fn symbol_id(&self) -> ScopedSymbolId {
1223 self.symbol_id
1224 }
1225}
1226
1227#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
1228pub struct MatchPatternDefinitionKind<'db> {
1229 pattern: AstNodeRef<ast::Pattern>,
1230 identifier: AstNodeRef<ast::Identifier>,
1231 predicate: PatternPredicate<'db>,
1232}
1233
1234impl<'db> MatchPatternDefinitionKind<'db> {
1235 pub fn pattern<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Pattern {
1236 self.pattern.node(module)
1237 }
1238
1239 pub fn predicate(&self) -> PatternPredicate<'db> {
1240 self.predicate
1241 }
1242}
1243
1244#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
1250pub struct ComprehensionDefinitionKind<'db> {
1251 unpack: Option<Unpack<'db>>,
1252 node: AstNodeRef<ast::Comprehension>,
1253 target: AstNodeRef<ast::Expr>,
1254 first: bool,
1255 is_async: bool,
1256 unpack_position: UnpackPosition,
1257}
1258
1259impl<'db> ComprehensionDefinitionKind<'db> {
1260 pub fn iterable<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1261 &self.node.node(module).iter
1262 }
1263
1264 pub fn target_kind(&self) -> TargetKind<'db> {
1265 TargetKind::from_unpack(self.unpack, self.unpack_position)
1266 }
1267
1268 pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1269 self.target.node(module)
1270 }
1271
1272 pub fn is_first(&self) -> bool {
1273 self.first
1274 }
1275
1276 pub fn is_async(&self) -> bool {
1277 self.is_async
1278 }
1279}
1280
1281#[derive(Clone, Debug, get_size2::GetSize)]
1282pub enum ParameterDefinitionNodeKind {
1283 VariadicPositionalParameter(AstNodeRef<ast::Parameter>),
1284 VariadicKeywordParameter(AstNodeRef<ast::Parameter>),
1285 Parameter(AstNodeRef<ast::ParameterWithDefault>),
1286}
1287
1288impl ParameterDefinitionNodeKind {
1289 fn target_range(&self, module: &ParsedModuleRef) -> TextRange {
1290 match self {
1291 Self::VariadicPositionalParameter(parameter) => parameter.node(module).name.range(),
1292 Self::VariadicKeywordParameter(parameter) => parameter.node(module).name.range(),
1293 Self::Parameter(parameter) => parameter.node(module).parameter.name.range(),
1294 }
1295 }
1296
1297 fn full_range(&self, module: &ParsedModuleRef) -> TextRange {
1298 match self {
1299 Self::VariadicPositionalParameter(parameter) => parameter.node(module).range(),
1300 Self::VariadicKeywordParameter(parameter) => parameter.node(module).range(),
1301 Self::Parameter(parameter) => parameter.node(module).parameter.range(),
1302 }
1303 }
1304
1305 fn category(&self, module: &ParsedModuleRef) -> DefinitionCategory {
1306 match self {
1307 Self::VariadicPositionalParameter(parameter)
1309 | Self::VariadicKeywordParameter(parameter) => {
1310 if parameter.node(module).annotation.is_some() {
1311 DefinitionCategory::DeclarationAndBinding
1312 } else {
1313 DefinitionCategory::Binding
1314 }
1315 }
1316 Self::Parameter(parameter_with_default) => {
1318 if parameter_with_default
1319 .node(module)
1320 .parameter
1321 .annotation
1322 .is_some()
1323 {
1324 DefinitionCategory::DeclarationAndBinding
1325 } else {
1326 DefinitionCategory::Binding
1327 }
1328 }
1329 }
1330 }
1331}
1332
1333#[derive(Clone, Debug, get_size2::GetSize)]
1334pub struct LambdaParameterDefinitionNodeKind {
1335 pub index: u32,
1336 pub lambda: AstNodeRef<ast::ExprLambda>,
1337 pub parameter: ParameterDefinitionNodeKind,
1338}
1339
1340#[derive(Clone, Debug, get_size2::GetSize)]
1341pub struct ImportDefinitionKind {
1342 node: AstNodeRef<ast::StmtImport>,
1343 alias_index: u32,
1344 is_reexported: bool,
1345}
1346
1347impl ImportDefinitionKind {
1348 pub fn import<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::StmtImport {
1349 self.node.node(module)
1350 }
1351
1352 pub fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
1353 &self.node.node(module).names[self.alias_index as usize]
1354 }
1355
1356 fn is_reexported(&self) -> bool {
1357 self.is_reexported
1358 }
1359}
1360
1361#[derive(Clone, Debug, get_size2::GetSize)]
1362pub struct ImportFromDefinitionKind {
1363 node: AstNodeRef<ast::StmtImportFrom>,
1364 alias_index: u32,
1365 is_reexported: bool,
1366}
1367
1368impl ImportFromDefinitionKind {
1369 pub fn import<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::StmtImportFrom {
1370 self.node.node(module)
1371 }
1372
1373 pub fn alias<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Alias {
1374 &self.node.node(module).names[self.alias_index as usize]
1375 }
1376
1377 fn is_reexported(&self) -> bool {
1378 self.is_reexported
1379 }
1380}
1381#[derive(Clone, Debug, get_size2::GetSize)]
1382pub struct ImportFromSubmoduleDefinitionKind {
1383 node: AstNodeRef<ast::StmtImportFrom>,
1384 module_index: u32,
1385}
1386
1387impl ImportFromSubmoduleDefinitionKind {
1388 pub fn import<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::StmtImportFrom {
1389 self.node.node(module)
1390 }
1391
1392 fn module<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Identifier {
1393 self.import(module)
1394 .module
1395 .as_ref()
1396 .expect("import-from submodule definitions should always have a module identifier")
1397 }
1398
1399 fn target_range(&self, module: &ParsedModuleRef) -> TextRange {
1400 let module_ident = self.module(module);
1401 let module_str = module_ident.as_str();
1402
1403 let Some((end_offset, _)) = module_str
1405 .match_indices('.')
1406 .nth(self.module_index as usize)
1407 else {
1408 return module_ident.range();
1410 };
1411
1412 let start_offset = module_str[..end_offset].rfind('.').map_or(0, |pos| pos + 1);
1414
1415 let Ok(start) = TextSize::try_from(start_offset) else {
1416 return module_ident.range();
1417 };
1418 let Ok(end) = TextSize::try_from(end_offset) else {
1419 return module_ident.range();
1420 };
1421 TextRange::new(start, end) + module_ident.start()
1422 }
1423}
1424
1425#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
1426pub struct AssignmentDefinitionKind<'db> {
1427 unpack: Option<Unpack<'db>>,
1428 value: AstNodeRef<ast::Expr>,
1429 target: AstNodeRef<ast::Expr>,
1430}
1431
1432impl<'db> AssignmentDefinitionKind<'db> {
1433 pub fn unpack(&self) -> Option<Unpack<'db>> {
1434 self.unpack
1435 }
1436
1437 pub fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1438 self.value.node(module)
1439 }
1440
1441 pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1442 self.target.node(module)
1443 }
1444}
1445
1446#[derive(Clone, Debug, get_size2::GetSize)]
1447pub struct AnnotatedAssignmentDefinitionKind {
1448 node: AstNodeRef<ast::StmtAnnAssign>,
1449 has_value: bool,
1450}
1451
1452impl AnnotatedAssignmentDefinitionKind {
1453 fn node<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::StmtAnnAssign {
1454 self.node.node(module)
1455 }
1456
1457 pub fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> Option<&'ast ast::Expr> {
1458 self.node(module).value.as_deref()
1459 }
1460
1461 pub const fn has_value(&self) -> bool {
1463 self.has_value
1464 }
1465
1466 pub fn annotation<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1467 &self.node(module).annotation
1468 }
1469
1470 pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1471 &self.node(module).target
1472 }
1473}
1474
1475#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
1476pub struct DictKeyAssignmentKind<'db> {
1477 key: AstNodeRef<ast::Expr>,
1478 value: AstNodeRef<ast::Expr>,
1479 assignment: Definition<'db>,
1480}
1481
1482impl<'db> DictKeyAssignmentKind<'db> {
1483 pub fn key<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1484 self.key.node(module)
1485 }
1486
1487 pub fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1488 self.value.node(module)
1489 }
1490
1491 pub fn assignment(&self) -> Definition<'db> {
1492 self.assignment
1493 }
1494}
1495
1496#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
1497pub struct WithItemDefinitionKind<'db> {
1498 unpack: Option<Unpack<'db>>,
1499 item: AstNodeRef<ast::WithItem>,
1500 target: AstNodeRef<ast::Expr>,
1501 is_async: bool,
1502 unpack_position: UnpackPosition,
1503}
1504
1505impl<'db> WithItemDefinitionKind<'db> {
1506 pub fn context_expr<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1507 &self.item.node(module).context_expr
1508 }
1509
1510 pub fn target_kind(&self) -> TargetKind<'db> {
1511 TargetKind::from_unpack(self.unpack, self.unpack_position)
1512 }
1513
1514 pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1515 self.target.node(module)
1516 }
1517
1518 pub const fn is_async(&self) -> bool {
1519 self.is_async
1520 }
1521}
1522
1523#[derive(Clone, Debug, get_size2::GetSize, salsa::SalsaValue)]
1524pub struct ForStmtDefinitionKind<'db> {
1525 unpack: Option<Unpack<'db>>,
1526 node: AstNodeRef<ast::StmtFor>,
1527 target: AstNodeRef<ast::Expr>,
1528 is_async: bool,
1529 unpack_position: UnpackPosition,
1530}
1531
1532impl<'db> ForStmtDefinitionKind<'db> {
1533 pub fn iterable<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1534 &self.node.node(module).iter
1535 }
1536
1537 pub fn target_kind(&self) -> TargetKind<'db> {
1538 TargetKind::from_unpack(self.unpack, self.unpack_position)
1539 }
1540
1541 pub fn target<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
1542 self.target.node(module)
1543 }
1544
1545 pub const fn is_async(&self) -> bool {
1546 self.is_async
1547 }
1548}
1549
1550#[derive(Clone, Debug, get_size2::GetSize)]
1551pub struct ExceptHandlerDefinitionKind {
1552 handler: AstNodeRef<ast::ExceptHandlerExceptHandler>,
1553 is_star: bool,
1554}
1555
1556impl ExceptHandlerDefinitionKind {
1557 pub fn node<'ast>(
1558 &self,
1559 module: &'ast ParsedModuleRef,
1560 ) -> &'ast ast::ExceptHandlerExceptHandler {
1561 self.handler.node(module)
1562 }
1563
1564 pub fn handled_exceptions<'ast>(
1565 &self,
1566 module: &'ast ParsedModuleRef,
1567 ) -> Option<&'ast ast::Expr> {
1568 self.node(module).type_.as_deref()
1569 }
1570
1571 pub fn is_star(&self) -> bool {
1572 self.is_star
1573 }
1574}
1575
1576#[derive(Clone, Debug, get_size2::GetSize)]
1578pub struct LoopHeaderDefinitionKind {
1579 loop_header_id: LoopHeaderId,
1581 loop_stmt: LoopStmtKind,
1582 place: ScopedPlaceId,
1583}
1584
1585#[derive(Clone, Debug, get_size2::GetSize)]
1586pub(crate) enum LoopStmtKind {
1587 While(AstNodeRef<ast::StmtWhile>),
1588 For(AstNodeRef<ast::StmtFor>),
1589}
1590
1591impl LoopHeaderDefinitionKind {
1592 pub fn loop_header_id(&self) -> LoopHeaderId {
1593 self.loop_header_id
1594 }
1595
1596 pub fn place(&self) -> ScopedPlaceId {
1597 self.place
1598 }
1599
1600 fn range(&self, module: &ParsedModuleRef) -> TextRange {
1601 match &self.loop_stmt {
1602 LoopStmtKind::While(stmt) => stmt.node(module).range(),
1603 LoopStmtKind::For(stmt) => stmt.node(module).range(),
1604 }
1605 }
1606}
1607
1608#[derive(Clone, Debug, get_size2::GetSize)]
1609pub struct NestedBindingsDefinitionKind {
1610 pub name: Name,
1611 pub execution: NestedBindingExecution,
1612 pub nested_declarations: SmallVec<[crate::builder::NestedDeclaration; 1]>,
1616}
1617
1618impl NestedBindingsDefinitionKind {
1619 fn binding_sources<'index, 'db>(
1623 &'index self,
1624 index: &'index SemanticIndex<'db>,
1625 ) -> impl Iterator<Item = (bool, BindingWithConstraintsIterator<'index, 'db>)> + 'index {
1626 self.nested_declarations.iter().filter_map(|declaration| {
1627 debug_assert!(declaration.is_bound);
1628 let symbol = index
1629 .place_table(declaration.file_scope_id)
1630 .symbol_id(&self.name)?;
1631 let use_def = index.use_def_map(declaration.file_scope_id);
1632 let bindings = match self.execution {
1633 NestedBindingExecution::Lazy => use_def.reachable_bindings(symbol.into()),
1634 NestedBindingExecution::Eager => use_def.end_of_scope_bindings(symbol.into()),
1635 };
1636 Some((declaration.is_global(), bindings))
1637 })
1638 }
1639
1640 pub fn visible_binding_sources<'index, 'db>(
1663 &'index self,
1664 index: &'index SemanticIndex<'db>,
1665 scope: FileScopeId,
1666 ) -> impl Iterator<Item = BindingWithConstraintsIterator<'index, 'db>> + 'index {
1667 let symbol_id = index.place_table(scope).symbol_id(&self.name);
1668 let sees_global = symbol_id
1669 .is_some_and(|symbol_id| index.symbol_resolves_to_global_scope(symbol_id, scope));
1670 let sees_nonlocal = !sees_global
1671 && symbol_id.is_some_and(|symbol_id| {
1672 !(index.scope(scope).kind().is_class()
1673 && index.place_table(scope).symbol(symbol_id).is_local())
1674 });
1675
1676 self.binding_sources(index)
1677 .filter_map(move |(is_global, bindings)| {
1678 (if is_global {
1679 sees_global
1680 } else {
1681 sees_nonlocal
1682 })
1683 .then_some(bindings)
1684 })
1685 }
1686}
1687
1688#[derive(Copy, Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
1690pub enum NestedBindingExecution {
1691 Lazy,
1693 Eager,
1695}
1696
1697#[derive(
1698 Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, get_size2::GetSize, salsa::SalsaValue,
1699)]
1700pub struct DefinitionNodeKey(NodeKey);
1701
1702impl DefinitionNodeKey {
1703 pub(crate) fn from_node_ref(node: ast::AnyNodeRef<'_>) -> Self {
1704 match node {
1705 ast::AnyNodeRef::ParameterWithDefault(parameter) => parameter.into(),
1706 _ => Self(NodeKey::from_node(node)),
1707 }
1708 }
1709
1710 pub fn from_assignment(node: &ast::StmtAssign) -> impl Iterator<Item = DefinitionNodeKey> {
1711 node.targets
1712 .iter()
1713 .map(|target| Self(NodeKey::from_node(target)))
1714 }
1715}
1716
1717impl From<&ast::Alias> for DefinitionNodeKey {
1718 fn from(node: &ast::Alias) -> Self {
1719 Self(NodeKey::from_node(node))
1720 }
1721}
1722
1723impl From<&ast::StmtImportFrom> for DefinitionNodeKey {
1724 fn from(node: &ast::StmtImportFrom) -> Self {
1725 Self(NodeKey::from_node(node))
1726 }
1727}
1728
1729impl From<&ast::StmtFunctionDef> for DefinitionNodeKey {
1730 fn from(node: &ast::StmtFunctionDef) -> Self {
1731 Self(NodeKey::from_node(node))
1732 }
1733}
1734
1735impl From<&ast::StmtClassDef> for DefinitionNodeKey {
1736 fn from(node: &ast::StmtClassDef) -> Self {
1737 Self(NodeKey::from_node(node))
1738 }
1739}
1740
1741impl From<&ast::StmtTypeAlias> for DefinitionNodeKey {
1742 fn from(node: &ast::StmtTypeAlias) -> Self {
1743 Self(NodeKey::from_node(node))
1744 }
1745}
1746
1747impl From<&ast::ExprName> for DefinitionNodeKey {
1748 fn from(node: &ast::ExprName) -> Self {
1749 Self(NodeKey::from_node(node))
1750 }
1751}
1752
1753impl From<&ast::ExprAttribute> for DefinitionNodeKey {
1754 fn from(node: &ast::ExprAttribute) -> Self {
1755 Self(NodeKey::from_node(node))
1756 }
1757}
1758
1759impl From<&ast::ExprSubscript> for DefinitionNodeKey {
1760 fn from(node: &ast::ExprSubscript) -> Self {
1761 Self(NodeKey::from_node(node))
1762 }
1763}
1764
1765impl From<&ast::ExprNamed> for DefinitionNodeKey {
1766 fn from(node: &ast::ExprNamed) -> Self {
1767 Self(NodeKey::from_node(node))
1768 }
1769}
1770
1771impl From<&ast::StmtAnnAssign> for DefinitionNodeKey {
1772 fn from(node: &ast::StmtAnnAssign) -> Self {
1773 Self(NodeKey::from_node(node))
1774 }
1775}
1776
1777impl From<&ast::StmtAugAssign> for DefinitionNodeKey {
1778 fn from(node: &ast::StmtAugAssign) -> Self {
1779 Self(NodeKey::from_node(node))
1780 }
1781}
1782
1783impl From<&ast::StmtWhile> for DefinitionNodeKey {
1784 fn from(node: &ast::StmtWhile) -> Self {
1785 Self(NodeKey::from_node(node))
1786 }
1787}
1788
1789impl From<&ast::StmtFor> for DefinitionNodeKey {
1790 fn from(node: &ast::StmtFor) -> Self {
1791 Self(NodeKey::from_node(node))
1792 }
1793}
1794
1795impl From<&ast::Parameter> for DefinitionNodeKey {
1796 fn from(node: &ast::Parameter) -> Self {
1797 Self(NodeKey::from_node(node))
1798 }
1799}
1800
1801impl From<&ast::ParameterWithDefault> for DefinitionNodeKey {
1802 fn from(node: &ast::ParameterWithDefault) -> Self {
1803 Self(NodeKey::from_node(&node.parameter))
1804 }
1805}
1806
1807impl From<ast::AnyParameterRef<'_>> for DefinitionNodeKey {
1808 fn from(value: ast::AnyParameterRef) -> Self {
1809 Self(match value {
1810 ast::AnyParameterRef::Variadic(node) => NodeKey::from_node(node),
1811 ast::AnyParameterRef::NonVariadic(node) => NodeKey::from_node(&node.parameter),
1812 })
1813 }
1814}
1815
1816impl From<&ast::Identifier> for DefinitionNodeKey {
1817 fn from(identifier: &ast::Identifier) -> Self {
1818 Self(NodeKey::from_node(identifier))
1819 }
1820}
1821
1822impl From<&ast::ExceptHandlerExceptHandler> for DefinitionNodeKey {
1823 fn from(handler: &ast::ExceptHandlerExceptHandler) -> Self {
1824 Self(NodeKey::from_node(handler))
1825 }
1826}
1827
1828impl From<&ast::TypeParamTypeVar> for DefinitionNodeKey {
1829 fn from(value: &ast::TypeParamTypeVar) -> Self {
1830 Self(NodeKey::from_node(value))
1831 }
1832}
1833
1834impl From<&ast::TypeParamParamSpec> for DefinitionNodeKey {
1835 fn from(value: &ast::TypeParamParamSpec) -> Self {
1836 Self(NodeKey::from_node(value))
1837 }
1838}
1839
1840impl From<&ast::TypeParamTypeVarTuple> for DefinitionNodeKey {
1841 fn from(value: &ast::TypeParamTypeVarTuple) -> Self {
1842 Self(NodeKey::from_node(value))
1843 }
1844}
1845
1846impl<T> From<&AstNodeRef<T>> for DefinitionNodeKey
1847where
1848 for<'a> &'a T: Into<DefinitionNodeKey>,
1849{
1850 fn from(value: &AstNodeRef<T>) -> Self {
1851 Self(NodeKey::from_node_ref(value))
1852 }
1853}