rubydex 0.1.0.beta1-x86_64-linux → 0.1.0.beta2-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/rubydex/declaration.c +146 -0
- data/ext/rubydex/declaration.h +10 -0
- data/ext/rubydex/definition.c +234 -0
- data/ext/rubydex/definition.h +28 -0
- data/ext/rubydex/diagnostic.c +6 -0
- data/ext/rubydex/diagnostic.h +11 -0
- data/ext/rubydex/document.c +98 -0
- data/ext/rubydex/document.h +10 -0
- data/ext/rubydex/extconf.rb +36 -15
- data/ext/rubydex/graph.c +405 -0
- data/ext/rubydex/graph.h +10 -0
- data/ext/rubydex/handle.h +44 -0
- data/ext/rubydex/location.c +22 -0
- data/ext/rubydex/location.h +15 -0
- data/ext/rubydex/reference.c +104 -0
- data/ext/rubydex/reference.h +16 -0
- data/ext/rubydex/rubydex.c +22 -0
- data/ext/rubydex/utils.c +27 -0
- data/ext/rubydex/utils.h +13 -0
- data/lib/rubydex/3.2/rubydex.so +0 -0
- data/lib/rubydex/3.3/rubydex.so +0 -0
- data/lib/rubydex/3.4/rubydex.so +0 -0
- data/lib/rubydex/4.0/rubydex.so +0 -0
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/version.rb +1 -1
- data/rust/Cargo.lock +1275 -0
- data/rust/Cargo.toml +23 -0
- data/rust/about.hbs +78 -0
- data/rust/about.toml +9 -0
- data/rust/rubydex/Cargo.toml +41 -0
- data/rust/rubydex/src/diagnostic.rs +108 -0
- data/rust/rubydex/src/errors.rs +28 -0
- data/rust/rubydex/src/indexing/local_graph.rs +172 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +5397 -0
- data/rust/rubydex/src/indexing.rs +128 -0
- data/rust/rubydex/src/job_queue.rs +186 -0
- data/rust/rubydex/src/lib.rs +15 -0
- data/rust/rubydex/src/listing.rs +249 -0
- data/rust/rubydex/src/main.rs +116 -0
- data/rust/rubydex/src/model/comment.rs +24 -0
- data/rust/rubydex/src/model/declaration.rs +541 -0
- data/rust/rubydex/src/model/definitions.rs +1475 -0
- data/rust/rubydex/src/model/document.rs +111 -0
- data/rust/rubydex/src/model/encoding.rs +22 -0
- data/rust/rubydex/src/model/graph.rs +1387 -0
- data/rust/rubydex/src/model/id.rs +90 -0
- data/rust/rubydex/src/model/identity_maps.rs +54 -0
- data/rust/rubydex/src/model/ids.rs +32 -0
- data/rust/rubydex/src/model/name.rs +188 -0
- data/rust/rubydex/src/model/references.rs +129 -0
- data/rust/rubydex/src/model/string_ref.rs +44 -0
- data/rust/rubydex/src/model/visibility.rs +41 -0
- data/rust/rubydex/src/model.rs +13 -0
- data/rust/rubydex/src/offset.rs +70 -0
- data/rust/rubydex/src/position.rs +6 -0
- data/rust/rubydex/src/query.rs +103 -0
- data/rust/rubydex/src/resolution.rs +4421 -0
- data/rust/rubydex/src/stats/memory.rs +71 -0
- data/rust/rubydex/src/stats/timer.rs +126 -0
- data/rust/rubydex/src/stats.rs +9 -0
- data/rust/rubydex/src/test_utils/context.rs +226 -0
- data/rust/rubydex/src/test_utils/graph_test.rs +229 -0
- data/rust/rubydex/src/test_utils/local_graph_test.rs +166 -0
- data/rust/rubydex/src/test_utils.rs +52 -0
- data/rust/rubydex/src/visualization/dot.rs +176 -0
- data/rust/rubydex/src/visualization.rs +6 -0
- data/rust/rubydex/tests/cli.rs +167 -0
- data/rust/rubydex-sys/Cargo.toml +20 -0
- data/rust/rubydex-sys/build.rs +14 -0
- data/rust/rubydex-sys/cbindgen.toml +12 -0
- data/rust/rubydex-sys/src/declaration_api.rs +114 -0
- data/rust/rubydex-sys/src/definition_api.rs +350 -0
- data/rust/rubydex-sys/src/diagnostic_api.rs +99 -0
- data/rust/rubydex-sys/src/document_api.rs +54 -0
- data/rust/rubydex-sys/src/graph_api.rs +493 -0
- data/rust/rubydex-sys/src/lib.rs +9 -0
- data/rust/rubydex-sys/src/location_api.rs +79 -0
- data/rust/rubydex-sys/src/name_api.rs +81 -0
- data/rust/rubydex-sys/src/reference_api.rs +191 -0
- data/rust/rubydex-sys/src/utils.rs +50 -0
- data/rust/rustfmt.toml +2 -0
- metadata +77 -2
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
use crate::offset::Offset;
|
|
2
|
+
|
|
3
|
+
#[derive(Debug, Clone)]
|
|
4
|
+
pub struct Comment {
|
|
5
|
+
offset: Offset,
|
|
6
|
+
string: String,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
impl Comment {
|
|
10
|
+
#[must_use]
|
|
11
|
+
pub fn new(offset: Offset, string: String) -> Self {
|
|
12
|
+
Self { offset, string }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[must_use]
|
|
16
|
+
pub fn offset(&self) -> &Offset {
|
|
17
|
+
&self.offset
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[must_use]
|
|
21
|
+
pub fn string(&self) -> &String {
|
|
22
|
+
&self.string
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
use crate::diagnostic::Diagnostic;
|
|
2
|
+
use crate::model::{
|
|
3
|
+
identity_maps::{IdentityHashMap, IdentityHashSet},
|
|
4
|
+
ids::{DeclarationId, DefinitionId, NameId, ReferenceId, StringId},
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/// A single ancestor in the linearized ancestor chain
|
|
8
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
9
|
+
pub enum Ancestor {
|
|
10
|
+
/// A complete ancestor that we have fully linearized
|
|
11
|
+
Complete(DeclarationId),
|
|
12
|
+
/// A partial ancestor that is missing linearization
|
|
13
|
+
Partial(NameId),
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// The ancestor chain and its current state
|
|
17
|
+
#[derive(Debug, Clone)]
|
|
18
|
+
pub enum Ancestors {
|
|
19
|
+
/// A complete linearization of ancestors with all parts resolved
|
|
20
|
+
Complete(Vec<Ancestor>),
|
|
21
|
+
/// A cyclic linearization of ancestors (e.g.: a module that includes itself)
|
|
22
|
+
Cyclic(Vec<Ancestor>),
|
|
23
|
+
/// A partial linearization of ancestors with some parts unresolved. This chain state always triggers retries
|
|
24
|
+
Partial(Vec<Ancestor>),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
impl Ancestors {
|
|
28
|
+
pub fn iter(&self) -> std::slice::Iter<'_, Ancestor> {
|
|
29
|
+
match self {
|
|
30
|
+
Ancestors::Complete(ancestors) | Ancestors::Partial(ancestors) | Ancestors::Cyclic(ancestors) => {
|
|
31
|
+
ancestors.iter()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[must_use]
|
|
37
|
+
pub fn to_partial(self) -> Self {
|
|
38
|
+
match self {
|
|
39
|
+
Ancestors::Complete(ancestors) | Ancestors::Cyclic(ancestors) | Ancestors::Partial(ancestors) => {
|
|
40
|
+
Ancestors::Partial(ancestors)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
impl<'a> IntoIterator for &'a Ancestors {
|
|
47
|
+
type Item = &'a Ancestor;
|
|
48
|
+
type IntoIter = std::slice::Iter<'a, Ancestor>;
|
|
49
|
+
|
|
50
|
+
fn into_iter(self) -> Self::IntoIter {
|
|
51
|
+
self.iter()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
macro_rules! all_declarations {
|
|
56
|
+
($value:expr, $var:ident => $expr:expr) => {
|
|
57
|
+
match $value {
|
|
58
|
+
Declaration::Namespace(Namespace::Class($var)) => $expr,
|
|
59
|
+
Declaration::Namespace(Namespace::Module($var)) => $expr,
|
|
60
|
+
Declaration::Namespace(Namespace::SingletonClass($var)) => $expr,
|
|
61
|
+
Declaration::Constant($var) => $expr,
|
|
62
|
+
Declaration::ConstantAlias($var) => $expr,
|
|
63
|
+
Declaration::Method($var) => $expr,
|
|
64
|
+
Declaration::GlobalVariable($var) => $expr,
|
|
65
|
+
Declaration::InstanceVariable($var) => $expr,
|
|
66
|
+
Declaration::ClassVariable($var) => $expr,
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
macro_rules! all_namespaces {
|
|
72
|
+
($value:expr, $var:ident => $expr:expr) => {
|
|
73
|
+
match $value {
|
|
74
|
+
Namespace::Class($var) => $expr,
|
|
75
|
+
Namespace::Module($var) => $expr,
|
|
76
|
+
Namespace::SingletonClass($var) => $expr,
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Macro to generate a new struct for namespace-like declarations such as classes and modules
|
|
82
|
+
macro_rules! namespace_declaration {
|
|
83
|
+
($variant:ident, $name:ident) => {
|
|
84
|
+
#[derive(Debug)]
|
|
85
|
+
pub struct $name {
|
|
86
|
+
/// The fully qualified name of this declaration
|
|
87
|
+
name: String,
|
|
88
|
+
/// The list of definition IDs that compose this declaration
|
|
89
|
+
definition_ids: Vec<DefinitionId>,
|
|
90
|
+
/// The set of references that are made to this declaration
|
|
91
|
+
references: IdentityHashSet<ReferenceId>,
|
|
92
|
+
/// The ID of the owner of this declaration. For singleton classes, this is the ID of the attached object
|
|
93
|
+
owner_id: DeclarationId,
|
|
94
|
+
/// The entities that are owned by this declaration. For example, constants and methods that are defined inside of
|
|
95
|
+
/// the namespace. Note that this is a hashmap of unqualified name IDs to declaration IDs. That assists the
|
|
96
|
+
/// traversal of the graph when trying to resolve constant references or trying to discover which methods exist in a
|
|
97
|
+
/// class
|
|
98
|
+
members: IdentityHashMap<StringId, DeclarationId>,
|
|
99
|
+
/// The linearized ancestor chain for this declaration. These are the other declarations that this
|
|
100
|
+
/// declaration inherits from
|
|
101
|
+
ancestors: Ancestors,
|
|
102
|
+
/// The set of declarations that inherit from this declaration
|
|
103
|
+
descendants: IdentityHashSet<DeclarationId>,
|
|
104
|
+
/// The singleton class associated with this declaration
|
|
105
|
+
singleton_class_id: Option<DeclarationId>,
|
|
106
|
+
/// Diagnostics associated with this declaration
|
|
107
|
+
diagnostics: Vec<Diagnostic>,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
impl $name {
|
|
111
|
+
#[must_use]
|
|
112
|
+
pub fn new(name: String, owner_id: DeclarationId) -> Self {
|
|
113
|
+
Self {
|
|
114
|
+
name,
|
|
115
|
+
definition_ids: Vec::new(),
|
|
116
|
+
members: IdentityHashMap::default(),
|
|
117
|
+
references: IdentityHashSet::default(),
|
|
118
|
+
owner_id,
|
|
119
|
+
ancestors: Ancestors::Partial(Vec::new()),
|
|
120
|
+
descendants: IdentityHashSet::default(),
|
|
121
|
+
singleton_class_id: None,
|
|
122
|
+
diagnostics: Vec::new(),
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub fn extend(&mut self, mut other: Namespace) {
|
|
127
|
+
self.definition_ids.extend(other.definitions());
|
|
128
|
+
self.references.extend(other.references());
|
|
129
|
+
self.members.extend(other.members());
|
|
130
|
+
self.diagnostics.extend(other.take_diagnostics());
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
|
|
134
|
+
self.singleton_class_id = Some(declaration_id);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
pub fn singleton_class_id(&self) -> Option<&DeclarationId> {
|
|
138
|
+
self.singleton_class_id.as_ref()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
#[must_use]
|
|
142
|
+
pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
|
|
143
|
+
&self.members
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
pub fn add_member(&mut self, string_id: StringId, declaration_id: DeclarationId) {
|
|
147
|
+
self.members.insert(string_id, declaration_id);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
pub fn remove_member(&mut self, string_id: &StringId) -> Option<DeclarationId> {
|
|
151
|
+
self.members.remove(string_id)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[must_use]
|
|
155
|
+
pub fn member(&self, string_id: &StringId) -> Option<&DeclarationId> {
|
|
156
|
+
self.members.get(string_id)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
pub fn set_ancestors(&mut self, ancestors: Ancestors) {
|
|
160
|
+
self.ancestors = ancestors;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
pub fn ancestors(&self) -> &Ancestors {
|
|
164
|
+
&self.ancestors
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
pub fn ancestors_mut(&mut self) -> &mut Ancestors {
|
|
168
|
+
&mut self.ancestors
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#[must_use]
|
|
172
|
+
pub fn clone_ancestors(&self) -> Ancestors {
|
|
173
|
+
self.ancestors.clone()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
#[must_use]
|
|
177
|
+
pub fn has_complete_ancestors(&self) -> bool {
|
|
178
|
+
matches!(&self.ancestors, Ancestors::Complete(_) | Ancestors::Cyclic(_))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
|
|
182
|
+
self.descendants.insert(descendant_id);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
fn remove_descendant(&mut self, descendant_id: &DeclarationId) {
|
|
186
|
+
self.descendants.remove(descendant_id);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
pub fn clear_descendants(&mut self) {
|
|
190
|
+
self.descendants.clear();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
pub fn descendants(&self) -> &IdentityHashSet<DeclarationId> {
|
|
194
|
+
&self.descendants
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/// Macro to generate a new struct for simple declarations like variables and methods
|
|
201
|
+
macro_rules! simple_declaration {
|
|
202
|
+
($name:ident) => {
|
|
203
|
+
#[derive(Debug)]
|
|
204
|
+
pub struct $name {
|
|
205
|
+
/// The fully qualified name of this declaration
|
|
206
|
+
name: String,
|
|
207
|
+
/// The list of definition IDs that compose this declaration
|
|
208
|
+
definition_ids: Vec<DefinitionId>,
|
|
209
|
+
/// The set of references that are made to this declaration
|
|
210
|
+
references: IdentityHashSet<ReferenceId>,
|
|
211
|
+
/// The ID of the owner of this declaration
|
|
212
|
+
owner_id: DeclarationId,
|
|
213
|
+
/// Diagnostics associated with this declaration
|
|
214
|
+
diagnostics: Vec<Diagnostic>,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
impl $name {
|
|
218
|
+
#[must_use]
|
|
219
|
+
pub fn new(name: String, owner_id: DeclarationId) -> Self {
|
|
220
|
+
Self {
|
|
221
|
+
name,
|
|
222
|
+
definition_ids: Vec::new(),
|
|
223
|
+
references: IdentityHashSet::default(),
|
|
224
|
+
owner_id,
|
|
225
|
+
diagnostics: Vec::new(),
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
pub fn extend(&mut self, mut other: Declaration) {
|
|
230
|
+
self.definition_ids.extend(other.definitions());
|
|
231
|
+
self.references.extend(other.references());
|
|
232
|
+
self.diagnostics.extend(other.take_diagnostics());
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/// A `Declaration` represents the global concept of an entity in Ruby. For example, the class `Foo` may be defined 3
|
|
239
|
+
/// times in different files and the `Foo` declaration is the combination of all of those definitions that contribute to
|
|
240
|
+
/// the same fully qualified name
|
|
241
|
+
#[derive(Debug)]
|
|
242
|
+
pub enum Declaration {
|
|
243
|
+
Namespace(Namespace),
|
|
244
|
+
Constant(Box<ConstantDeclaration>),
|
|
245
|
+
ConstantAlias(Box<ConstantAliasDeclaration>),
|
|
246
|
+
Method(Box<MethodDeclaration>),
|
|
247
|
+
GlobalVariable(Box<GlobalVariableDeclaration>),
|
|
248
|
+
InstanceVariable(Box<InstanceVariableDeclaration>),
|
|
249
|
+
ClassVariable(Box<ClassVariableDeclaration>),
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
impl Declaration {
|
|
253
|
+
#[must_use]
|
|
254
|
+
pub fn name(&self) -> &str {
|
|
255
|
+
all_declarations!(self, it => &it.name)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#[must_use]
|
|
259
|
+
pub fn kind(&self) -> &'static str {
|
|
260
|
+
match self {
|
|
261
|
+
Declaration::Namespace(namespace) => namespace.kind(),
|
|
262
|
+
Declaration::Constant(_) => "Constant",
|
|
263
|
+
Declaration::ConstantAlias(_) => "ConstantAlias",
|
|
264
|
+
Declaration::Method(_) => "Method",
|
|
265
|
+
Declaration::GlobalVariable(_) => "GlobalVariable",
|
|
266
|
+
Declaration::InstanceVariable(_) => "InstanceVariable",
|
|
267
|
+
Declaration::ClassVariable(_) => "ClassVariable",
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
#[must_use]
|
|
272
|
+
pub fn as_namespace(&self) -> Option<&Namespace> {
|
|
273
|
+
match self {
|
|
274
|
+
Declaration::Namespace(namespace) => Some(namespace),
|
|
275
|
+
_ => None,
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#[must_use]
|
|
280
|
+
pub fn as_namespace_mut(&mut self) -> Option<&mut Namespace> {
|
|
281
|
+
match self {
|
|
282
|
+
Declaration::Namespace(namespace) => Some(namespace),
|
|
283
|
+
_ => None,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
#[must_use]
|
|
288
|
+
pub fn references(&self) -> &IdentityHashSet<ReferenceId> {
|
|
289
|
+
all_declarations!(self, it => &it.references)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
#[must_use]
|
|
293
|
+
pub fn definitions(&self) -> &[DefinitionId] {
|
|
294
|
+
all_declarations!(self, it => &it.definition_ids)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#[must_use]
|
|
298
|
+
pub fn has_no_definitions(&self) -> bool {
|
|
299
|
+
all_declarations!(self, it => it.definition_ids.is_empty())
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
pub fn add_definition(&mut self, definition_id: DefinitionId) {
|
|
303
|
+
all_declarations!(self, it => {
|
|
304
|
+
debug_assert!(
|
|
305
|
+
!it.definition_ids.contains(&definition_id),
|
|
306
|
+
"Cannot add the same exact definition to a declaration twice. Duplicate definition IDs"
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
it.definition_ids.push(definition_id);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
pub fn add_reference(&mut self, id: ReferenceId) {
|
|
314
|
+
all_declarations!(self, it => {
|
|
315
|
+
it.references.insert(id);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
pub fn remove_reference(&mut self, reference_id: &ReferenceId) {
|
|
320
|
+
all_declarations!(self, it => {
|
|
321
|
+
it.references.remove(reference_id);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Deletes a definition from this declaration
|
|
326
|
+
pub fn remove_definition(&mut self, definition_id: &DefinitionId) -> bool {
|
|
327
|
+
all_declarations!(self, it => {
|
|
328
|
+
if let Some(pos) = it.definition_ids.iter().position(|id| id == definition_id) {
|
|
329
|
+
it.definition_ids.swap_remove(pos);
|
|
330
|
+
it.definition_ids.shrink_to_fit();
|
|
331
|
+
true
|
|
332
|
+
} else {
|
|
333
|
+
false
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
#[must_use]
|
|
339
|
+
pub fn owner_id(&self) -> &DeclarationId {
|
|
340
|
+
all_declarations!(self, it => &it.owner_id)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Splits the fully qualified name either in the last `::` or the `#` to return the simple name of this declaration
|
|
344
|
+
#[must_use]
|
|
345
|
+
pub fn unqualified_name(&self) -> String {
|
|
346
|
+
all_declarations!(self, it => {
|
|
347
|
+
let after_colons = it.name.rsplit("::").next().unwrap_or(&it.name);
|
|
348
|
+
after_colons.rsplit('#').next().unwrap_or(after_colons).to_string()
|
|
349
|
+
})
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
#[must_use]
|
|
353
|
+
pub fn diagnostics(&self) -> &[Diagnostic] {
|
|
354
|
+
all_declarations!(self, it => &it.diagnostics)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
|
|
358
|
+
all_declarations!(self, it => std::mem::take(&mut it.diagnostics))
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
pub fn add_diagnostic(&mut self, diagnostic: Diagnostic) {
|
|
362
|
+
all_declarations!(self, it => it.diagnostics.push(diagnostic));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
pub fn clear_diagnostics(&mut self) {
|
|
366
|
+
all_declarations!(self, it => it.diagnostics.clear());
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
#[derive(Debug)]
|
|
371
|
+
pub enum Namespace {
|
|
372
|
+
Class(Box<ClassDeclaration>),
|
|
373
|
+
SingletonClass(Box<SingletonClassDeclaration>),
|
|
374
|
+
Module(Box<ModuleDeclaration>),
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
impl Namespace {
|
|
378
|
+
#[must_use]
|
|
379
|
+
pub fn kind(&self) -> &'static str {
|
|
380
|
+
match self {
|
|
381
|
+
Namespace::Class(_) => "Class",
|
|
382
|
+
Namespace::SingletonClass(_) => "SingletonClass",
|
|
383
|
+
Namespace::Module(_) => "Module",
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
#[must_use]
|
|
388
|
+
pub fn references(&self) -> &IdentityHashSet<ReferenceId> {
|
|
389
|
+
all_namespaces!(self, it => &it.references)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
#[must_use]
|
|
393
|
+
pub fn definitions(&self) -> &[DefinitionId] {
|
|
394
|
+
all_namespaces!(self, it => &it.definition_ids)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
#[must_use]
|
|
398
|
+
pub fn members(&self) -> &IdentityHashMap<StringId, DeclarationId> {
|
|
399
|
+
all_namespaces!(self, it => &it.members)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
#[must_use]
|
|
403
|
+
pub fn diagnostics(&self) -> &[Diagnostic] {
|
|
404
|
+
all_namespaces!(self, it => &it.diagnostics)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
|
|
408
|
+
all_namespaces!(self, it => std::mem::take(&mut it.diagnostics))
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/// # Panics
|
|
412
|
+
///
|
|
413
|
+
/// Panics if the declaration is not a namespace or a constant
|
|
414
|
+
#[must_use]
|
|
415
|
+
pub fn ancestors(&self) -> Ancestors {
|
|
416
|
+
all_namespaces!(self, it => it.clone_ancestors())
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
pub fn set_ancestors(&mut self, ancestors: Ancestors) {
|
|
420
|
+
all_namespaces!(self, it => it.set_ancestors(ancestors));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
#[must_use]
|
|
424
|
+
pub fn has_complete_ancestors(&self) -> bool {
|
|
425
|
+
all_namespaces!(self, it => it.has_complete_ancestors())
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
pub fn add_descendant(&mut self, descendant_id: DeclarationId) {
|
|
429
|
+
all_namespaces!(self, it => it.add_descendant(descendant_id));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
pub fn remove_descendant(&mut self, descendant_id: &DeclarationId) {
|
|
433
|
+
all_namespaces!(self, it => it.remove_descendant(descendant_id));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
pub fn for_each_ancestor<F>(&self, mut f: F)
|
|
437
|
+
where
|
|
438
|
+
F: FnMut(&Ancestor),
|
|
439
|
+
{
|
|
440
|
+
all_namespaces!(self, it => it.ancestors().iter().for_each(&mut f));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
pub fn for_each_descendant<F>(&self, mut f: F)
|
|
444
|
+
where
|
|
445
|
+
F: FnMut(&DeclarationId),
|
|
446
|
+
{
|
|
447
|
+
all_namespaces!(self, it => it.descendants().iter().for_each(&mut f));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
pub fn clear_ancestors(&mut self) {
|
|
451
|
+
all_namespaces!(self, it => it.set_ancestors(Ancestors::Partial(vec![])));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
pub fn clear_descendants(&mut self) {
|
|
455
|
+
all_namespaces!(self, it => it.clear_descendants());
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
#[must_use]
|
|
459
|
+
pub fn member(&self, str_id: &StringId) -> Option<&DeclarationId> {
|
|
460
|
+
all_namespaces!(self, it => it.member(str_id))
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
#[must_use]
|
|
464
|
+
pub fn singleton_class(&self) -> Option<&DeclarationId> {
|
|
465
|
+
all_namespaces!(self, it => it.singleton_class_id())
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
pub fn set_singleton_class_id(&mut self, declaration_id: DeclarationId) {
|
|
469
|
+
all_namespaces!(self, it => it.set_singleton_class_id(declaration_id));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
namespace_declaration!(Class, ClassDeclaration);
|
|
474
|
+
namespace_declaration!(Module, ModuleDeclaration);
|
|
475
|
+
namespace_declaration!(SingletonClass, SingletonClassDeclaration);
|
|
476
|
+
simple_declaration!(ConstantDeclaration);
|
|
477
|
+
simple_declaration!(MethodDeclaration);
|
|
478
|
+
simple_declaration!(GlobalVariableDeclaration);
|
|
479
|
+
simple_declaration!(InstanceVariableDeclaration);
|
|
480
|
+
simple_declaration!(ClassVariableDeclaration);
|
|
481
|
+
simple_declaration!(ConstantAliasDeclaration);
|
|
482
|
+
|
|
483
|
+
#[cfg(test)]
|
|
484
|
+
mod tests {
|
|
485
|
+
use super::*;
|
|
486
|
+
|
|
487
|
+
#[test]
|
|
488
|
+
#[should_panic(expected = "Cannot add the same exact definition to a declaration twice. Duplicate definition IDs")]
|
|
489
|
+
fn inserting_duplicate_definitions() {
|
|
490
|
+
let mut decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
|
|
491
|
+
"MyDecl".to_string(),
|
|
492
|
+
DeclarationId::from("Object"),
|
|
493
|
+
))));
|
|
494
|
+
let def_id = DefinitionId::new(123);
|
|
495
|
+
|
|
496
|
+
// The second call will panic because we're adding the same exact ID twice
|
|
497
|
+
decl.add_definition(def_id);
|
|
498
|
+
decl.add_definition(def_id);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
#[test]
|
|
502
|
+
fn adding_and_removing_members() {
|
|
503
|
+
let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
|
|
504
|
+
"Foo".to_string(),
|
|
505
|
+
DeclarationId::from("Object"),
|
|
506
|
+
))));
|
|
507
|
+
let member_name_id = StringId::from("Bar");
|
|
508
|
+
let member_decl_id = DeclarationId::from("Foo::Bar");
|
|
509
|
+
|
|
510
|
+
let Declaration::Namespace(Namespace::Class(mut class)) = decl else {
|
|
511
|
+
panic!("Expected a class declaration");
|
|
512
|
+
};
|
|
513
|
+
class.add_member(member_name_id, member_decl_id);
|
|
514
|
+
assert_eq!(class.members.len(), 1);
|
|
515
|
+
|
|
516
|
+
let removed = class.remove_member(&member_name_id);
|
|
517
|
+
assert_eq!(removed, Some(member_decl_id));
|
|
518
|
+
assert_eq!(class.members.len(), 0);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
#[test]
|
|
522
|
+
fn unqualified_name() {
|
|
523
|
+
let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
|
|
524
|
+
"Foo".to_string(),
|
|
525
|
+
DeclarationId::from("Foo"),
|
|
526
|
+
))));
|
|
527
|
+
assert_eq!(decl.unqualified_name(), "Foo");
|
|
528
|
+
|
|
529
|
+
let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
|
|
530
|
+
"Foo::Bar".to_string(),
|
|
531
|
+
DeclarationId::from("Foo"),
|
|
532
|
+
))));
|
|
533
|
+
assert_eq!(decl.unqualified_name(), "Bar");
|
|
534
|
+
|
|
535
|
+
let decl = Declaration::Namespace(Namespace::Class(Box::new(ClassDeclaration::new(
|
|
536
|
+
"Foo::Bar#baz".to_string(),
|
|
537
|
+
DeclarationId::from("Foo::Bar"),
|
|
538
|
+
))));
|
|
539
|
+
assert_eq!(decl.unqualified_name(), "baz");
|
|
540
|
+
}
|
|
541
|
+
}
|