aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/semantics.rs26
-rw-r--r--crates/ide/src/annotations.rs86
-rw-r--r--crates/ide/src/runnables.rs59
3 files changed, 103 insertions, 68 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 945638cc5..2a0a36de4 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2,10 +2,12 @@
2 2
3mod source_to_def; 3mod source_to_def;
4 4
5use std::{cell::RefCell, fmt, iter::successors}; 5use std::{cell::RefCell, collections::VecDeque, fmt, iter::successors};
6 6
7use base_db::{FileId, FileRange}; 7use base_db::{FileId, FileRange};
8use either::Either;
8use hir_def::{ 9use hir_def::{
10 nameres::ModuleSource,
9 resolver::{self, HasResolver, Resolver, TypeNs}, 11 resolver::{self, HasResolver, Resolver, TypeNs},
10 AsMacroCall, FunctionId, TraitId, VariantId, 12 AsMacroCall, FunctionId, TraitId, VariantId,
11}; 13};
@@ -155,6 +157,28 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
155 self.imp.ancestors_at_offset_with_macros(node, offset) 157 self.imp.ancestors_at_offset_with_macros(node, offset)
156 } 158 }
157 159
160 /// Iterates all `ModuleDef`s and `Impl` blocks of the given file.
161 pub fn visit_file_defs(&self, file_id: FileId, cb: &mut dyn FnMut(Either<ModuleDef, Impl>)) {
162 let module = match self.to_module_def(file_id) {
163 Some(it) => it,
164 None => return,
165 };
166 let mut defs: VecDeque<_> = module.declarations(self.db).into();
167 while let Some(def) = defs.pop_front() {
168 if let ModuleDef::Module(submodule) = def {
169 if let ModuleSource::Module(_) = submodule.definition_source(self.db).value {
170 defs.extend(submodule.declarations(self.db));
171 submodule
172 .impl_defs(self.db)
173 .into_iter()
174 .for_each(|impl_| cb(Either::Right(impl_)));
175 }
176 }
177 cb(Either::Left(def));
178 }
179 module.impl_defs(self.db).into_iter().for_each(|impl_| cb(Either::Right(impl_)));
180 }
181
158 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, 182 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
159 /// search up until it is of the target AstNode type 183 /// search up until it is of the target AstNode type
160 pub fn find_node_at_offset_with_macros<N: AstNode>( 184 pub fn find_node_at_offset_with_macros<N: AstNode>(
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index 8e0a8fd8d..c3422ce70 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -1,17 +1,17 @@
1use hir::Semantics; 1use either::Either;
2use hir::{HasSource, Semantics};
2use ide_db::{ 3use ide_db::{
3 base_db::{FileId, FilePosition, FileRange, SourceDatabase}, 4 base_db::{FileId, FilePosition, FileRange},
4 RootDatabase, SymbolKind, 5 RootDatabase,
5}; 6};
6use syntax::TextRange; 7use syntax::{ast::NameOwner, AstNode, TextRange, TextSize};
7 8
8use crate::{ 9use crate::{
9 file_structure::file_structure,
10 fn_references::find_all_methods, 10 fn_references::find_all_methods,
11 goto_implementation::goto_implementation, 11 goto_implementation::goto_implementation,
12 references::find_all_refs, 12 references::find_all_refs,
13 runnables::{runnables, Runnable}, 13 runnables::{runnables, Runnable},
14 NavigationTarget, RunnableKind, StructureNodeKind, 14 NavigationTarget, RunnableKind,
15}; 15};
16 16
17// Feature: Annotations 17// Feature: Annotations
@@ -75,41 +75,56 @@ pub(crate) fn annotations(
75 } 75 }
76 } 76 }
77 77
78 file_structure(&db.parse(file_id).tree()) 78 Semantics::new(db).visit_file_defs(file_id, &mut |def| match def {
79 .into_iter() 79 Either::Left(def) => {
80 .filter(|node| { 80 let node = match def {
81 matches!( 81 hir::ModuleDef::Const(konst) => {
82 node.kind, 82 konst.source(db).and_then(|node| range_and_position_of(&node.value))
83 StructureNodeKind::SymbolKind(SymbolKind::Trait) 83 }
84 | StructureNodeKind::SymbolKind(SymbolKind::Struct) 84 hir::ModuleDef::Trait(trait_) => {
85 | StructureNodeKind::SymbolKind(SymbolKind::Enum) 85 trait_.source(db).and_then(|node| range_and_position_of(&node.value))
86 | StructureNodeKind::SymbolKind(SymbolKind::Union) 86 }
87 | StructureNodeKind::SymbolKind(SymbolKind::Const) 87 hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
88 ) 88 strukt.source(db).and_then(|node| range_and_position_of(&node.value))
89 }) 89 }
90 .for_each(|node| { 90 hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => {
91 if config.annotate_impls 91 enum_.source(db).and_then(|node| range_and_position_of(&node.value))
92 && node.kind != StructureNodeKind::SymbolKind(SymbolKind::Const) 92 }
93 { 93 hir::ModuleDef::Adt(hir::Adt::Union(union)) => {
94 union.source(db).and_then(|node| range_and_position_of(&node.value))
95 }
96 _ => None,
97 };
98 let (offset, range) = match node {
99 Some(node) => node,
100 None => return,
101 };
102
103 if config.annotate_impls && !matches!(def, hir::ModuleDef::Const(_)) {
94 annotations.push(Annotation { 104 annotations.push(Annotation {
95 range: node.node_range, 105 range,
96 kind: AnnotationKind::HasImpls { 106 kind: AnnotationKind::HasImpls {
97 position: FilePosition { file_id, offset: node.navigation_range.start() }, 107 position: FilePosition { file_id, offset },
98 data: None, 108 data: None,
99 }, 109 },
100 }); 110 });
101 } 111 }
102
103 if config.annotate_references { 112 if config.annotate_references {
104 annotations.push(Annotation { 113 annotations.push(Annotation {
105 range: node.node_range, 114 range,
106 kind: AnnotationKind::HasReferences { 115 kind: AnnotationKind::HasReferences {
107 position: FilePosition { file_id, offset: node.navigation_range.start() }, 116 position: FilePosition { file_id, offset },
108 data: None, 117 data: None,
109 }, 118 },
110 }); 119 });
111 } 120 }
112 }); 121
122 fn range_and_position_of(node: &dyn NameOwner) -> Option<(TextSize, TextRange)> {
123 Some((node.name()?.syntax().text_range().start(), node.syntax().text_range()))
124 }
125 }
126 Either::Right(_) => (),
127 });
113 128
114 if config.annotate_method_references { 129 if config.annotate_method_references {
115 annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation { 130 annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation {
@@ -936,4 +951,19 @@ mod tests {
936 "#]], 951 "#]],
937 ); 952 );
938 } 953 }
954
955 #[test]
956 fn test_no_annotations_outside_module_tree() {
957 check(
958 r#"
959//- /foo.rs
960struct Foo;
961//- /lib.rs
962// this file comes last since `check` checks the first file only
963"#,
964 expect![[r#"
965 []
966 "#]],
967 );
968 }
939} 969}
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 27d35de5b..17454f270 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -2,6 +2,7 @@ use std::fmt;
2 2
3use ast::NameOwner; 3use ast::NameOwner;
4use cfg::CfgExpr; 4use cfg::CfgExpr;
5use either::Either;
5use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics}; 6use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
6use ide_assists::utils::test_related_attribute; 7use ide_assists::utils::test_related_attribute;
7use ide_db::{ 8use ide_db::{
@@ -102,13 +103,27 @@ impl Runnable {
102// |=== 103// |===
103pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 104pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
104 let sema = Semantics::new(db); 105 let sema = Semantics::new(db);
105 let module = match sema.to_module_def(file_id) {
106 None => return Vec::new(),
107 Some(it) => it,
108 };
109 106
110 let mut res = Vec::new(); 107 let mut res = Vec::new();
111 runnables_mod(&sema, &mut res, module); 108 sema.visit_file_defs(file_id, &mut |def| match def {
109 Either::Left(def) => {
110 let runnable = match def {
111 hir::ModuleDef::Module(it) => runnable_mod(&sema, it),
112 hir::ModuleDef::Function(it) => runnable_fn(&sema, it),
113 _ => None,
114 };
115 res.extend(runnable.or_else(|| module_def_doctest(&sema, def)))
116 }
117 Either::Right(impl_) => {
118 res.extend(impl_.items(db).into_iter().filter_map(|assoc| match assoc {
119 hir::AssocItem::Function(it) => {
120 runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into()))
121 }
122 hir::AssocItem::Const(it) => module_def_doctest(&sema, it.into()),
123 hir::AssocItem::TypeAlias(it) => module_def_doctest(&sema, it.into()),
124 }))
125 }
126 });
112 res 127 res
113} 128}
114 129
@@ -211,39 +226,6 @@ fn parent_test_module(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Optio
211 }) 226 })
212} 227}
213 228
214fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module: hir::Module) {
215 acc.extend(module.declarations(sema.db).into_iter().filter_map(|def| {
216 let runnable = match def {
217 hir::ModuleDef::Module(it) => runnable_mod(&sema, it),
218 hir::ModuleDef::Function(it) => runnable_fn(&sema, it),
219 _ => None,
220 };
221 runnable.or_else(|| module_def_doctest(&sema, def))
222 }));
223
224 acc.extend(module.impl_defs(sema.db).into_iter().flat_map(|it| it.items(sema.db)).filter_map(
225 |def| match def {
226 hir::AssocItem::Function(it) => {
227 runnable_fn(&sema, it).or_else(|| module_def_doctest(&sema, it.into()))
228 }
229 hir::AssocItem::Const(it) => module_def_doctest(&sema, it.into()),
230 hir::AssocItem::TypeAlias(it) => module_def_doctest(&sema, it.into()),
231 },
232 ));
233
234 for def in module.declarations(sema.db) {
235 if let hir::ModuleDef::Module(submodule) = def {
236 match submodule.definition_source(sema.db).value {
237 hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule),
238 hir::ModuleSource::SourceFile(_) => {
239 cov_mark::hit!(dont_recurse_in_outline_submodules)
240 }
241 hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable
242 }
243 }
244 }
245}
246
247pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { 229pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
248 let func = def.source(sema.db)?; 230 let func = def.source(sema.db)?;
249 let name_string = def.name(sema.db).to_string(); 231 let name_string = def.name(sema.db).to_string();
@@ -1178,7 +1160,6 @@ mod tests {
1178 1160
1179 #[test] 1161 #[test]
1180 fn dont_recurse_in_outline_submodules() { 1162 fn dont_recurse_in_outline_submodules() {
1181 cov_mark::check!(dont_recurse_in_outline_submodules);
1182 check( 1163 check(
1183 r#" 1164 r#"
1184//- /lib.rs 1165//- /lib.rs