aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/assists.rs7
-rw-r--r--crates/ra_ide/src/change.rs10
-rw-r--r--crates/ra_ide/src/imports_locator.rs76
-rw-r--r--crates/ra_ide/src/inlay_hints.rs14
-rw-r--r--crates/ra_ide/src/lib.rs4
-rw-r--r--crates/ra_ide/src/runnables.rs16
6 files changed, 118 insertions, 9 deletions
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs
index a936900da..c43c45c65 100644
--- a/crates/ra_ide/src/assists.rs
+++ b/crates/ra_ide/src/assists.rs
@@ -2,8 +2,9 @@
2 2
3use ra_db::{FilePosition, FileRange}; 3use ra_db::{FilePosition, FileRange};
4 4
5use crate::{db::RootDatabase, FileId, SourceChange, SourceFileEdit}; 5use crate::{
6 6 db::RootDatabase, imports_locator::ImportsLocatorIde, FileId, SourceChange, SourceFileEdit,
7};
7use either::Either; 8use either::Either;
8pub use ra_assists::AssistId; 9pub use ra_assists::AssistId;
9use ra_assists::{AssistAction, AssistLabel}; 10use ra_assists::{AssistAction, AssistLabel};
@@ -16,7 +17,7 @@ pub struct Assist {
16} 17}
17 18
18pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { 19pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> {
19 ra_assists::assists(db, frange) 20 ra_assists::assists_with_imports_locator(db, frange, ImportsLocatorIde::new(db))
20 .into_iter() 21 .into_iter()
21 .map(|assist| { 22 .map(|assist| {
22 let file_id = frange.file_id; 23 let file_id = frange.file_id;
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index b0aa2c8e0..ce617840c 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -166,13 +166,15 @@ impl LibraryData {
166const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100); 166const GC_COOLDOWN: time::Duration = time::Duration::from_millis(100);
167 167
168impl RootDatabase { 168impl RootDatabase {
169 pub(crate) fn request_cancellation(&mut self) {
170 let _p = profile("RootDatabase::request_cancellation");
171 self.salsa_runtime_mut().synthetic_write(Durability::LOW);
172 }
173
169 pub(crate) fn apply_change(&mut self, change: AnalysisChange) { 174 pub(crate) fn apply_change(&mut self, change: AnalysisChange) {
170 let _p = profile("RootDatabase::apply_change"); 175 let _p = profile("RootDatabase::apply_change");
176 self.request_cancellation();
171 log::info!("apply_change {:?}", change); 177 log::info!("apply_change {:?}", change);
172 {
173 let _p = profile("RootDatabase::apply_change/cancellation");
174 self.salsa_runtime_mut().synthetic_write(Durability::LOW);
175 }
176 if !change.new_roots.is_empty() { 178 if !change.new_roots.is_empty() {
177 let mut local_roots = Vec::clone(&self.local_roots()); 179 let mut local_roots = Vec::clone(&self.local_roots());
178 for (root_id, is_local) in change.new_roots { 180 for (root_id, is_local) in change.new_roots {
diff --git a/crates/ra_ide/src/imports_locator.rs b/crates/ra_ide/src/imports_locator.rs
new file mode 100644
index 000000000..48b014c7d
--- /dev/null
+++ b/crates/ra_ide/src/imports_locator.rs
@@ -0,0 +1,76 @@
1//! This module contains an import search funcionality that is provided to the ra_assists module.
2//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.
3
4use crate::{
5 db::RootDatabase,
6 references::{classify_name, NameDefinition, NameKind},
7 symbol_index::{self, FileSymbol},
8 Query,
9};
10use hir::{db::HirDatabase, ModuleDef, SourceBinder};
11use ra_assists::ImportsLocator;
12use ra_prof::profile;
13use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
14
15pub(crate) struct ImportsLocatorIde<'a> {
16 source_binder: SourceBinder<'a, RootDatabase>,
17}
18
19impl<'a> ImportsLocatorIde<'a> {
20 pub(crate) fn new(db: &'a RootDatabase) -> Self {
21 Self { source_binder: SourceBinder::new(db) }
22 }
23
24 fn get_name_definition(
25 &mut self,
26 db: &impl HirDatabase,
27 import_candidate: &FileSymbol,
28 ) -> Option<NameDefinition> {
29 let _p = profile("get_name_definition");
30 let file_id = import_candidate.file_id.into();
31 let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
32 let candidate_name_node = if candidate_node.kind() != NAME {
33 candidate_node.children().find(|it| it.kind() == NAME)?
34 } else {
35 candidate_node
36 };
37 classify_name(
38 &mut self.source_binder,
39 hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
40 )
41 }
42}
43
44impl ImportsLocator for ImportsLocatorIde<'_> {
45 fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
46 let _p = profile("search_for_imports");
47 let db = self.source_binder.db;
48
49 let project_results = {
50 let mut query = Query::new(name_to_import.to_string());
51 query.exact();
52 query.limit(40);
53 symbol_index::world_symbols(db, query)
54 };
55 let lib_results = {
56 let mut query = Query::new(name_to_import.to_string());
57 query.libs();
58 query.exact();
59 query.limit(40);
60 symbol_index::world_symbols(db, query)
61 };
62
63 project_results
64 .into_iter()
65 .chain(lib_results.into_iter())
66 .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate))
67 .filter_map(|name_definition_to_import| {
68 if let NameKind::Def(module_def) = name_definition_to_import.kind {
69 Some(module_def)
70 } else {
71 None
72 }
73 })
74 .collect()
75 }
76}
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 236557541..393ca9447 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -245,6 +245,7 @@ struct Test<K, T = u8> {
245 245
246fn main() { 246fn main() {
247 let zz = Test { t: 23, k: 33 }; 247 let zz = Test { t: 23, k: 33 };
248 let zz_ref = &zz;
248}"#, 249}"#,
249 ); 250 );
250 251
@@ -255,6 +256,11 @@ fn main() {
255 kind: TypeHint, 256 kind: TypeHint,
256 label: "Test<i32>", 257 label: "Test<i32>",
257 }, 258 },
259 InlayHint {
260 range: [105; 111),
261 kind: TypeHint,
262 label: "&Test<i32>",
263 },
258 ] 264 ]
259 "### 265 "###
260 ); 266 );
@@ -374,6 +380,7 @@ fn main() {
374 380
375 let multiply = |a, b, c, d| a * b * c * d; 381 let multiply = |a, b, c, d| a * b * c * d;
376 let _: i32 = multiply(1, 2, 3, 4); 382 let _: i32 = multiply(1, 2, 3, 4);
383 let multiply_ref = &multiply;
377 384
378 let return_42 = || 42; 385 let return_42 = || 42;
379}"#, 386}"#,
@@ -417,7 +424,12 @@ fn main() {
417 label: "i32", 424 label: "i32",
418 }, 425 },
419 InlayHint { 426 InlayHint {
420 range: [201; 210), 427 range: [200; 212),
428 kind: TypeHint,
429 label: "&|…| -> i32",
430 },
431 InlayHint {
432 range: [235; 244),
421 kind: TypeHint, 433 kind: TypeHint,
422 label: "|| -> i32", 434 label: "|| -> i32",
423 }, 435 },
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 4d8deb21c..03ad6b2c1 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -30,6 +30,7 @@ mod syntax_highlighting;
30mod parent_module; 30mod parent_module;
31mod references; 31mod references;
32mod impls; 32mod impls;
33mod imports_locator;
33mod assists; 34mod assists;
34mod diagnostics; 35mod diagnostics;
35mod syntax_tree; 36mod syntax_tree;
@@ -202,6 +203,9 @@ impl AnalysisHost {
202 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> { 203 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> {
203 self.db.per_query_memory_usage() 204 self.db.per_query_memory_usage()
204 } 205 }
206 pub fn request_cancellation(&mut self) {
207 self.db.request_cancellation();
208 }
205 pub fn raw_database( 209 pub fn raw_database(
206 &self, 210 &self,
207 ) -> &(impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) { 211 ) -> &(impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 7533692f6..8622dd956 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -43,7 +43,7 @@ fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> {
43 let name = fn_def.name()?.text().clone(); 43 let name = fn_def.name()?.text().clone();
44 let kind = if name == "main" { 44 let kind = if name == "main" {
45 RunnableKind::Bin 45 RunnableKind::Bin
46 } else if fn_def.has_atom_attr("test") { 46 } else if has_test_related_attribute(&fn_def) {
47 RunnableKind::Test { name: name.to_string() } 47 RunnableKind::Test { name: name.to_string() }
48 } else if fn_def.has_atom_attr("bench") { 48 } else if fn_def.has_atom_attr("bench") {
49 RunnableKind::Bench { name: name.to_string() } 49 RunnableKind::Bench { name: name.to_string() }
@@ -53,6 +53,20 @@ fn runnable_fn(fn_def: ast::FnDef) -> Option<Runnable> {
53 Some(Runnable { range: fn_def.syntax().text_range(), kind }) 53 Some(Runnable { range: fn_def.syntax().text_range(), kind })
54} 54}
55 55
56/// This is a method with a heuristics to support test methods annotated with custom test annotations, such as
57/// `#[test_case(...)]`, `#[tokio::test]` and similar.
58/// Also a regular `#[test]` annotation is supported.
59///
60/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
61/// but it's better than not to have the runnables for the tests at all.
62fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
63 fn_def
64 .attrs()
65 .filter_map(|attr| attr.path())
66 .map(|path| path.syntax().to_string().to_lowercase())
67 .any(|attribute_text| attribute_text.contains("test"))
68}
69
56fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> { 70fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Option<Runnable> {
57 let has_test_function = module 71 let has_test_function = module
58 .item_list()? 72 .item_list()?