simplify runnables

This commit is contained in:
Aleksey Kladov 2019-01-02 20:12:38 +03:00
parent ef08b6c084
commit 28f6eedba5
7 changed files with 65 additions and 124 deletions

1
Cargo.lock generated
View file

@ -667,6 +667,7 @@ name = "ra_analysis"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fst 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ra_db 0.1.0", "ra_db 0.1.0",

View file

@ -5,6 +5,7 @@ version = "0.1.0"
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"] authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
[dependencies] [dependencies]
itertools = "0.8.0"
log = "0.4.5" log = "0.4.5"
relative-path = "0.4.0" relative-path = "0.4.0"
rayon = "1.0.2" rayon = "1.0.2"
@ -12,6 +13,7 @@ fst = "0.3.1"
salsa = "0.9.0" salsa = "0.9.0"
rustc-hash = "1.0" rustc-hash = "1.0"
parking_lot = "0.7.0" parking_lot = "0.7.0"
ra_syntax = { path = "../ra_syntax" } ra_syntax = { path = "../ra_syntax" }
ra_editor = { path = "../ra_editor" } ra_editor = { path = "../ra_editor" }
ra_text_edit = { path = "../ra_text_edit" } ra_text_edit = { path = "../ra_text_edit" }

View file

@ -100,27 +100,6 @@ impl db::RootDatabase {
} }
impl db::RootDatabase { impl db::RootDatabase {
pub(crate) fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> {
let descr = match source_binder::module_from_position(self, position)? {
None => return Ok(None),
Some(it) => it,
};
let name = match descr.name() {
None => return Ok(None),
Some(it) => it.to_string(),
};
let modules = descr.path_to_root();
let path = modules
.iter()
.filter_map(|s| s.name())
.skip(1) // name is already part of the string.
.fold(name, |path, it| format!("{}::{}", it, path));
Ok(Some(path.to_string()))
}
/// This returns `Vec` because a module may be included from several places. We /// This returns `Vec` because a module may be included from several places. We
/// don't handle this case yet though, so the Vec has length at most one. /// don't handle this case yet though, so the Vec has length at most one.
pub(crate) fn parent_module( pub(crate) fn parent_module(

View file

@ -382,10 +382,6 @@ impl Analysis {
pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
self.db.parent_module(position) self.db.parent_module(position)
} }
/// Returns `::` separated path to the current module from the crate root.
pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> {
self.db.module_path(position)
}
/// Returns crates this file belongs too. /// Returns crates this file belongs too.
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
self.db.crate_for(file_id) self.db.crate_for(file_id)
@ -396,8 +392,7 @@ impl Analysis {
} }
/// Returns the set of possible targets to run for the current file. /// Returns the set of possible targets to run for the current file.
pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
let file = self.db.source_file(file_id); runnables::runnables(&*self.db, file_id)
Ok(runnables::runnables(self, &file, file_id))
} }
/// Computes syntax highlighting for the given file. /// Computes syntax highlighting for the given file.
pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {

View file

@ -1,11 +1,11 @@
use itertools::Itertools;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, NameOwner, ModuleItemOwner}, ast::{self, AstNode, NameOwner, ModuleItemOwner},
SourceFileNode, TextRange, SyntaxNodeRef, TextRange, SyntaxNodeRef,
TextUnit,
};
use crate::{
Analysis, FileId, FilePosition
}; };
use ra_db::{Cancelable, SyntaxDatabase};
use crate::{db::RootDatabase, FileId};
#[derive(Debug)] #[derive(Debug)]
pub struct Runnable { pub struct Runnable {
@ -20,24 +20,31 @@ pub enum RunnableKind {
Bin, Bin,
} }
pub fn runnables( pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<Runnable>> {
analysis: &Analysis, let source_file = db.source_file(file_id);
file_node: &SourceFileNode, let res = source_file
file_id: FileId,
) -> Vec<Runnable> {
file_node
.syntax() .syntax()
.descendants() .descendants()
.filter_map(|i| runnable(analysis, i, file_id)) .filter_map(|i| runnable(db, file_id, i))
.collect() .collect();
Ok(res)
} }
fn runnable<'a>(analysis: &Analysis, item: SyntaxNodeRef<'a>, file_id: FileId) -> Option<Runnable> { fn runnable(db: &RootDatabase, file_id: FileId, item: SyntaxNodeRef) -> Option<Runnable> {
if let Some(f) = ast::FnDef::cast(item) { if let Some(fn_def) = ast::FnDef::cast(item) {
let name = f.name()?.text(); runnable_fn(fn_def)
} else if let Some(m) = ast::Module::cast(item) {
runnable_mod(db, file_id, m)
} else {
None
}
}
fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> {
let name = fn_def.name()?.text();
let kind = if name == "main" { let kind = if name == "main" {
RunnableKind::Bin RunnableKind::Bin
} else if f.has_atom_attr("test") { } else if fn_def.has_atom_attr("test") {
RunnableKind::Test { RunnableKind::Test {
name: name.to_string(), name: name.to_string(),
} }
@ -45,28 +52,35 @@ fn runnable<'a>(analysis: &Analysis, item: SyntaxNodeRef<'a>, file_id: FileId) -
return None; return None;
}; };
Some(Runnable { Some(Runnable {
range: f.syntax().range(), range: fn_def.syntax().range(),
kind, kind,
}) })
} else if let Some(m) = ast::Module::cast(item) { }
if m.item_list()?
fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> {
let has_test_function = module
.item_list()?
.items() .items()
.map(ast::ModuleItem::syntax) .filter_map(|it| match it {
.filter_map(ast::FnDef::cast) ast::ModuleItem::FnDef(it) => Some(it),
.any(|f| f.has_atom_attr("test")) _ => None,
{ })
let postition = FilePosition { .any(|f| f.has_atom_attr("test"));
file_id, if !has_test_function {
offset: m.syntax().range().start() + TextUnit::from_usize(1), return None;
}; }
analysis.module_path(postition).ok()?.map(|path| Runnable { let range = module.syntax().range();
range: m.syntax().range(), let module =
hir::source_binder::module_from_child_node(db, file_id, module.syntax()).ok()??;
let path = module
.path_to_root()
.into_iter()
.rev()
.into_iter()
.filter_map(|it| it.name().map(Clone::clone))
.join("::");
Some(Runnable {
range,
kind: RunnableKind::TestMod { path }, kind: RunnableKind::TestMod { path },
}) })
} else {
None
}
} else {
None
}
} }

