method-ray 0.1.9 → 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.
@@ -37,155 +37,3 @@ pub(crate) fn process_return_node(
37
37
 
38
38
  None
39
39
  }
40
-
41
- #[cfg(test)]
42
- mod tests {
43
- use crate::env::{GlobalEnv, LocalEnv};
44
- use crate::graph::ChangeSet;
45
- use crate::parser::ParseSession;
46
- use crate::types::Type;
47
-
48
- fn setup_and_infer(source: &str) -> GlobalEnv {
49
- let session = ParseSession::new();
50
- let parse_result = session.parse_source(source, "test.rb").unwrap();
51
- let root = parse_result.node();
52
- let program = root.as_program_node().unwrap();
53
-
54
- let mut genv = GlobalEnv::new();
55
- let mut lenv = LocalEnv::new();
56
- let mut changes = ChangeSet::new();
57
-
58
- for stmt in &program.statements().body() {
59
- crate::analyzer::install::install_node(
60
- &mut genv, &mut lenv, &mut changes, source, &stmt,
61
- );
62
- }
63
-
64
- genv.apply_changes(changes);
65
- genv.run_all();
66
- genv
67
- }
68
-
69
- fn get_return_type(genv: &GlobalEnv, class_name: &str, method_name: &str) -> String {
70
- let info = genv
71
- .resolve_method(&Type::instance(class_name), method_name)
72
- .unwrap_or_else(|| panic!("{}#{} should be registered", class_name, method_name));
73
- let vtx = info
74
- .return_vertex
75
- .expect("return_vertex should be Some");
76
-
77
- if let Some(source) = genv.get_source(vtx) {
78
- source.ty.show()
79
- } else if let Some(vertex) = genv.get_vertex(vtx) {
80
- vertex.show()
81
- } else {
82
- panic!("return_vertex not found");
83
- }
84
- }
85
-
86
- #[test]
87
- fn test_simple_return() {
88
- let source = r#"
89
- class Foo
90
- def bar
91
- return "hello"
92
- end
93
- end
94
- "#;
95
- let genv = setup_and_infer(source);
96
- assert_eq!(get_return_type(&genv, "Foo", "bar"), "String");
97
- }
98
-
99
- #[test]
100
- fn test_return_with_implicit_return_union() {
101
- let source = r#"
102
- class Foo
103
- def bar
104
- return "hello" if true
105
- 42
106
- end
107
- end
108
- "#;
109
- let genv = setup_and_infer(source);
110
- let ty = get_return_type(&genv, "Foo", "bar");
111
- assert!(ty.contains("Integer"), "should contain Integer, got: {}", ty);
112
- assert!(ty.contains("String"), "should contain String, got: {}", ty);
113
- }
114
-
115
- #[test]
116
- fn test_multiple_returns() {
117
- let source = r#"
118
- class Foo
119
- def bar
120
- return "a" if true
121
- return :b if false
122
- 42
123
- end
124
- end
125
- "#;
126
- let genv = setup_and_infer(source);
127
- let ty = get_return_type(&genv, "Foo", "bar");
128
- assert!(ty.contains("Integer"), "should contain Integer, got: {}", ty);
129
- assert!(ty.contains("String"), "should contain String, got: {}", ty);
130
- assert!(ty.contains("Symbol"), "should contain Symbol, got: {}", ty);
131
- }
132
-
133
- #[test]
134
- fn test_return_without_value() {
135
- let source = r#"
136
- class Foo
137
- def bar
138
- return if true
139
- 42
140
- end
141
- end
142
- "#;
143
- let genv = setup_and_infer(source);
144
- let ty = get_return_type(&genv, "Foo", "bar");
145
- assert!(ty.contains("Integer"), "should contain Integer, got: {}", ty);
146
- assert!(ty.contains("nil"), "should contain nil, got: {}", ty);
147
- }
148
-
149
- #[test]
150
- fn test_no_return_backward_compat() {
151
- let source = r#"
152
- class Foo
153
- def bar
154
- "hello"
155
- end
156
- end
157
- "#;
158
- let genv = setup_and_infer(source);
159
- assert_eq!(get_return_type(&genv, "Foo", "bar"), "String");
160
- }
161
-
162
- #[test]
163
- fn test_return_only_method() {
164
- let source = r#"
165
- class Foo
166
- def bar
167
- return "hello"
168
- end
169
- end
170
- "#;
171
- let genv = setup_and_infer(source);
172
- assert_eq!(get_return_type(&genv, "Foo", "bar"), "String");
173
- }
174
-
175
- #[test]
176
- fn test_return_dead_code_over_approximation() {
177
- let source = r#"
178
- class Foo
179
- def bar
180
- return "hello"
181
- 42
182
- end
183
- end
184
- "#;
185
- let genv = setup_and_infer(source);
186
- let ty = get_return_type(&genv, "Foo", "bar");
187
- // Dead code after return is still processed (over-approximation)
188
- assert!(ty.contains("Integer"), "should contain Integer (dead code), got: {}", ty);
189
- assert!(ty.contains("String"), "should contain String, got: {}", ty);
190
- }
191
- }
@@ -69,217 +69,6 @@ fn process_super_call(
69
69
  arg_vtxs,
70
70
  kw,
71
71
  Some(location),
72
+ false, // super calls cannot use safe navigation
72
73
  ))
