mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
simplify runnables
This commit is contained in:
parent
ef08b6c084
commit
28f6eedba5
7 changed files with 65 additions and 124 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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>>()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue