rubydex 0.4.0-aarch64-linux → 0.4.2-aarch64-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/README.md +9 -14
- data/THIRD_PARTY_LICENSES.html +13 -24
- data/ext/rubydex/definition.c +34 -0
- data/ext/rubydex/definition.h +3 -0
- data/ext/rubydex/diagnostic.c +2 -49
- data/ext/rubydex/extconf.rb +4 -2
- data/ext/rubydex/graph.c +59 -11
- 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/cli/command/dead_code.rb +59 -0
- data/lib/rubydex/cli/command/lint/explain.rb +8 -6
- data/lib/rubydex/cli/command/lint.rb +10 -4
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/linter/rule_loader.rb +1 -1
- data/lib/rubydex/mcp_server/tools/codebase_stats_tool.rb +1 -1
- data/lib/rubydex/mcp_server/tools/find_constant_references_tool.rb +4 -4
- data/lib/rubydex/mcp_server/tools/find_dead_code_candidates_tool.rb +33 -0
- data/lib/rubydex/mcp_server/tools/get_declaration_tool.rb +2 -2
- data/lib/rubydex/mcp_server/tools/get_descendants_tool.rb +4 -4
- data/lib/rubydex/mcp_server/tools/get_file_declarations_tool.rb +2 -2
- data/lib/rubydex/mcp_server/tools/search_declarations_tool.rb +6 -6
- data/lib/rubydex/mcp_server.rb +24 -12
- data/lib/rubydex/rules/dynamic_ancestor.rb +29 -0
- data/lib/rubydex/rules/dynamic_constant_reference.rb +25 -0
- data/lib/rubydex/rules/dynamic_singleton_definition.rb +30 -0
- data/lib/rubydex/rules/invalid_constant_visibility.rb +28 -0
- data/lib/rubydex/rules/invalid_method_visibility.rb +28 -0
- data/lib/rubydex/rules/parse_error.rb +25 -0
- data/lib/rubydex/rules/parse_warning.rb +28 -0
- data/lib/rubydex/rules/top_level_mixin_self.rb +27 -0
- data/lib/rubydex/rules/undefined_constant_visibility_target.rb +27 -0
- data/lib/rubydex/rules/undefined_method_visibility_target.rb +27 -0
- data/lib/rubydex/skill.rb +1 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +2 -0
- data/lib/rubydex_linter/rules/rule_structure.rb +19 -4
- data/rbi/rubydex.rbi +32 -130
- data/rust/Cargo.lock +17 -11
- data/rust/Cargo.toml +3 -0
- data/rust/rubydex/Cargo.toml +6 -2
- data/rust/rubydex/src/bin/generate_ruby_rules.rs +94 -0
- data/rust/rubydex/src/compile_assertions.rs +2 -0
- data/rust/rubydex/src/config.rs +1 -1
- data/rust/rubydex/src/diagnostic.rs +142 -51
- data/rust/rubydex/src/indexing/rbs_indexer.rs +4 -4
- data/rust/rubydex/src/indexing/ruby_indexer.rs +26 -18
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +42 -2
- data/rust/rubydex/src/indexing.rs +6 -6
- data/rust/rubydex/src/listing.rs +12 -12
- data/rust/rubydex/src/model/built_in.rs +1 -1
- data/rust/rubydex/src/model/comment.rs +4 -4
- data/rust/rubydex/src/model/declaration.rs +25 -17
- data/rust/rubydex/src/model/document.rs +11 -11
- data/rust/rubydex/src/model/graph.rs +3 -3
- data/rust/rubydex/src/offset.rs +1 -13
- data/rust/rubydex/src/operation/ruby_builder.rs +29 -19
- data/rust/rubydex/src/query.rs +193 -2
- data/rust/rubydex/src/test_utils/graph_test.rs +2 -2
- data/rust/rubydex/src/test_utils/local_graph_test.rs +13 -6
- data/rust/rubydex-sys/Cargo.toml +2 -2
- data/rust/rubydex-sys/src/definition_api.rs +69 -2
- data/rust/rubydex-sys/src/diagnostic_api.rs +0 -35
- data/rust/rubydex-sys/src/graph_api.rs +193 -45
- data/rust/rubydex-sys/src/name_api.rs +219 -48
- metadata +199 -187
|
@@ -1,42 +1,105 @@
|
|
|
1
1
|
use rubydex::model::{graph::Graph, ids::NameId, name::ParentScope};
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
struct NameTracker<'graph> {
|
|
4
|
+
graph: &'graph mut Graph,
|
|
5
|
+
tracked_name_ids: Vec<NameId>,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
impl<'graph> NameTracker<'graph> {
|
|
9
|
+
fn new(graph: &'graph mut Graph) -> Self {
|
|
10
|
+
Self {
|
|
11
|
+
graph,
|
|
12
|
+
tracked_name_ids: Vec::new(),
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fn track_name(&mut self, string: &str, parent_scope: ParentScope, nesting: Option<NameId>) -> NameId {
|
|
17
|
+
let str_id = self.graph.intern_string(string.to_owned());
|
|
18
|
+
let name_id = self.graph.add_name(str_id, parent_scope, nesting);
|
|
19
|
+
self.tracked_name_ids.push(name_id);
|
|
20
|
+
name_id
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl Drop for NameTracker<'_> {
|
|
25
|
+
fn drop(&mut self) {
|
|
26
|
+
for name_id in self.tracked_name_ids.drain(..) {
|
|
27
|
+
self.graph.untrack_name(name_id);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// A name temporarily tracked in a graph. Dropping this guard undoes every name and string reference-count increment
|
|
33
|
+
/// made while building the name.
|
|
34
|
+
pub struct TrackedName<'graph> {
|
|
35
|
+
tracker: NameTracker<'graph>,
|
|
36
|
+
name_id: NameId,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
impl<'graph> TrackedName<'graph> {
|
|
40
|
+
fn new(tracker: NameTracker<'graph>, name_id: NameId) -> Self {
|
|
41
|
+
TrackedName { tracker, name_id }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[must_use]
|
|
45
|
+
pub fn name_id(&self) -> NameId {
|
|
46
|
+
self.name_id
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#[must_use]
|
|
50
|
+
pub fn graph(&self) -> &Graph {
|
|
51
|
+
&*self.tracker.graph
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub fn graph_mut(&mut self) -> &mut Graph {
|
|
55
|
+
&mut *self.tracker.graph
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// Takes a constant name and nesting names (e.g.: `["Foo", "Bar::Baz", "Qux"]`) and transforms them into a `NameId`,
|
|
60
|
+
/// registering each required part in the graph. The names are untracked when the returned guard is dropped.
|
|
61
|
+
/// Returns `None` if the constant name contains no valid identifier parts (e.g.: `""`, `"::"`, `"Foo::"`).
|
|
62
|
+
pub fn name_from_nesting_names<'graph>(
|
|
63
|
+
graph: &'graph mut Graph,
|
|
8
64
|
const_name: &str,
|
|
9
65
|
nesting: Vec<String>,
|
|
10
|
-
) -> Option<
|
|
66
|
+
) -> Option<TrackedName<'graph>> {
|
|
11
67
|
let mut current_nesting = None;
|
|
12
68
|
let mut current_name = ParentScope::None;
|
|
13
|
-
let mut
|
|
69
|
+
let mut tracker = NameTracker::new(graph);
|
|
14
70
|
|
|
15
71
|
for entry in nesting {
|
|
16
|
-
process_qualified_name(
|
|
17
|
-
graph,
|
|
18
|
-
&entry,
|
|
19
|
-
&mut current_name,
|
|
20
|
-
&mut current_nesting,
|
|
21
|
-
&mut names_to_untrack,
|
|
22
|
-
);
|
|
72
|
+
process_qualified_name(&mut tracker, &entry, current_nesting, &mut current_name);
|
|
23
73
|
current_nesting = current_name.as_ref().copied();
|
|
24
74
|
current_name = ParentScope::None;
|
|
25
75
|
}
|
|
26
76
|
|
|
27
|
-
process_qualified_name(
|
|
28
|
-
graph,
|
|
29
|
-
const_name,
|
|
30
|
-
&mut current_name,
|
|
31
|
-
&mut current_nesting,
|
|
32
|
-
&mut names_to_untrack,
|
|
33
|
-
);
|
|
77
|
+
process_qualified_name(&mut tracker, const_name, current_nesting, &mut current_name);
|
|
34
78
|
|
|
35
79
|
let (ParentScope::Some(name_id) | ParentScope::Attached(name_id)) = current_name else {
|
|
36
80
|
return None;
|
|
37
81
|
};
|
|
38
82
|
|
|
39
|
-
Some((
|
|
83
|
+
Some(TrackedName::new(tracker, name_id))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// Takes a constant name and an existing lexical nesting and transforms them into a `NameId`, registering each required
|
|
87
|
+
/// part in the graph. The names are untracked when the returned guard is dropped.
|
|
88
|
+
pub fn name_from_lexical_nesting<'graph>(
|
|
89
|
+
graph: &'graph mut Graph,
|
|
90
|
+
const_name: &str,
|
|
91
|
+
nesting: Option<NameId>,
|
|
92
|
+
) -> Option<TrackedName<'graph>> {
|
|
93
|
+
let mut current_name = ParentScope::None;
|
|
94
|
+
let mut tracker = NameTracker::new(graph);
|
|
95
|
+
|
|
96
|
+
process_qualified_name(&mut tracker, const_name, nesting, &mut current_name);
|
|
97
|
+
|
|
98
|
+
let (ParentScope::Some(name_id) | ParentScope::Attached(name_id)) = current_name else {
|
|
99
|
+
return None;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
Some(TrackedName::new(tracker, name_id))
|
|
40
103
|
}
|
|
41
104
|
|
|
42
105
|
/// Processes a qualified name (e.g., `"Foo::Bar"` or `"<Foo>"`) by splitting on `"::"` and registering each part in the
|
|
@@ -45,11 +108,10 @@ pub fn nesting_stack_to_name_id(
|
|
|
45
108
|
/// When a singleton is the first part (i.e., `current_name` has no parent), `current_nesting` is used as the attachment
|
|
46
109
|
/// point.
|
|
47
110
|
fn process_qualified_name(
|
|
48
|
-
|
|
111
|
+
tracker: &mut NameTracker<'_>,
|
|
49
112
|
qualified_name: &str,
|
|
113
|
+
current_nesting: Option<NameId>,
|
|
50
114
|
current_name: &mut ParentScope,
|
|
51
|
-
current_nesting: &mut Option<NameId>,
|
|
52
|
-
names_to_untrack: &mut Vec<NameId>,
|
|
53
115
|
) {
|
|
54
116
|
for part in qualified_name.split("::") {
|
|
55
117
|
if part.is_empty() {
|
|
@@ -60,18 +122,16 @@ fn process_qualified_name(
|
|
|
60
122
|
let (parent_scope, nesting_for_part) = if part.starts_with('<') {
|
|
61
123
|
let attached_id = match *current_name {
|
|
62
124
|
ParentScope::Some(id) | ParentScope::Attached(id) => Some(id),
|
|
63
|
-
_ =>
|
|
125
|
+
_ => current_nesting,
|
|
64
126
|
};
|
|
65
127
|
|
|
66
128
|
let attached = attached_id.map_or(ParentScope::None, ParentScope::Attached);
|
|
67
129
|
(attached, attached_id)
|
|
68
130
|
} else {
|
|
69
|
-
(*current_name,
|
|
131
|
+
(*current_name, current_nesting)
|
|
70
132
|
};
|
|
71
133
|
|
|
72
|
-
let
|
|
73
|
-
let name_id = graph.add_name(str_id, parent_scope, nesting_for_part);
|
|
74
|
-
names_to_untrack.push(name_id);
|
|
134
|
+
let name_id = tracker.track_name(part, parent_scope, nesting_for_part);
|
|
75
135
|
*current_name = ParentScope::Some(name_id);
|
|
76
136
|
}
|
|
77
137
|
}
|
|
@@ -86,38 +146,41 @@ mod tests {
|
|
|
86
146
|
fn nesting_is_converted_to_name_id() {
|
|
87
147
|
let mut graph = Graph::new();
|
|
88
148
|
|
|
89
|
-
let
|
|
149
|
+
let tracked_name = name_from_nesting_names(
|
|
90
150
|
&mut graph,
|
|
91
151
|
"Some::CONST",
|
|
92
152
|
vec!["Foo".into(), "Bar::Zip".into(), "Qux".into()],
|
|
93
153
|
)
|
|
94
154
|
.unwrap();
|
|
155
|
+
let name_id = tracked_name.name_id();
|
|
95
156
|
|
|
96
|
-
let const_name = graph.names().get(&name_id).unwrap();
|
|
157
|
+
let const_name = tracked_name.graph().names().get(&name_id).unwrap();
|
|
97
158
|
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
98
159
|
|
|
99
|
-
let some_name =
|
|
160
|
+
let some_name = tracked_name
|
|
161
|
+
.graph()
|
|
100
162
|
.names()
|
|
101
163
|
.get(&const_name.parent_scope().expect("Parent scope should exist"))
|
|
102
164
|
.unwrap();
|
|
103
165
|
assert_eq!(StringId::from("Some"), *some_name.str());
|
|
104
166
|
assert_eq!(const_name.nesting(), some_name.nesting());
|
|
105
167
|
|
|
106
|
-
let qux_name = graph.names().get(&some_name.nesting().unwrap()).unwrap();
|
|
168
|
+
let qux_name = tracked_name.graph().names().get(&some_name.nesting().unwrap()).unwrap();
|
|
107
169
|
assert_eq!(StringId::from("Qux"), *qux_name.str());
|
|
108
170
|
assert!(qux_name.parent_scope().is_none());
|
|
109
171
|
|
|
110
|
-
let zip_name = graph.names().get(&qux_name.nesting().unwrap()).unwrap();
|
|
172
|
+
let zip_name = tracked_name.graph().names().get(&qux_name.nesting().unwrap()).unwrap();
|
|
111
173
|
assert_eq!(StringId::from("Zip"), *zip_name.str());
|
|
112
174
|
|
|
113
|
-
let bar_name =
|
|
175
|
+
let bar_name = tracked_name
|
|
176
|
+
.graph()
|
|
114
177
|
.names()
|
|
115
178
|
.get(&zip_name.parent_scope().expect("Parent scope should exist"))
|
|
116
179
|
.unwrap();
|
|
117
180
|
assert_eq!(StringId::from("Bar"), *bar_name.str());
|
|
118
181
|
assert_eq!(zip_name.nesting(), bar_name.nesting());
|
|
119
182
|
|
|
120
|
-
let foo_name = graph.names().get(&bar_name.nesting().unwrap()).unwrap();
|
|
183
|
+
let foo_name = tracked_name.graph().names().get(&bar_name.nesting().unwrap()).unwrap();
|
|
121
184
|
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
122
185
|
assert!(foo_name.parent_scope().is_none());
|
|
123
186
|
assert!(foo_name.nesting().is_none());
|
|
@@ -127,13 +190,18 @@ mod tests {
|
|
|
127
190
|
fn top_level_reference_is_converted_to_name_id() {
|
|
128
191
|
let mut graph = Graph::new();
|
|
129
192
|
|
|
130
|
-
let
|
|
193
|
+
let tracked_name = name_from_nesting_names(&mut graph, "::CONST", vec!["Foo".into()]).unwrap();
|
|
194
|
+
let name_id = tracked_name.name_id();
|
|
131
195
|
|
|
132
|
-
let const_name = graph.names().get(&name_id).unwrap();
|
|
196
|
+
let const_name = tracked_name.graph().names().get(&name_id).unwrap();
|
|
133
197
|
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
134
198
|
assert!(const_name.parent_scope().is_top_level());
|
|
135
199
|
|
|
136
|
-
let foo_name =
|
|
200
|
+
let foo_name = tracked_name
|
|
201
|
+
.graph()
|
|
202
|
+
.names()
|
|
203
|
+
.get(&const_name.nesting().unwrap())
|
|
204
|
+
.unwrap();
|
|
137
205
|
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
138
206
|
assert!(foo_name.nesting().is_none());
|
|
139
207
|
assert!(foo_name.parent_scope().is_none());
|
|
@@ -143,13 +211,18 @@ mod tests {
|
|
|
143
211
|
fn singleton_class_names_use_attached_parent_scope() {
|
|
144
212
|
let mut graph = Graph::new();
|
|
145
213
|
|
|
146
|
-
let
|
|
214
|
+
let tracked_name = name_from_nesting_names(&mut graph, "CONST", vec!["Foo".into(), "<Foo>".into()]).unwrap();
|
|
215
|
+
let name_id = tracked_name.name_id();
|
|
147
216
|
|
|
148
|
-
let const_name = graph.names().get(&name_id).unwrap();
|
|
217
|
+
let const_name = tracked_name.graph().names().get(&name_id).unwrap();
|
|
149
218
|
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
150
219
|
|
|
151
220
|
// The nesting should be <Foo> with an Attached parent scope
|
|
152
|
-
let singleton_name =
|
|
221
|
+
let singleton_name = tracked_name
|
|
222
|
+
.graph()
|
|
223
|
+
.names()
|
|
224
|
+
.get(&const_name.nesting().unwrap())
|
|
225
|
+
.unwrap();
|
|
153
226
|
assert_eq!(StringId::from("<Foo>"), *singleton_name.str());
|
|
154
227
|
assert!(
|
|
155
228
|
matches!(singleton_name.parent_scope(), ParentScope::Attached(_)),
|
|
@@ -159,7 +232,7 @@ mod tests {
|
|
|
159
232
|
|
|
160
233
|
// The attached parent should be Foo
|
|
161
234
|
let foo_id = singleton_name.parent_scope().expect("Attached should have an id");
|
|
162
|
-
let foo_name = graph.names().get(&foo_id).unwrap();
|
|
235
|
+
let foo_name = tracked_name.graph().names().get(&foo_id).unwrap();
|
|
163
236
|
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
164
237
|
}
|
|
165
238
|
|
|
@@ -167,19 +240,117 @@ mod tests {
|
|
|
167
240
|
fn top_level_nesting_is_converted_to_name_id() {
|
|
168
241
|
let mut graph = Graph::new();
|
|
169
242
|
|
|
170
|
-
let
|
|
243
|
+
let tracked_name = name_from_nesting_names(&mut graph, "CONST", vec!["Foo".into(), "::Bar".into()]).unwrap();
|
|
244
|
+
let name_id = tracked_name.name_id();
|
|
171
245
|
|
|
172
|
-
let const_name = graph.names().get(&name_id).unwrap();
|
|
246
|
+
let const_name = tracked_name.graph().names().get(&name_id).unwrap();
|
|
173
247
|
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
174
248
|
assert!(const_name.parent_scope().is_none());
|
|
175
249
|
|
|
176
|
-
let bar_name =
|
|
250
|
+
let bar_name = tracked_name
|
|
251
|
+
.graph()
|
|
252
|
+
.names()
|
|
253
|
+
.get(&const_name.nesting().unwrap())
|
|
254
|
+
.unwrap();
|
|
177
255
|
assert_eq!(StringId::from("Bar"), *bar_name.str());
|
|
178
256
|
assert!(bar_name.parent_scope().is_top_level());
|
|
179
257
|
|
|
180
|
-
let foo_name = graph.names().get(&bar_name.nesting().unwrap()).unwrap();
|
|
258
|
+
let foo_name = tracked_name.graph().names().get(&bar_name.nesting().unwrap()).unwrap();
|
|
181
259
|
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
182
260
|
assert!(foo_name.parent_scope().is_none());
|
|
183
261
|
assert!(foo_name.nesting().is_none());
|
|
184
262
|
}
|
|
263
|
+
|
|
264
|
+
#[test]
|
|
265
|
+
fn invalid_names_restore_name_and_string_counts() {
|
|
266
|
+
let mut graph = Graph::new();
|
|
267
|
+
let name_count = graph.names().len();
|
|
268
|
+
let string_count = graph.strings().len();
|
|
269
|
+
|
|
270
|
+
assert!(name_from_nesting_names(&mut graph, "", vec!["Foo".into()]).is_none());
|
|
271
|
+
assert_eq!(name_count, graph.names().len());
|
|
272
|
+
assert_eq!(string_count, graph.strings().len());
|
|
273
|
+
|
|
274
|
+
assert!(name_from_nesting_names(&mut graph, "Foo::", vec!["Bar".into()]).is_none());
|
|
275
|
+
assert_eq!(name_count, graph.names().len());
|
|
276
|
+
assert_eq!(string_count, graph.strings().len());
|
|
277
|
+
|
|
278
|
+
assert!(name_from_lexical_nesting(&mut graph, "Foo::", None).is_none());
|
|
279
|
+
assert_eq!(name_count, graph.names().len());
|
|
280
|
+
assert_eq!(string_count, graph.strings().len());
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
#[test]
|
|
284
|
+
fn invalid_name_restores_existing_name_reference_counts() {
|
|
285
|
+
let mut graph = Graph::new();
|
|
286
|
+
let string_id = graph.intern_string("Foo".to_owned());
|
|
287
|
+
let name_id = graph.add_name(string_id, ParentScope::None, None);
|
|
288
|
+
let name_ref_count = graph.names().get(&name_id).unwrap().ref_count();
|
|
289
|
+
let string_ref_count = graph.strings().get(&string_id).unwrap().ref_count();
|
|
290
|
+
|
|
291
|
+
assert!(name_from_nesting_names(&mut graph, "", vec!["Foo".into()]).is_none());
|
|
292
|
+
|
|
293
|
+
assert_eq!(name_ref_count, graph.names().get(&name_id).unwrap().ref_count());
|
|
294
|
+
assert_eq!(string_ref_count, graph.strings().get(&string_id).unwrap().ref_count());
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#[test]
|
|
298
|
+
fn tracker_preserves_duplicate_name_ids() {
|
|
299
|
+
let mut graph = Graph::new();
|
|
300
|
+
let name_count = graph.names().len();
|
|
301
|
+
let string_count = graph.strings().len();
|
|
302
|
+
|
|
303
|
+
{
|
|
304
|
+
let mut tracker = NameTracker::new(&mut graph);
|
|
305
|
+
let first_id = tracker.track_name("Foo", ParentScope::None, None);
|
|
306
|
+
let second_id = tracker.track_name("Foo", ParentScope::None, None);
|
|
307
|
+
|
|
308
|
+
assert_eq!(first_id, second_id);
|
|
309
|
+
assert_eq!(2, tracker.graph.names().get(&first_id).unwrap().ref_count());
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
assert_eq!(name_count, graph.names().len());
|
|
313
|
+
assert_eq!(string_count, graph.strings().len());
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
#[test]
|
|
317
|
+
fn tracked_name_is_untracked_when_scope_ends() {
|
|
318
|
+
let mut graph = Graph::new();
|
|
319
|
+
let name_count = graph.names().len();
|
|
320
|
+
let string_count = graph.strings().len();
|
|
321
|
+
|
|
322
|
+
{
|
|
323
|
+
let tracked_name = name_from_nesting_names(&mut graph, "Bar::CONST", vec!["Foo".into()]).unwrap();
|
|
324
|
+
let name_id = tracked_name.name_id();
|
|
325
|
+
let const_name = tracked_name.graph().names().get(&name_id).unwrap();
|
|
326
|
+
|
|
327
|
+
assert_eq!(
|
|
328
|
+
"CONST",
|
|
329
|
+
tracked_name.graph().strings().get(const_name.str()).unwrap().as_str()
|
|
330
|
+
);
|
|
331
|
+
assert_eq!(name_count + 3, tracked_name.graph().names().len());
|
|
332
|
+
assert_eq!(string_count + 3, tracked_name.graph().strings().len());
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
assert_eq!(name_count, graph.names().len());
|
|
336
|
+
assert_eq!(string_count, graph.strings().len());
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
#[test]
|
|
340
|
+
fn tracked_name_is_untracked_during_unwind() {
|
|
341
|
+
let mut graph = Graph::new();
|
|
342
|
+
let name_count = graph.names().len();
|
|
343
|
+
let string_count = graph.strings().len();
|
|
344
|
+
|
|
345
|
+
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
|
346
|
+
let tracked_name = name_from_nesting_names(&mut graph, "Bar::CONST", vec!["Foo".into()]).unwrap();
|
|
347
|
+
|
|
348
|
+
assert_eq!(name_count + 3, tracked_name.graph().names().len());
|
|
349
|
+
panic!("unwind tracked name");
|
|
350
|
+
}));
|
|
351
|
+
|
|
352
|
+
assert!(result.is_err());
|
|
353
|
+
assert_eq!(name_count, graph.names().len());
|
|
354
|
+
assert_eq!(string_count, graph.strings().len());
|
|
355
|
+
}
|
|
185
356
|
}
|