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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +9 -11
- data/core/Cargo.toml +1 -1
- data/core/src/analyzer/assignments.rs +0 -280
- data/core/src/analyzer/blocks.rs +0 -190
- data/core/src/analyzer/calls.rs +3 -32
- data/core/src/analyzer/conditionals.rs +0 -348
- data/core/src/analyzer/definitions.rs +11 -526
- data/core/src/analyzer/dispatch.rs +54 -1000
- data/core/src/analyzer/exceptions.rs +0 -454
- data/core/src/analyzer/literals.rs +0 -54
- data/core/src/analyzer/loops.rs +0 -207
- data/core/src/analyzer/mod.rs +0 -15
- data/core/src/analyzer/operators.rs +0 -205
- data/core/src/analyzer/parameters.rs +4 -227
- data/core/src/analyzer/parentheses.rs +0 -88
- data/core/src/analyzer/returns.rs +0 -152
- data/core/src/analyzer/super_calls.rs +1 -212
- data/core/src/analyzer/variables.rs +5 -25
- data/core/src/checker.rs +0 -13
- data/core/src/diagnostics/diagnostic.rs +0 -41
- data/core/src/diagnostics/formatter.rs +0 -38
- data/core/src/env/box_manager.rs +0 -30
- data/core/src/env/global_env.rs +52 -79
- data/core/src/env/local_env.rs +0 -50
- data/core/src/env/method_registry.rs +52 -233
- data/core/src/env/scope.rs +0 -375
- data/core/src/env/vertex_manager.rs +0 -73
- data/core/src/graph/box.rs +20 -439
- data/core/src/graph/change_set.rs +0 -65
- data/core/src/graph/vertex.rs +0 -69
- data/core/src/parser.rs +0 -77
- data/ext/Cargo.toml +1 -1
- data/lib/methodray/version.rb +1 -1
- metadata +5 -4
|
@@ -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
|
-
}
|
data/core/src/env/box_manager.rs
CHANGED
|
@@ -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
|
-
}
|