method-ray 0.1.8 → 0.1.10

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +9 -11
  4. data/{rust → core}/Cargo.toml +1 -1
  5. data/core/src/analyzer/assignments.rs +219 -0
  6. data/{rust → core}/src/analyzer/blocks.rs +0 -50
  7. data/{rust → core}/src/analyzer/calls.rs +3 -32
  8. data/core/src/analyzer/conditionals.rs +190 -0
  9. data/core/src/analyzer/definitions.rs +205 -0
  10. data/core/src/analyzer/dispatch.rs +455 -0
  11. data/core/src/analyzer/exceptions.rs +168 -0
  12. data/{rust → core}/src/analyzer/install.rs +16 -1
  13. data/{rust → core}/src/analyzer/literals.rs +3 -71
  14. data/core/src/analyzer/loops.rs +94 -0
  15. data/{rust → core}/src/analyzer/mod.rs +1 -15
  16. data/core/src/analyzer/operators.rs +79 -0
  17. data/{rust → core}/src/analyzer/parameters.rs +4 -67
  18. data/core/src/analyzer/parentheses.rs +25 -0
  19. data/core/src/analyzer/returns.rs +39 -0
  20. data/core/src/analyzer/super_calls.rs +74 -0
  21. data/{rust → core}/src/analyzer/variables.rs +5 -25
  22. data/{rust → core}/src/checker.rs +0 -13
  23. data/{rust → core}/src/diagnostics/diagnostic.rs +0 -41
  24. data/{rust → core}/src/diagnostics/formatter.rs +0 -38
  25. data/{rust → core}/src/env/box_manager.rs +0 -30
  26. data/{rust → core}/src/env/global_env.rs +67 -80
  27. data/core/src/env/local_env.rs +42 -0
  28. data/core/src/env/method_registry.rs +173 -0
  29. data/core/src/env/scope.rs +299 -0
  30. data/{rust → core}/src/env/vertex_manager.rs +0 -73
  31. data/core/src/graph/box.rs +347 -0
  32. data/{rust → core}/src/graph/change_set.rs +0 -65
  33. data/{rust → core}/src/graph/vertex.rs +0 -69
  34. data/{rust → core}/src/parser.rs +0 -77
  35. data/{rust → core}/src/types.rs +11 -0
  36. data/ext/Cargo.toml +2 -2
  37. data/lib/methodray/binary_locator.rb +2 -2
  38. data/lib/methodray/commands.rb +1 -1
  39. data/lib/methodray/version.rb +1 -1
  40. metadata +58 -56
  41. data/rust/src/analyzer/assignments.rs +0 -152
  42. data/rust/src/analyzer/conditionals.rs +0 -538
  43. data/rust/src/analyzer/definitions.rs +0 -719
  44. data/rust/src/analyzer/dispatch.rs +0 -1137
  45. data/rust/src/analyzer/exceptions.rs +0 -521
  46. data/rust/src/analyzer/loops.rs +0 -176
  47. data/rust/src/analyzer/operators.rs +0 -284
  48. data/rust/src/analyzer/parentheses.rs +0 -113
  49. data/rust/src/analyzer/returns.rs +0 -191
  50. data/rust/src/env/local_env.rs +0 -92
  51. data/rust/src/env/method_registry.rs +0 -268
  52. data/rust/src/env/scope.rs +0 -596
  53. data/rust/src/graph/box.rs +0 -766
  54. /data/{rust → core}/src/analyzer/attributes.rs +0 -0
  55. /data/{rust → core}/src/cache/mod.rs +0 -0
  56. /data/{rust → core}/src/cache/rbs_cache.rs +0 -0
  57. /data/{rust → core}/src/cli/args.rs +0 -0
  58. /data/{rust → core}/src/cli/commands.rs +0 -0
  59. /data/{rust → core}/src/cli/mod.rs +0 -0
  60. /data/{rust → core}/src/diagnostics/mod.rs +0 -0
  61. /data/{rust → core}/src/env/mod.rs +0 -0
  62. /data/{rust → core}/src/env/type_error.rs +0 -0
  63. /data/{rust → core}/src/graph/mod.rs +0 -0
  64. /data/{rust → core}/src/lib.rs +0 -0
  65. /data/{rust → core}/src/lsp/diagnostics.rs +0 -0
  66. /data/{rust → core}/src/lsp/main.rs +0 -0
  67. /data/{rust → core}/src/lsp/mod.rs +0 -0
  68. /data/{rust → core}/src/lsp/server.rs +0 -0
  69. /data/{rust → core}/src/main.rs +0 -0
  70. /data/{rust → core}/src/rbs/converter.rs +0 -0
  71. /data/{rust → core}/src/rbs/error.rs +0 -0
  72. /data/{rust → core}/src/rbs/loader.rs +0 -0
  73. /data/{rust → core}/src/rbs/mod.rs +0 -0
  74. /data/{rust → core}/src/source_map.rs +0 -0
