ty_python_core/
ast_ids.rs1use rustc_hash::FxHashMap;
2
3use ruff_index::{IndexVec, newtype_index};
4use ruff_python_ast as ast;
5use ruff_python_ast::ExprRef;
6
7use crate::Db;
8use crate::ProgramFile;
9use crate::frozen::FrozenMap;
10use crate::scope::FileScopeId;
11use crate::semantic_index;
12
13pub use node_key::ExpressionNodeKey;
14
15#[derive(Debug, get_size2::GetSize)]
30pub(crate) struct AstIds {
31 uses_map: FrozenMap<ExpressionNodeKey, ScopedUseId>,
33}
34
35impl AstIds {
36 pub(super) fn from_builders(builders: IndexVec<FileScopeId, AstIdsBuilder>) -> Self {
37 let capacity = builders.iter().map(|builder| builder.uses_map.len()).sum();
38 let mut uses_map = Vec::with_capacity(capacity);
39
40 for builder in builders {
41 uses_map.extend(builder.uses_map);
42 }
43
44 let uses_map = FrozenMap::from_entries(uses_map);
45 debug_assert!(
46 uses_map.keys().is_sorted_by(|left, right| left < right),
47 "AST ID builders must contain disjoint keys"
48 );
49
50 Self { uses_map }
51 }
52
53 fn use_id(&self, key: impl Into<ExpressionNodeKey>) -> ScopedUseId {
54 self.uses_map[&key.into()]
55 }
56}
57
58fn ast_ids<'db>(db: &'db dyn Db, file: ProgramFile<'db>) -> &'db AstIds {
59 semantic_index(db, file).ast_ids()
60}
61
62#[newtype_index]
64#[derive(Ord, PartialOrd, get_size2::GetSize)]
65pub struct ScopedUseId;
66
67pub trait HasScopedUseId {
68 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId;
70}
71
72impl HasScopedUseId for ast::Identifier {
73 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId {
74 let ast_ids = ast_ids(db, file);
75 ast_ids.use_id(self)
76 }
77}
78
79impl HasScopedUseId for ast::ExprName {
80 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId {
81 let expression_ref = ExprRef::from(self);
82 expression_ref.scoped_use_id(db, file)
83 }
84}
85
86impl HasScopedUseId for ast::ExprAttribute {
87 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId {
88 let expression_ref = ExprRef::from(self);
89 expression_ref.scoped_use_id(db, file)
90 }
91}
92
93impl HasScopedUseId for ast::ExprSubscript {
94 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId {
95 let expression_ref = ExprRef::from(self);
96 expression_ref.scoped_use_id(db, file)
97 }
98}
99
100impl HasScopedUseId for ast::Keyword {
101 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId {
102 let ast_ids = ast_ids(db, file);
103 ast_ids.use_id(self)
104 }
105}
106
107impl HasScopedUseId for ast::ExprRef<'_> {
108 fn scoped_use_id(&self, db: &dyn Db, file: ProgramFile<'_>) -> ScopedUseId {
109 let ast_ids = ast_ids(db, file);
110 ast_ids.use_id(*self)
111 }
112}
113
114#[derive(Debug, Default)]
115pub(super) struct AstIdsBuilder {
116 uses_map: FxHashMap<ExpressionNodeKey, ScopedUseId>,
117}
118
119impl AstIdsBuilder {
120 pub(super) fn record_use(&mut self, expr: impl Into<ExpressionNodeKey>) -> ScopedUseId {
122 let use_id = self.uses_map.len().into();
123 self.uses_map.insert(expr.into(), use_id);
124 use_id
125 }
126
127 pub(super) fn try_use_id(&self, key: impl Into<ExpressionNodeKey>) -> Option<ScopedUseId> {
128 self.uses_map.get(&key.into()).copied()
129 }
130}
131
132pub(crate) mod node_key {
134 use ruff_python_ast as ast;
135
136 use crate::{ast_node_ref::AstNodeRef, node_key::NodeKey};
137
138 #[derive(
139 Copy,
140 Clone,
141 Eq,
142 PartialEq,
143 Ord,
144 PartialOrd,
145 Hash,
146 Debug,
147 get_size2::GetSize,
148 salsa::SalsaValue,
149 )]
150 pub struct ExpressionNodeKey(NodeKey);
151
152 impl From<ast::ExprRef<'_>> for ExpressionNodeKey {
153 fn from(value: ast::ExprRef<'_>) -> Self {
154 Self(NodeKey::from_node(value))
155 }
156 }
157
158 impl From<&ast::Expr> for ExpressionNodeKey {
159 fn from(value: &ast::Expr) -> Self {
160 Self(NodeKey::from_node(value))
161 }
162 }
163
164 impl From<&Box<ast::Expr>> for ExpressionNodeKey {
165 fn from(value: &Box<ast::Expr>) -> Self {
166 Self(NodeKey::from_node(&**value))
167 }
168 }
169
170 impl From<&ast::ExprCall> for ExpressionNodeKey {
171 fn from(value: &ast::ExprCall) -> Self {
172 Self(NodeKey::from_node(value))
173 }
174 }
175
176 impl From<&ast::ExprLambda> for ExpressionNodeKey {
177 fn from(value: &ast::ExprLambda) -> Self {
178 Self(NodeKey::from_node(value))
179 }
180 }
181
182 impl From<&ast::Identifier> for ExpressionNodeKey {
183 fn from(value: &ast::Identifier) -> Self {
184 Self(NodeKey::from_node(value))
185 }
186 }
187
188 impl From<&ast::Keyword> for ExpressionNodeKey {
189 fn from(value: &ast::Keyword) -> Self {
190 Self(NodeKey::from_node(value))
191 }
192 }
193
194 impl<T> From<&AstNodeRef<T>> for ExpressionNodeKey {
195 fn from(value: &AstNodeRef<T>) -> Self {
196 Self(NodeKey::from_node_ref(value))
197 }
198 }
199}