View file

@ -131,56 +131,6 @@ fn test_resolve_parent_module_for_inline() {
); );
} }
#[test]
fn test_path_one_layer() {
let (analysis, pos) = analysis_and_position(
"
//- /lib.rs
mod foo;
//- /foo/mod.rs
mod bla;
//- /foo/bla.rs
<|> //empty
",
);
let symbols = analysis.module_path(pos).unwrap().unwrap();
assert_eq!("foo::bla", &symbols);
}
#[test]
fn test_path_two_layer() {
let (analysis, pos) = analysis_and_position(
"
//- /lib.rs
mod foo;
//- /foo/mod.rs
mod bla;
//- /foo/bla/mod.rs
mod more;
//- /foo/bla/more.rs
<|> //empty
",
);
let symbols = analysis.module_path(pos).unwrap().unwrap();
assert_eq!("foo::bla::more", &symbols);
}
#[test]
fn test_path_in_file_mod() {
let (analysis, pos) = analysis_and_position(
"
//- /lib.rs
mod foo;
//- /foo.rs
mod bar {
<|> //empty
}
",
);
let symbols = analysis.module_path(pos).unwrap().unwrap();
assert_eq!("foo::bar", &symbols);
}
#[test] #[test]
fn test_resolve_crate_root() { fn test_resolve_crate_root() {
let mock = MockAnalysis::with_files( let mock = MockAnalysis::with_files(

View file

@ -80,7 +80,7 @@ impl Module {
Some(Crate::new(crate_id)) Some(Crate::new(crate_id))
} }
/// Returns the all modulkes on the way to the root. /// Returns the all modules on the way to the root.
pub fn path_to_root(&self) -> Vec<Module> { pub fn path_to_root(&self) -> Vec<Module> {
generate(Some(self.clone()), move |it| it.parent()).collect::<Vec<Module>>() generate(Some(self.clone()), move |it| it.parent()).collect::<Vec<Module>>()
} }