73
74
  }
74
-
75
- #[cfg(test)]
76
- mod tests {
77
- use crate::analyzer::install::AstInstaller;
78
- use crate::env::{GlobalEnv, LocalEnv};
79
- use crate::graph::VertexId;
80
- use crate::parser::ParseSession;
81
- use crate::types::Type;
82
-
83
- /// Helper: parse Ruby source, process with AstInstaller, and return GlobalEnv
84
- fn analyze(source: &str) -> GlobalEnv {
85
- let session = ParseSession::new();
86
- let parse_result = session.parse_source(source, "test.rb").unwrap();
87
- let root = parse_result.node();
88
- let program = root.as_program_node().unwrap();
89
-
90
- let mut genv = GlobalEnv::new();
91
- let mut lenv = LocalEnv::new();
92
-
93
- let mut installer = AstInstaller::new(&mut genv, &mut lenv, source);
94
- for stmt in &program.statements().body() {
95
- installer.install_node(&stmt);
96
- }
97
- installer.finish();
98
-
99
- genv
100
- }
101
-
102
- /// Helper: get the type string for a vertex ID
103
- fn get_type_show(genv: &GlobalEnv, vtx: VertexId) -> String {
104
- if let Some(vertex) = genv.get_vertex(vtx) {
105
- vertex.show()
106
- } else if let Some(source) = genv.get_source(vtx) {
107
- source.ty.show()
108
- } else {
109
- panic!("vertex {:?} not found as either Vertex or Source", vtx);
110
- }
111
- }
112
-
113
- #[test]
114
- fn test_super_basic() {
115
- let source = r#"
116
- class Animal
117
- def speak
118
- "..."
119
- end
120
- end
121
-
122
- class Dog < Animal
123
- def speak
124
- super
125
- end
126
- end
127
- "#;
128
- let genv = analyze(source);
129
- let info = genv
130
- .resolve_method(&Type::instance("Dog"), "speak")
131
- .expect("Dog#speak should be registered");
132
- let ret_vtx = info.return_vertex.unwrap();
133
- assert_eq!(get_type_show(&genv, ret_vtx), "String");
134
- }
135
-
136
- #[test]
137
- fn test_super_with_method_chain() {
138
- let source = r#"
139
- class Animal
140
- def speak
141
- "hello"
142
- end
143
- end
144
-
145
- class Dog < Animal
146
- def speak
147
- super.upcase
148
- end
149
- end
150
- "#;
151
- let genv = analyze(source);
152
- let info = genv
153
- .resolve_method(&Type::instance("Dog"), "speak")
154
- .expect("Dog#speak should be registered");
155
- assert!(info.return_vertex.is_some());
156
- }
157
-
158
- #[test]
159
- fn test_super_with_arguments() {
160
- let source = r#"
161
- class Base
162
- def greet(name)
163
- name
164
- end
165
- end
166
-
167
- class Child < Base
168
- def greet(name)
169
- super(name)
170
- end
171
- end
172
-
173
- Child.new.greet("Alice")
174
- "#;
175
- let genv = analyze(source);
176
- let info = genv
177
- .resolve_method(&Type::instance("Child"), "greet")
178
- .expect("Child#greet should be registered");
179
- let ret_vtx = info.return_vertex.unwrap();
180
- assert_eq!(get_type_show(&genv, ret_vtx), "String");
181
- }
182
-
183
- #[test]
184
- fn test_super_outside_method_ignored() {
185
- let source = r#"
186
- class Foo < Object
187
- super
188
- end
189
- "#;
190
- analyze(source);
191
- }
192
-
193
- #[test]
194
- fn test_super_explicit_empty_args() {
195
- let source = r#"
196
- class Animal
197
- def speak
198
- "hello"
199
- end
200
- end
201
-
202
- class Dog < Animal
203
- def speak
204
- super()
205
- end
206
- end
207
- "#;
208
- let genv = analyze(source);
209
- let info = genv
210
- .resolve_method(&Type::instance("Dog"), "speak")
211
- .expect("Dog#speak should be registered");
212
- let ret_vtx = info.return_vertex.unwrap();
213
- assert_eq!(get_type_show(&genv, ret_vtx), "String");
214
- }
215
-
216
- #[test]
217
- fn test_super_without_superclass_ignored() {
218
- let source = r#"
219
- class Foo
220
- def bar
221
- super
222
- end
223
- end
224
- "#;
225
- let genv = analyze(source);
226
- let info = genv
227
- .resolve_method(&Type::instance("Foo"), "bar")
228
- .expect("Foo#bar should be registered");
229
- assert!(info.return_vertex.is_some());
230
- }
231
-
232
- #[test]
233
- fn test_super_qualified_superclass() {
234
- let source = r#"
235
- module Animals
236
- class Pet
237
- def name
238
- "pet"
239
- end
240
- end
241
- end
242
-
243
- class Dog < Animals::Pet
244
- def name
245
- super
246
- end
247
- end
248
- "#;
249
- let genv = analyze(source);
250
- let info = genv
251
- .resolve_method(&Type::instance("Dog"), "name")
252
- .expect("Dog#name should be registered");
253
- let ret_vtx = info.return_vertex.unwrap();
254
- assert_eq!(get_type_show(&genv, ret_vtx), "String");
255
- }
256
-
257
- #[test]
258
- fn test_super_multi_level_inheritance() {
259
- let source = r#"
260
- class A
261
- def foo
262
- "hello"
263
- end
264
- end
265
-
266
- class B < A
267
- def foo
268
- super
269
- end
270
- end
271
-
272
- class C < B
273
- def foo
274
- super
275
- end
276
- end
277
- "#;
278
- let genv = analyze(source);
279
- let info = genv
280
- .resolve_method(&Type::instance("C"), "foo")
281
- .expect("C#foo should be registered");
282
- let ret_vtx = info.return_vertex.unwrap();
283
- assert_eq!(get_type_show(&genv, ret_vtx), "String");
284
- }
285
- }
@@ -10,7 +10,7 @@ use crate::graph::{ChangeSet, VertexId};
10
10
  use crate::types::Type;
