generalize SourceAnalyzer to handle all defs with bodies

This commit is contained in:
Aleksey Kladov 2019-04-11 16:22:10 +03:00
parent 07cc047b4f
commit 5471c1ef4b
3 changed files with 51 additions and 11 deletions

View file

@ -454,6 +454,14 @@ impl DefWithBody {
db.body_hir(*self) db.body_hir(*self)
} }
pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
match *self {
DefWithBody::Const(ref c) => c.body_source_map(db),
DefWithBody::Function(ref f) => f.body_source_map(db),
DefWithBody::Static(ref s) => s.body_source_map(db),
}
}
/// Builds a resolver for code inside this item. /// Builds a resolver for code inside this item.
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
match *self { match *self {

View file

@ -15,7 +15,7 @@ use ra_syntax::{
}; };
use crate::{ use crate::{
HirDatabase, Function, Struct, Enum, Const, Static, Either, HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody,
AsName, Module, HirFileId, Crate, Trait, Resolver, AsName, Module, HirFileId, Crate, Trait, Resolver,
ids::LocationCtx, ids::LocationCtx,
expr, AstId expr, AstId
@ -219,7 +219,7 @@ pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> R
.unwrap_or_default() .unwrap_or_default()
} }
pub fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> Resolver { fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> Resolver {
node.ancestors() node.ancestors()
.find_map(|node| { .find_map(|node| {
if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
@ -284,16 +284,24 @@ pub enum PathResolution {
impl SourceAnalyzer { impl SourceAnalyzer {
pub fn new(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> SourceAnalyzer { pub fn new(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> SourceAnalyzer {
let resolver = resolver_for_node(db, file_id, node); let def_with_body = node.ancestors().find_map(|node| {
let function = function_from_child_node(db, file_id, node); if let Some(src) = ast::FnDef::cast(node) {
if let Some(function) = function { return function_from_source(db, file_id, src).map(DefWithBody::from);
SourceAnalyzer {
resolver,
body_source_map: Some(function.body_source_map(db)),
infer: Some(function.infer(db)),
} }
} else { if let Some(src) = ast::StaticDef::cast(node) {
SourceAnalyzer { resolver, body_source_map: None, infer: None } return static_from_source(db, file_id, src).map(DefWithBody::from);
}
if let Some(src) = ast::ConstDef::cast(node) {
return const_from_source(db, file_id, src).map(DefWithBody::from);
}
None
});
SourceAnalyzer {
resolver: def_with_body
.map(|it| it.resolver(db))
.unwrap_or_else(|| resolver_for_node(db, file_id, node)),
body_source_map: def_with_body.map(|it| it.body_source_map(db)),
infer: def_with_body.map(|it| it.infer(db)),
} }
} }

View file

@ -305,6 +305,30 @@ mod tests {
kind: Method, kind: Method,
detail: "pub fn blah(&self)" detail: "pub fn blah(&self)"
} }
]"###
);
}
#[test]
fn test_completion_works_in_consts() {
assert_debug_snapshot_matches!(
do_ref_completion(
r"
struct A { the_field: u32 }
const X: u32 = {
A { the_field: 92 }.<|>
};
",
),
@r###"[
CompletionItem {
label: "the_field",
source_range: [106; 106),
delete: [106; 106),
insert: "the_field",
kind: Field,
detail: "u32"
}
]"### ]"###
); );
} }