feat: Resolve builtin-attr and tools in ide layer

This commit is contained in:
Lukas Wirth 2021-12-03 16:32:14 +01:00
parent 4691a0647b
commit e58af219a4
15 changed files with 209 additions and 99 deletions

View file

@ -29,8 +29,9 @@ use syntax::{
};
use crate::{
db::HirDatabase, semantics::PathResolution, Adt, BuiltinType, Const, Field, Function, Local,
MacroDef, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Variant,
db::HirDatabase, semantics::PathResolution, Adt, BuiltinAttr, BuiltinType, Const, Field,
Function, Local, MacroDef, ModuleDef, Static, Struct, Tool, Trait, Type, TypeAlias, TypeParam,
Variant,
};
use base_db::CrateId;
@ -246,18 +247,6 @@ impl SourceAnalyzer {
}
}
pub(crate) fn resolve_path_as_macro(
&self,
db: &dyn HirDatabase,
path: &ast::Path,
) -> Option<MacroDef> {
// This must be a normal source file rather than macro file.
let hygiene = Hygiene::new(db.upcast(), self.file_id);
let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
let hir_path = Path::from_src(path.clone(), &ctx)?;
resolve_hir_path_as_macro(db, &self.resolver, &hir_path)
}
pub(crate) fn resolve_path(
&self,
db: &dyn HirDatabase,
@ -318,15 +307,6 @@ impl SourceAnalyzer {
let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
let hir_path = Path::from_src(path.clone(), &ctx)?;
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
// trying to resolve foo::bar.
if let Some(outer_path) = parent().and_then(ast::Path::cast) {
if let Some(qualifier) = outer_path.qualifier() {
if path == &qualifier {
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
}
}
}
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
// trying to resolve foo::bar.
if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
@ -337,10 +317,50 @@ impl SourceAnalyzer {
}
}
if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
let is_path_of_attr = path
.top_path()
.syntax()
.ancestors()
.nth(2) // Path -> Meta -> Attr
.map_or(false, |it| ast::Attr::can_cast(it.kind()));
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
// trying to resolve foo::bar.
if let Some(outer_path) = path.parent_path() {
if let Some(qualifier) = outer_path.qualifier() {
if path == &qualifier {
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
}
}
} else if is_path_of_attr {
let res = resolve_hir_path_as_macro(db, &self.resolver, &hir_path);
return match res {
Some(_) => res.map(PathResolution::Macro),
None => path.as_single_name_ref().and_then(|name_ref| {
if let Some(builtin) = BuiltinAttr::by_name(&name_ref.text()) {
Some(PathResolution::BuiltinAttr(builtin))
} else if let Some(tool) = Tool::by_name(&name_ref.text()) {
Some(PathResolution::Tool(tool))
} else {
None
}
}),
};
}
let res = if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
} else {
resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
};
match res {
Some(_) => res,
None if is_path_of_attr => path
.first_segment()
.and_then(|seg| seg.name_ref())
.and_then(|name_ref| Tool::by_name(&name_ref.text()))
.map(PathResolution::Tool),
None => None,
}
}