@@ -0,0 +1,299 @@
1
+ use crate::graph::VertexId;
2
+ use std::collections::HashMap;
3
+
4
+ /// Scope ID
5
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6
+ pub struct ScopeId(pub usize);
7
+
8
+ /// Scope kind
9
+ #[derive(Debug, Clone)]
10
+ pub enum ScopeKind {
11
+ TopLevel,
12
+ Class {
13
+ name: String,
14
+ superclass: Option<String>,
15
+ },
16
+ Module {
17
+ name: String,
18
+ },
19
+ Method {
20
+ name: String,
21
+ receiver_type: Option<String>, // Receiver class/module name
22
+ return_vertex: Option<VertexId>, // Merge vertex for return statements
23
+ },
24
+ Block,
25
+ }
26
+
27
+ /// Scope information
28
+ #[derive(Debug, Clone)]
29
+ pub struct Scope {
30
+ pub id: ScopeId,
31
+ pub kind: ScopeKind,
32
+ pub parent: Option<ScopeId>,
33
+
34
+ /// Local variables
35
+ pub local_vars: HashMap<String, VertexId>,
36
+
37
+ /// Instance variables (class/module scope only)
38
+ pub instance_vars: HashMap<String, VertexId>,
39
+
40
+ /// Class variables (class scope only)
41
+ pub class_vars: HashMap<String, VertexId>,
42
+
43
+ /// Constants (simple name → qualified name)
44
+ pub constants: HashMap<String, String>,
45
+ }
46
+
47
+ impl Scope {
48
+ pub fn new(id: ScopeId, kind: ScopeKind, parent: Option<ScopeId>) -> Self {
49
+ Self {
50
+ id,
51
+ kind,
52
+ parent,
53
+ local_vars: HashMap::new(),
54
+ instance_vars: HashMap::new(),
55
+ class_vars: HashMap::new(),
56
+ constants: HashMap::new(),
57
+ }
58
+ }
59
+
60
+ /// Add local variable
61
+ pub fn set_local_var(&mut self, name: String, vtx: VertexId) {
62
+ self.local_vars.insert(name, vtx);
63
+ }
64
+
65
+ /// Get local variable
66
+ pub fn get_local_var(&self, name: &str) -> Option<VertexId> {
67
+ self.local_vars.get(name).copied()
68
+ }
69
+
70
+ /// Add instance variable
71
+ pub fn set_instance_var(&mut self, name: String, vtx: VertexId) {
72
+ self.instance_vars.insert(name, vtx);
73
+ }
74
+
75
+ /// Get instance variable
76
+ pub fn get_instance_var(&self, name: &str) -> Option<VertexId> {
77
+ self.instance_vars.get(name).copied()
78
+ }
79
+ }
80
+
81
+ /// Scope manager
82
+ #[derive(Debug)]
83
+ pub struct ScopeManager {
84
+ scopes: HashMap<ScopeId, Scope>,
85
+ next_id: usize,
86
+ current_scope: ScopeId,
87
+ }
88
+
89
+ impl Default for ScopeManager {
90
+ fn default() -> Self {
91
+ Self::new()
92
+ }
93
+ }
94
+
95
+ impl ScopeManager {
96
+ pub fn new() -> Self {
97
+ let top_level = Scope::new(ScopeId(0), ScopeKind::TopLevel, None);
98
+
99
+ let mut scopes = HashMap::new();
100
+ scopes.insert(ScopeId(0), top_level);
101
+
102
+ Self {
103
+ scopes,
104
+ next_id: 1,
105
+ current_scope: ScopeId(0),
106
+ }
107
+ }
108
+
109
+ /// Create a new scope
110
+ pub fn new_scope(&mut self, kind: ScopeKind) -> ScopeId {
111
+ let id = ScopeId(self.next_id);
112
+ self.next_id += 1;
113
+
114
+ let scope = Scope::new(id, kind, Some(self.current_scope));
115
+ self.scopes.insert(id, scope);
116
+
117
+ id
118
+ }
119
+
120
+ /// Enter a scope
121
+ pub fn enter_scope(&mut self, scope_id: ScopeId) {
122
+ self.current_scope = scope_id;
123
+ }
124
+
125
+ /// Exit current scope
126
+ pub fn exit_scope(&mut self) {
127
+ if let Some(scope) = self.scopes.get(&self.current_scope) {
128
+ if let Some(parent) = scope.parent {
129
+ self.current_scope = parent;
130
+ }
131
+ }
132
+ }
133
+
134
+ /// Get current scope
135
+ pub fn current_scope(&self) -> &Scope {
136
+ self.scopes.get(&self.current_scope).unwrap()
137
+ }
138
+
139
+ /// Get current scope mutably
140
+ pub fn current_scope_mut(&mut self) -> &mut Scope {
141
+ self.scopes.get_mut(&self.current_scope).unwrap()
142
+ }
143
+
144
+ /// Walk scopes from current scope up to the top-level, yielding each scope
145
+ fn walk_scopes(&self) -> impl Iterator<Item = &Scope> + '_ {
146
+ let scopes = &self.scopes;
147
+ let mut current = Some(self.current_scope);
148
+ std::iter::from_fn(move || {
149
+ let scope_id = current?;
150
+ let scope = scopes.get(&scope_id)?;
151
+ current = scope.parent;
152
+ Some(scope)
153
+ })
154
+ }
155
+
156
+ /// Get scope by ID
157
+ pub fn get_scope(&self, id: ScopeId) -> Option<&Scope> {
158
+ self.scopes.get(&id)
159
+ }
160
+
161
+ /// Get scope by ID mutably
162
+ pub fn get_scope_mut(&mut self, id: ScopeId) -> Option<&mut Scope> {
163
+ self.scopes.get_mut(&id)
164
+ }
165
+
166
+ /// Lookup variable in current scope or parent scopes
167
+ pub fn lookup_var(&self, name: &str) -> Option<VertexId> {
168
+ self.walk_scopes().find_map(|scope| scope.get_local_var(name))
169
+ }
170
+
171
+ /// Lookup constant in current scope or parent scopes (simple name → qualified name)
172
+ pub fn lookup_constant(&self, simple_name: &str) -> Option<String> {
173
+ self.walk_scopes()
174
+ .find_map(|scope| scope.constants.get(simple_name).cloned())
175
+ }
176
+
177
+ /// Lookup instance variable in enclosing class scope
178
+ pub fn lookup_instance_var(&self, name: &str) -> Option<VertexId> {
179
+ self.walk_scopes()
180
+ .find(|scope| matches!(&scope.kind, ScopeKind::Class { .. }))
181
+ .and_then(|scope| scope.get_instance_var(name))
182
+ }
183
+
184
+ /// Set instance variable in enclosing class scope
185
+ pub fn set_instance_var_in_class(&mut self, name: String, vtx: VertexId) {
186
+ let class_scope_id = self.walk_scopes()
187
+ .find(|scope| matches!(&scope.kind, ScopeKind::Class { .. }))
188
+ .map(|scope| scope.id);
189
+ if let Some(scope_id) = class_scope_id {
190
+ if let Some(scope) = self.scopes.get_mut(&scope_id) {
191
+ scope.set_instance_var(name, vtx);
192
+ }
193
+ }
194
+ }
195
+
196
+ /// Get current class name (simple name, not qualified)
197
+ pub fn current_class_name(&self) -> Option<String> {
198
+ self.walk_scopes().find_map(|scope| {
199
+ if let ScopeKind::Class { name, .. } = &scope.kind {
200
+ Some(name.clone())
201
+ } else {
202
+ None
203
+ }
204
+ })
205
+ }
206
+
207
+ /// Get current module name (simple name, not qualified)
208
+ pub fn current_module_name(&self) -> Option<String> {
209
+ self.walk_scopes().find_map(|scope| {
210
+ if let ScopeKind::Module { name } = &scope.kind {
211
+ Some(name.clone())
212
+ } else {
213
+ None
214
+ }
215
+ })
216
+ }
217
+
218
+ /// Get current fully qualified name by traversing all parent class/module scopes
219
+ ///
220
+ /// For example, in:
221
+ /// ```ruby
222
+ /// module Api
223
+ /// module V1
224
+ /// class User
225
+ /// def greet; end
226
+ /// end
227
+ /// end
228
+ /// end
229
+ /// ```
230
+ /// When inside `greet`, this returns `Some("Api::V1::User")`
231
+ pub fn current_qualified_name(&self) -> Option<String> {
232
+ let mut path_segments: Vec<&str> = self.walk_scopes()
233
+ .filter_map(|scope| match &scope.kind {
234
+ ScopeKind::Class { name, .. } | ScopeKind::Module { name } => Some(name.as_str()),
235
+ _ => None,
236
+ })
237
+ .collect();
238
+
239
+ if path_segments.is_empty() {
240
+ return None;
241
+ }
242
+
243
+ // Reverse to get from outermost to innermost
244
+ path_segments.reverse();
245
+ Some(path_segments.join("::"))
246
+ }
247
+
248
+ /// Get current method name from nearest enclosing method scope
249
+ pub fn current_method_name(&self) -> Option<String> {
250
+ self.walk_scopes().find_map(|scope| {
251
+ if let ScopeKind::Method { name, .. } = &scope.kind {
252
+ Some(name.clone())
253
+ } else {
254
+ None
255
+ }
256
+ })
257
+ }
258
+
259
+ /// Get superclass name from nearest enclosing class scope
260
+ pub fn current_superclass(&self) -> Option<String> {
261
+ self.walk_scopes().find_map(|scope| {
262
+ if let ScopeKind::Class { superclass, .. } = &scope.kind {
263
+ superclass.clone()
264
+ } else {
265
+ None
266
+ }
267
+ })
268
+ }
269
+
270
+ /// Get return_vertex from the nearest enclosing method scope
271
+ pub fn current_method_return_vertex(&self) -> Option<VertexId> {
272
+ self.walk_scopes().find_map(|scope| {
273
+ if let ScopeKind::Method { return_vertex, .. } = &scope.kind {
274
+ *return_vertex
275
+ } else {
276
+ None
277
+ }
278
+ })
279
+ }
280
+
281
+ /// Lookup instance variable in enclosing module scope
282
+ pub fn lookup_instance_var_in_module(&self, name: &str) -> Option<VertexId> {
283
+ self.walk_scopes()
284
+ .find(|scope| matches!(&scope.kind, ScopeKind::Module { .. }))
285
+ .and_then(|scope| scope.get_instance_var(name))
286
+ }
287
+
288
+ /// Set instance variable in enclosing module scope
289
+ pub fn set_instance_var_in_module(&mut self, name: String, vtx: VertexId) {
290
+ let module_scope_id = self.walk_scopes()
291
+ .find(|scope| matches!(&scope.kind, ScopeKind::Module { .. }))
292
+ .map(|scope| scope.id);
293
+ if let Some(scope_id) = module_scope_id {
294
+ if let Some(scope) = self.scopes.get_mut(&scope_id) {
295
+ scope.set_instance_var(name, vtx);
296
+ }
297
+ }
298
+ }
299
+ }
@@ -119,76 +119,3 @@ impl VertexManager {
119
119
  lines.join("\n")
120
120
  }
