From 7348f7883fa2bd571fff036c82e98c102d05c362 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 23 Dec 2018 12:05:54 +0100 Subject: Add testing infrastructure for type inference - move dir_tests to test_utils for that. --- crates/ra_hir/src/mock.rs | 9 ++++ crates/ra_hir/src/ty.rs | 30 ++++++++++++ crates/ra_hir/src/ty/tests.rs | 62 ++++++++++++++++--------- crates/ra_hir/src/ty/tests/data/0001_basics.rs | 11 +++++ crates/ra_hir/src/ty/tests/data/0001_basics.txt | 13 ++++++ 5 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 crates/ra_hir/src/ty/tests/data/0001_basics.rs create mode 100644 crates/ra_hir/src/ty/tests/data/0001_basics.txt (limited to 'crates/ra_hir') 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 { (db, source_root) } + pub(crate) fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) { + let mut db = MockDatabase::default(); + let mut source_root = SourceRoot::default(); + let file_id = db.add_file(&mut source_root, "/main.rs", text); + db.query_mut(ra_db::SourceRootQuery) + .set(WORKSPACE, Arc::new(source_root.clone())); + (db, source_root, file_id) + } + pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { let (db, _, position) = MockDatabase::from_fixture(fixture); 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}; use std::sync::Arc; use std::collections::HashMap; +use std::fmt; use ra_db::LocalSyntaxPtr; use ra_syntax::{ @@ -184,11 +185,40 @@ impl Ty { } } +impl fmt::Display for Ty { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ty::Bool => write!(f, "bool"), + Ty::Char => write!(f, "char"), + Ty::Int(t) => write!(f, "{}", t.ty_to_string()), + Ty::Uint(t) => write!(f, "{}", t.ty_to_string()), + Ty::Float(t) => write!(f, "{}", t.ty_to_string()), + Ty::Str => write!(f, "str"), + Ty::Slice(t) => write!(f, "[{}]", t), + Ty::Never => write!(f, "!"), + Ty::Tuple(ts) => { + write!(f, "(")?; + for t in ts { + write!(f, "{},", t)?; + } + write!(f, ")") + } + Ty::Unknown => write!(f, "[unknown]") + } + } +} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { type_for: FxHashMap, } +impl InferenceResult { + pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option { + self.type_for.get(&LocalSyntaxPtr::new(node)).cloned() + } +} + #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceContext { scopes: Arc, 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 @@ +use std::fmt::Write; use std::sync::Arc; +use std::path::{Path, PathBuf}; use salsa::Database; use ra_db::{FilesDatabase, CrateGraph, SyntaxDatabase}; use ra_syntax::{SmolStr, algo::visit::{visitor, Visitor}, ast::{self, AstNode}}; +use test_utils::{project_dir, dir_tests}; use relative_path::RelativePath; use crate::{source_binder, mock::WORKSPACE, module::ModuleSourceNode}; @@ -13,33 +16,46 @@ use crate::{ mock::MockDatabase, }; -fn infer_all_fns(fixture: &str) -> () { - let (db, source_root) = MockDatabase::with_files(fixture); - for &file_id in source_root.files.values() { - let source_file = db.source_file(file_id); - for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { - let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap().unwrap(); - let inference_result = func.infer(&db); - for (syntax_ptr, ty) in &inference_result.type_for { - let node = syntax_ptr.resolve(&source_file); - eprintln!("{} '{}': {:?}", syntax_ptr.range(), node.text(), ty); - } +fn infer_file(content: &str) -> String { + let (db, source_root, file_id) = MockDatabase::with_single_file(content); + let source_file = db.source_file(file_id); + let mut acc = String::new(); + for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { + let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap().unwrap(); + let inference_result = func.infer(&db); + for (syntax_ptr, ty) in &inference_result.type_for { + let node = syntax_ptr.resolve(&source_file); + write!(acc, "{} '{}': {}\n", syntax_ptr.range(), ellipsize(node.text().to_string().replace("\n", " "), 15), ty); } } + acc +} + +fn ellipsize(mut text: String, max_len: usize) -> String { + if text.len() <= max_len { + return text; + } + let ellipsis = "..."; + let e_len = ellipsis.len(); + let mut prefix_len = (max_len - e_len) / 2; + while !text.is_char_boundary(prefix_len) { + prefix_len += 1; + } + let mut suffix_len = max_len - e_len - prefix_len; + while !text.is_char_boundary(text.len() - suffix_len) { + suffix_len += 1; + } + text.replace_range(prefix_len..text.len() - suffix_len, ellipsis); + text } #[test] -fn infer_smoke_test() { - let text = " - //- /lib.rs - fn foo(x: u32, y: !) -> i128 { - x; - y; - return 1; - \"hello\"; - 0 - } - "; +pub fn infer_tests() { + dir_tests(&test_data_dir(), &["."], |text, _path| { + infer_file(text) + }); +} - infer_all_fns(text); +fn test_data_dir() -> PathBuf { + project_dir().join("crates/ra_hir/src/ty/tests/data") } 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 @@ + +fn test(a: u32, b: isize, c: !, d: &str) { + a; + b; + c; + d; + 1usize; + 1isize; + "test"; + 1.0f32; +} 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 @@ +[33; 34) 'd': [unknown] +[88; 94) '1isize': [unknown] +[48; 49) 'a': u32 +[55; 56) 'b': isize +[112; 118) '1.0f32': [unknown] +[76; 82) '1usize': [unknown] +[9; 10) 'a': u32 +[27; 28) 'c': ! +[62; 63) 'c': ! +[17; 18) 'b': isize +[100; 106) '"test"': [unknown] +[42; 121) '{ ...f32; }': () +[69; 70) 'd': [unknown] -- cgit v1.2.3