Introduce Semantics::visit_file_defs

This commit is contained in:
Lukas Wirth 2021-03-14 16:12:38 +01:00
parent 5138baf2ac
commit a1c96e04be
3 changed files with 108 additions and 73 deletions

View file

@ -1,17 +1,17 @@
use hir::Semantics;
use either::Either;
use hir::{HasSource, Semantics};
use ide_db::{
base_db::{FileId, FilePosition, FileRange, SourceDatabase},
RootDatabase, SymbolKind,
base_db::{FileId, FilePosition, FileRange},
RootDatabase,
};
use syntax::TextRange;
use syntax::{ast::NameOwner, AstNode, TextRange, TextSize};
use crate::{
file_structure::file_structure,
fn_references::find_all_methods,
goto_implementation::goto_implementation,
references::find_all_refs,
runnables::{runnables, Runnable},
NavigationTarget, RunnableKind, StructureNodeKind,
NavigationTarget, RunnableKind,
};
// Feature: Annotations
@ -75,41 +75,56 @@ pub(crate) fn annotations(
}
}
file_structure(&db.parse(file_id).tree())
.into_iter()
.filter(|node| {
matches!(
node.kind,
StructureNodeKind::SymbolKind(SymbolKind::Trait)
| StructureNodeKind::SymbolKind(SymbolKind::Struct)
| StructureNodeKind::SymbolKind(SymbolKind::Enum)
| StructureNodeKind::SymbolKind(SymbolKind::Union)
| StructureNodeKind::SymbolKind(SymbolKind::Const)
)
})
.for_each(|node| {
if config.annotate_impls
&& node.kind != StructureNodeKind::SymbolKind(SymbolKind::Const)
{
Semantics::new(db).visit_file_defs(file_id, &mut |def| match def {
Either::Left(def) => {
let node = match def {
hir::ModuleDef::Const(konst) => {
konst.source(db).and_then(|node| range_and_position_of(&node.value))
}
hir::ModuleDef::Trait(trait_) => {
trait_.source(db).and_then(|node| range_and_position_of(&node.value))
}
hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
strukt.source(db).and_then(|node| range_and_position_of(&node.value))
}
hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => {
enum_.source(db).and_then(|node| range_and_position_of(&node.value))
}
hir::ModuleDef::Adt(hir::Adt::Union(union)) => {
union.source(db).and_then(|node| range_and_position_of(&node.value))
}
_ => None,
};
let (offset, range) = match node {
Some(node) => node,
None => return,
};
if config.annotate_impls && !matches!(def, hir::ModuleDef::Const(_)) {
annotations.push(Annotation {
range: node.node_range,
range,
kind: AnnotationKind::HasImpls {
position: FilePosition { file_id, offset: node.navigation_range.start() },
position: FilePosition { file_id, offset },
data: None,
},
});
}
if config.annotate_references {
annotations.push(Annotation {
range,
kind: AnnotationKind::HasReferences {
position: FilePosition { file_id, offset },
data: None,
},
});
}
if config.annotate_references {
annotations.push(Annotation {
range: node.node_range,
kind: AnnotationKind::HasReferences {
position: FilePosition { file_id, offset: node.navigation_range.start() },
data: None,
},
});
fn range_and_position_of(node: &dyn NameOwner) -> Option<(TextSize, TextRange)> {
Some((node.name()?.syntax().text_range().start(), node.syntax().text_range()))
}
});
}
Either::Right(_) => (),
});
if config.annotate_method_references {
annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation {
@ -936,4 +951,19 @@ mod tests {
"#]],
);
}
#[test]
fn test_no_annotations_outside_module_tree() {
check(
r#"
//- /foo.rs
struct Foo;
//- /lib.rs
// this file comes last since `check` checks the first file only
"#,
expect![[r#"
[]
"#]],
);
}
}