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.rs66
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,
}
}