11
11
 
12
12
  /// Install local variable write: x = value
13
- pub fn install_local_var_write(
13
+ pub(crate) fn install_local_var_write(
14
14
  genv: &mut GlobalEnv,
15
15
  lenv: &mut LocalEnv,
16
16
  changes: &mut ChangeSet,
@@ -24,7 +24,7 @@ pub fn install_local_var_write(
24
24
  }
25
25
 
26
26
  /// Install local variable read: x
27
- pub fn install_local_var_read(lenv: &LocalEnv, var_name: &str) -> Option<VertexId> {
27
+ pub(crate) fn install_local_var_read(lenv: &LocalEnv, var_name: &str) -> Option<VertexId> {
28
28
  lenv.get_var(var_name)
29
29
  }
30
30
 
@@ -33,7 +33,7 @@ pub fn install_local_var_read(lenv: &LocalEnv, var_name: &str) -> Option<VertexI
33
33
  /// If @name already has a pre-allocated VertexId (e.g., from attr_reader),
34
34
  /// an edge is added from value_vtx to the existing vertex so types propagate.
35
35
  /// Otherwise, value_vtx is registered directly as the ivar's VertexId.
36
- pub fn install_ivar_write(
36
+ pub(crate) fn install_ivar_write(
37
37
  genv: &mut GlobalEnv,
38
38
  ivar_name: String,
39
39
  value_vtx: VertexId,
@@ -49,36 +49,16 @@ pub fn install_ivar_write(
49
49
  }
50
50
 
51
51
  /// Install instance variable read: @name
52
- pub fn install_ivar_read(genv: &GlobalEnv, ivar_name: &str) -> Option<VertexId> {
52
+ pub(crate) fn install_ivar_read(genv: &GlobalEnv, ivar_name: &str) -> Option<VertexId> {
53
53
  genv.scope_manager.lookup_instance_var(ivar_name)
54
54
  }
55
55
 
56
56
  /// Install self node
57
57
  /// Uses the fully qualified name if available (e.g., Api::V1::User instead of just User)
58
- pub fn install_self(genv: &mut GlobalEnv) -> VertexId {
58
+ pub(crate) fn install_self(genv: &mut GlobalEnv) -> VertexId {
59
59
  if let Some(qualified_name) = genv.scope_manager.current_qualified_name() {
60
60
  genv.new_source(Type::instance(&qualified_name))
61
61
  } else {
62
62
  genv.new_source(Type::instance("Object"))
63
63
  }
64
64
  }
65
-
66
- #[cfg(test)]
67
- mod tests {
68
- use super::*;
69
-
70
- #[test]
71
- fn test_install_self_at_top_level() {
72
- let mut genv = GlobalEnv::new();
73
-
74
- let vtx = install_self(&mut genv);
75
- assert_eq!(genv.get_source(vtx).unwrap().ty.show(), "Object");
76
- }
77
-
78
- #[test]
79
- fn test_local_var_read_not_found() {
80
- let lenv = LocalEnv::new();
81
-
82
- assert_eq!(install_local_var_read(&lenv, "unknown"), None);
83
- }
84
- }
data/core/src/checker.rs CHANGED
@@ -134,16 +134,3 @@ fn collect_diagnostics(genv: &GlobalEnv, file_path: &Path) -> Vec<Diagnostic> {
134
134
 
135
135
  diagnostics
136
136
  }
137
-
138
- #[cfg(test)]
139
- mod tests {
140
- use super::*;
141
-
142
- #[test]
143
- fn test_file_checker_creation() {
144
- // This test will fail if RBS cache doesn't exist
145
- // That's expected - cache should be generated from Ruby side first
146
- let result = FileChecker::new();
147
- assert!(result.is_ok() || result.is_err()); // Just check it doesn't panic
148
- }
149
- }
@@ -79,44 +79,3 @@ impl Diagnostic {
79
79
  Self::warning(location, message)
80
80
  }
81
81
  }
82
-
83
- #[cfg(test)]
84
- mod tests {
85
- use super::*;
86
-
87
- #[test]
88
- fn test_diagnostic_creation() {
89
- let loc = Location {
90
- file: PathBuf::from("test.rb"),
91
- line: 10,
92
- column: 5,
93
- length: None,
94
- };
95
-
96
- let diag = Diagnostic::undefined_method(loc.clone(), "Integer", "upcase");
97
- assert_eq!(diag.level, DiagnosticLevel::Error);
98
- assert_eq!(diag.message, "undefined method `upcase` for Integer");
99
- }
100
-
101
- #[test]
102
- fn test_union_partial_error() {
103
- let loc = Location {
104
- file: PathBuf::from("test.rb"),
105
- line: 15,
106
- column: 3,
107
- length: None,
108
- };
109
-
110
- let diag = Diagnostic::union_partial_error(
111
- loc,
112
- vec!["String".to_string()],
113
- vec!["Integer".to_string()],
114
- "upcase",
115
- );
116
-
117
- assert_eq!(diag.level, DiagnosticLevel::Warning);
118
- assert!(diag
119
- .message
120
- .contains("method `upcase` is defined for String but not for Integer"));
121
- }
122
- }
@@ -78,41 +78,3 @@ pub fn format_diagnostics_with_file(diagnostics: &[Diagnostic], file_path: &Path
78
78
  Err(_) => format_diagnostics(diagnostics), // Fallback to simple format
79
79
  }
80
80
  }
81
-
82
- #[cfg(test)]
83
- mod tests {
84
- use super::*;
85
- use crate::diagnostics::diagnostic::{Diagnostic, Location};
86
- use std::path::PathBuf;
87
-
88
- #[test]
89
- fn test_format_diagnostics() {
90
- let diagnostics = vec![
91
- Diagnostic::undefined_method(
92
- Location {
93
- file: PathBuf::from("test.rb"),
94
- line: 10,
95
- column: 5,
96
- length: None,
97
- },
98
- "Integer",
99
- "upcase",
100
- ),
101
- Diagnostic::union_partial_error(
102
- Location {
103
- file: PathBuf::from("test.rb"),
104
- line: 15,
105
- column: 3,
106
- length: None,
107
- },
108
- vec!["String".to_string()],
109
- vec!["Integer".to_string()],
110
- "upcase",
111
- ),
112
- ];
113
-
114
- let output = format_diagnostics(&diagnostics);
115
- assert!(output.contains("test.rb:10:5: error:"));
116
- assert!(output.contains("test.rb:15:3: warning:"));
117
- }
118
- }
@@ -87,33 +87,3 @@ impl BoxManager {
87
87
  self.boxes.is_empty()
88
88
  }
89
89
  }
90
-
91
- #[cfg(test)]
92
- mod tests {
93
- use super::*;
94
-
95
- #[test]
96
- fn test_add_run_prevents_duplicates() {
97
- let mut manager = BoxManager::new();
98
-
99
- let id = BoxId(0);
100
- manager.add_run(id);
101
- manager.add_run(id); // Should be ignored
102
-
103
- assert_eq!(manager.run_queue.len(), 1);
104
- }
105
-
106
- #[test]
107
- fn test_pop_run() {
108
- let mut manager = BoxManager::new();
109
-
110
- let id1 = BoxId(0);
111
- let id2 = BoxId(1);
112
- manager.add_run(id1);
113
- manager.add_run(id2);
114
-
115
- assert_eq!(manager.pop_run(), Some(id1));
116
- assert_eq!(manager.pop_run(), Some(id2));
117
- assert_eq!(manager.pop_run(), None);
118
- }
119
- }