aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2018-12-23 11:05:54 +0000
committerFlorian Diebold <[email protected]>2018-12-23 12:48:04 +0000
commit7348f7883fa2bd571fff036c82e98c102d05c362 (patch)
treee7882097498b6d85e631d570dac0d8a89cd24875 /crates/ra_hir
parent3899898d75176ce3cd87f9e2acecd7e3a987dda5 (diff)
Add testing infrastructure for type inference
- move dir_tests to test_utils for that.
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/mock.rs9
-rw-r--r--crates/ra_hir/src/ty.rs30
-rw-r--r--crates/ra_hir/src/ty/tests.rs62
-rw-r--r--crates/ra_hir/src/ty/tests/data/0001_basics.rs11
-rw-r--r--crates/ra_hir/src/ty/tests/data/0001_basics.txt13
5 files changed, 102 insertions, 23 deletions
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index a9fa540d5..3020ee793 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -24,6 +24,15 @@ impl MockDatabase {
24 (db, source_root) 24 (db, source_root)
25 } 25 }
26 26
27 pub(crate) fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) {
28 let mut db = MockDatabase::default();
29 let mut source_root = SourceRoot::default();
30 let file_id = db.add_file(&mut source_root, "/main.rs", text);
31 db.query_mut(ra_db::SourceRootQuery)
32 .set(WORKSPACE, Arc::new(source_root.clone()));
33 (db, source_root, file_id)
34 }
35
27 pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { 36 pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) {
28 let (db, _, position) = MockDatabase::from_fixture(fixture); 37 let (db, _, position) = MockDatabase::from_fixture(fixture);
29 let position = position.expect("expected a marker ( <|> )"); 38 let position = position.expect("expected a marker ( <|> )");
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 087385b98..66b204dcd 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -6,6 +6,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
6 6
7use std::sync::Arc; 7use std::sync::Arc;
8use std::collections::HashMap; 8use std::collections::HashMap;
9use std::fmt;
9 10
10use ra_db::LocalSyntaxPtr; 11use ra_db::LocalSyntaxPtr;
11use ra_syntax::{ 12use ra_syntax::{
@@ -184,11 +185,40 @@ impl Ty {
184 } 185 }
185} 186}
186 187
188impl fmt::Display for Ty {
189 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190 match self {
191 Ty::Bool => write!(f, "bool"),
192 Ty::Char => write!(f, "char"),
193 Ty::Int(t) => write!(f, "{}", t.ty_to_string()),
194 Ty::Uint(t) => write!(f, "{}", t.ty_to_string()),
195 Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
196 Ty::Str => write!(f, "str"),
197 Ty::Slice(t) => write!(f, "[{}]", t),
198 Ty::Never => write!(f, "!"),
199 Ty::Tuple(ts) => {
200 write!(f, "(")?;
201 for t in ts {
202 write!(f, "{},", t)?;
203 }
204 write!(f, ")")
205 }
206 Ty::Unknown => write!(f, "[unknown]")
207 }
208 }
209}
210
187#[derive(Clone, PartialEq, Eq, Debug)] 211#[derive(Clone, PartialEq, Eq, Debug)]
188pub struct InferenceResult { 212pub struct InferenceResult {
189 type_for: FxHashMap<LocalSyntaxPtr, Ty>, 213 type_for: FxHashMap<LocalSyntaxPtr, Ty>,
190} 214}
191 215
216impl InferenceResult {
217 pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> {
218 self.type_for.get(&LocalSyntaxPtr::new(node)).cloned()
219 }
220}
221
192#[derive(Clone, PartialEq, Eq, Debug)] 222#[derive(Clone, PartialEq, Eq, Debug)]
193pub struct InferenceContext { 223pub struct InferenceContext {
194 scopes: Arc<FnScopes>, 224 scopes: Arc<FnScopes>,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index f2466dd51..98eedaa3f 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1,8 +1,11 @@
1use std::fmt::Write;
1use std::sync::Arc; 2use std::sync::Arc;
3use std::path::{Path, PathBuf};
2 4
3use salsa::Database; 5use salsa::Database;
4use ra_db::{FilesDatabase, CrateGraph, SyntaxDatabase}; 6use ra_db::{FilesDatabase, CrateGraph, SyntaxDatabase};
5use ra_syntax::{SmolStr, algo::visit::{visitor, Visitor}, ast::{self, AstNode}}; 7use ra_syntax::{SmolStr, algo::visit::{visitor, Visitor}, ast::{self, AstNode}};
8use test_utils::{project_dir, dir_tests};
6use relative_path::RelativePath; 9use relative_path::RelativePath;
7 10
8use crate::{source_binder, mock::WORKSPACE, module::ModuleSourceNode}; 11use crate::{source_binder, mock::WORKSPACE, module::ModuleSourceNode};
@@ -13,33 +16,46 @@ use crate::{
13 mock::MockDatabase, 16 mock::MockDatabase,
14}; 17};
15 18
16fn infer_all_fns(fixture: &str) -> () { 19fn infer_file(content: &str) -> String {
17 let (db, source_root) = MockDatabase::with_files(fixture); 20 let (db, source_root, file_id) = MockDatabase::with_single_file(content);
18 for &file_id in source_root.files.values() { 21 let source_file = db.source_file(file_id);
19 let source_file = db.source_file(file_id); 22 let mut acc = String::new();
20 for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { 23 for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) {
21 let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap().unwrap(); 24 let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap().unwrap();
22 let inference_result = func.infer(&db); 25 let inference_result = func.infer(&db);
23 for (syntax_ptr, ty) in &inference_result.type_for { 26 for (syntax_ptr, ty) in &inference_result.type_for {
24 let node = syntax_ptr.resolve(&source_file); 27 let node = syntax_ptr.resolve(&source_file);
25 eprintln!("{} '{}': {:?}", syntax_ptr.range(), node.text(), ty); 28 write!(acc, "{} '{}': {}\n", syntax_ptr.range(), ellipsize(node.text().to_string().replace("\n", " "), 15), ty);
26 }
27 } 29 }
28 } 30 }
31 acc
32}
33
34fn ellipsize(mut text: String, max_len: usize) -> String {
35 if text.len() <= max_len {
36 return text;
37 }
38 let ellipsis = "...";
39 let e_len = ellipsis.len();
40 let mut prefix_len = (max_len - e_len) / 2;
41 while !text.is_char_boundary(prefix_len) {
42 prefix_len += 1;
43 }
44 let mut suffix_len = max_len - e_len - prefix_len;
45 while !text.is_char_boundary(text.len() - suffix_len) {
46 suffix_len += 1;
47 }
48 text.replace_range(prefix_len..text.len() - suffix_len, ellipsis);
49 text
29} 50}
30 51
31#[test] 52#[test]
32fn infer_smoke_test() { 53pub fn infer_tests() {
33 let text = " 54 dir_tests(&test_data_dir(), &["."], |text, _path| {
34 //- /lib.rs 55 infer_file(text)
35 fn foo(x: u32, y: !) -> i128 { 56 });
36 x; 57}
37 y;
38 return 1;
39 \"hello\";
40 0
41 }
42 ";
43 58
44 infer_all_fns(text); 59fn test_data_dir() -> PathBuf {
60 project_dir().join("crates/ra_hir/src/ty/tests/data")
45} 61}
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.rs b/crates/ra_hir/src/ty/tests/data/0001_basics.rs
new file mode 100644
index 000000000..59a60d031
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0001_basics.rs
@@ -0,0 +1,11 @@
1
2fn test(a: u32, b: isize, c: !, d: &str) {
3 a;
4 b;
5 c;
6 d;
7 1usize;
8 1isize;
9 "test";
10 1.0f32;
11}
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/0001_basics.txt
new file mode 100644
index 000000000..0c46f243a
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0001_basics.txt
@@ -0,0 +1,13 @@
1[33; 34) 'd': [unknown]
2[88; 94) '1isize': [unknown]
3[48; 49) 'a': u32
4[55; 56) 'b': isize
5[112; 118) '1.0f32': [unknown]
6[76; 82) '1usize': [unknown]
7[9; 10) 'a': u32
8[27; 28) 'c': !
9[62; 63) 'c': !
10[17; 18) 'b': isize
11[100; 106) '"test"': [unknown]
12[42; 121) '{ ...f32; }': ()
13[69; 70) 'd': [unknown]