Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 66 |
1 files changed, 43 insertions, 23 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 23fcd02b57..8f6c3d995f 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -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,29 +307,60 @@ 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 + // 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(outer_path) = parent().and_then(ast::Path::cast) { - if let Some(qualifier) = outer_path.qualifier() { - if path == &qualifier { + if let Some(use_tree) = parent().and_then(ast::UseTree::cast) { + if let Some(qualifier) = use_tree.path() { + if path == &qualifier && use_tree.coloncolon_token().is_some() { 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 + + 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(use_tree) = parent().and_then(ast::UseTree::cast) { - if let Some(qualifier) = use_tree.path() { - if path == &qualifier && use_tree.coloncolon_token().is_some() { + 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 + } + }), + }; } - if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) { + 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, } } |