121
121
  }
122
-
123
- #[cfg(test)]
124
- mod tests {
125
- use super::*;
126
-
127
- #[test]
128
- fn test_new_vertex() {
129
- let mut manager = VertexManager::new();
130
-
131
- let v1 = manager.new_vertex();
132
- let v2 = manager.new_vertex();
133
-
134
- assert_eq!(v1.0, 0);
135
- assert_eq!(v2.0, 1);
136
- assert!(manager.get_vertex(v1).is_some());
137
- assert!(manager.get_vertex(v2).is_some());
138
- }
139
-
140
- #[test]
141
- fn test_new_source() {
142
- let mut manager = VertexManager::new();
143
-
144
- let s1 = manager.new_source(Type::string());
145
- let s2 = manager.new_source(Type::integer());
146
-
147
- assert_eq!(manager.get_source(s1).unwrap().ty.show(), "String");
148
- assert_eq!(manager.get_source(s2).unwrap().ty.show(), "Integer");
149
- }
150
-
151
- #[test]
152
- fn test_edge_propagation() {
153
- let mut manager = VertexManager::new();
154
-
155
- let src = manager.new_source(Type::string());
156
- let vtx = manager.new_vertex();
157
-
158
- manager.add_edge(src, vtx);
159
-
160
- assert_eq!(manager.get_vertex(vtx).unwrap().show(), "String");
161
- }
162
-
163
- #[test]
164
- fn test_chain_propagation() {
165
- let mut manager = VertexManager::new();
166
-
167
- let src = manager.new_source(Type::string());
168
- let v1 = manager.new_vertex();
169
- let v2 = manager.new_vertex();
170
-
171
- manager.add_edge(src, v1);
172
- manager.add_edge(v1, v2);
173
-
174
- assert_eq!(manager.get_vertex(v1).unwrap().show(), "String");
175
- assert_eq!(manager.get_vertex(v2).unwrap().show(), "String");
176
- }
177
-
178
- #[test]
179
- fn test_union_propagation() {
180
- let mut manager = VertexManager::new();
181
-
182
- let src1 = manager.new_source(Type::string());
183
- let src2 = manager.new_source(Type::integer());
184
- let vtx = manager.new_vertex();
185
-
186
- manager.add_edge(src1, vtx);
187
- manager.add_edge(src2, vtx);
188
-
189
- assert_eq!(
190
- manager.get_vertex(vtx).unwrap().show(),
191
- "(Integer | String)"
192
- );
193
- }
194
- }