Skip to content

Commit 3f3289d

Browse files
bors[bot]Veykril
andauthored
Merge #10915
10915: feat: Resolve builtin-attr and tools in ide layer r=Veykril a=Veykril Co-authored-by: Lukas Wirth <[email protected]>
2 parents cf1c7e5 + 8da850b commit 3f3289d

26 files changed

+350
-176
lines changed

crates/hir/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ pub use {
103103
hir_def::{
104104
adt::StructKind,
105105
attr::{Attr, Attrs, AttrsWithOwner, Documentation},
106+
builtin_attr::AttributeTemplate,
106107
find_path::PrefixKind,
107108
import_map,
108109
item_scope::ItemScope,
@@ -2023,6 +2024,40 @@ impl Local {
20232024
}
20242025
}
20252026

2027+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2028+
pub struct BuiltinAttr(usize);
2029+
2030+
impl BuiltinAttr {
2031+
pub(crate) fn by_name(name: &str) -> Option<Self> {
2032+
// FIXME: def maps registered attrs?
2033+
hir_def::builtin_attr::find_builtin_attr_idx(name).map(Self)
2034+
}
2035+
2036+
pub fn name(&self, _: &dyn HirDatabase) -> &str {
2037+
// FIXME: Return a `Name` here
2038+
hir_def::builtin_attr::INERT_ATTRIBUTES[self.0].name
2039+
}
2040+
2041+
pub fn template(&self, _: &dyn HirDatabase) -> AttributeTemplate {
2042+
hir_def::builtin_attr::INERT_ATTRIBUTES[self.0].template
2043+
}
2044+
}
2045+
2046+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2047+
pub struct ToolModule(usize);
2048+
2049+
impl ToolModule {
2050+
pub(crate) fn by_name(name: &str) -> Option<Self> {
2051+
// FIXME: def maps registered tools
2052+
hir_def::builtin_attr::TOOL_MODULES.iter().position(|&tool| tool == name).map(Self)
2053+
}
2054+
2055+
pub fn name(&self, _: &dyn HirDatabase) -> &str {
2056+
// FIXME: Return a `Name` here
2057+
hir_def::builtin_attr::TOOL_MODULES[self.0]
2058+
}
2059+
}
2060+
20262061
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
20272062
pub struct Label {
20282063
pub(crate) parent: DefWithBodyId,

crates/hir/src/semantics.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ use crate::{
2525
db::HirDatabase,
2626
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
2727
source_analyzer::{resolve_hir_path, resolve_hir_path_as_macro, SourceAnalyzer},
28-
Access, AssocItem, Callable, ConstParam, Crate, Field, Function, HasSource, HirFileId, Impl,
29-
InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait,
30-
Type, TypeAlias, TypeParam, VariantDef,
28+
Access, AssocItem, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
29+
HirFileId, Impl, InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path,
30+
ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
3131
};
3232

3333
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -43,6 +43,8 @@ pub enum PathResolution {
4343
SelfType(Impl),
4444
Macro(MacroDef),
4545
AssocItem(AssocItem),
46+
BuiltinAttr(BuiltinAttr),
47+
ToolModule(ToolModule),
4648
}
4749

4850
impl PathResolution {
@@ -63,9 +65,11 @@ impl PathResolution {
6365
PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
6466
Some(TypeNs::TypeAliasId((*alias).into()))
6567
}
66-
PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => {
67-
None
68-
}
68+
PathResolution::BuiltinAttr(_)
69+
| PathResolution::ToolModule(_)
70+
| PathResolution::Local(_)
71+
| PathResolution::Macro(_)
72+
| PathResolution::ConstParam(_) => None,
6973
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
7074
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
7175
PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None,
@@ -334,10 +338,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
334338
self.imp.resolve_path(path)
335339
}
336340

337-
pub fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
338-
self.imp.resolve_path_as_macro(path)
339-
}
340-
341341
pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
342342
self.imp.resolve_extern_crate(extern_crate)
343343
}
@@ -860,12 +860,6 @@ impl<'db> SemanticsImpl<'db> {
860860
self.analyze(path.syntax()).resolve_path(self.db, path)
861861
}
862862

863-
// FIXME: This shouldn't exist, but is currently required to always resolve attribute paths in
864-
// the IDE layer due to namespace collisions
865-
fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
866-
self.analyze(path.syntax()).resolve_path_as_macro(self.db, path)
867-
}
868-
869863
fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
870864
let krate = self.scope(extern_crate.syntax()).krate()?;
871865
krate.dependencies(self.db).into_iter().find_map(|dep| {

crates/hir/src/source_analyzer.rs

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ use syntax::{
2929
};
3030

3131
use crate::{
32-
db::HirDatabase, semantics::PathResolution, Adt, BuiltinType, Const, Field, Function, Local,
33-
MacroDef, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Variant,
32+
db::HirDatabase, semantics::PathResolution, Adt, BuiltinAttr, BuiltinType, Const, Field,
33+
Function, Local, MacroDef, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias,
34+
TypeParam, Variant,
3435
};
3536
use base_db::CrateId;
3637

@@ -246,24 +247,14 @@ impl SourceAnalyzer {
246247
}
247248
}
248249

249-
pub(crate) fn resolve_path_as_macro(
250-
&self,
251-
db: &dyn HirDatabase,
252-
path: &ast::Path,
253-
) -> Option<MacroDef> {
254-
// This must be a normal source file rather than macro file.
255-
let hygiene = Hygiene::new(db.upcast(), self.file_id);
256-
let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
257-
let hir_path = Path::from_src(path.clone(), &ctx)?;
258-
resolve_hir_path_as_macro(db, &self.resolver, &hir_path)
259-
}
260-
261250
pub(crate) fn resolve_path(
262251
&self,
263252
db: &dyn HirDatabase,
264253
path: &ast::Path,
265254
) -> Option<PathResolution> {
266-
let parent = || path.syntax().parent();
255+
let parent = path.syntax().parent();
256+
let parent = || parent.clone();
257+
267258
let mut prefer_value_ns = false;
268259
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
269260
let expr_id = self.expr_id(db, &path_expr.into())?;
@@ -318,29 +309,62 @@ impl SourceAnalyzer {
318309
let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
319310
let hir_path = Path::from_src(path.clone(), &ctx)?;
320311

321-
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
312+
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
322313
// trying to resolve foo::bar.
323-
if let Some(outer_path) = parent().and_then(ast::Path::cast) {
324-
if let Some(qualifier) = outer_path.qualifier() {
325-
if path == &qualifier {
314+
if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
315+
if let Some(qualifier) = use_tree.path() {
316+
if path == &qualifier && use_tree.coloncolon_token().is_some() {
326317
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
327318
}
328319
}
329320
}
330-
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
321+
322+
let is_path_of_attr = path
323+
.top_path()
324+
.syntax()
325+
.ancestors()
326+
.nth(2) // Path -> Meta -> Attr
327+
.map_or(false, |it| ast::Attr::can_cast(it.kind()));
328+
329+
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
331330
// trying to resolve foo::bar.
332-
if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
333-
if let Some(qualifier) = use_tree.path() {
334-
if path == &qualifier && use_tree.coloncolon_token().is_some() {
331+
if let Some(outer_path) = path.parent_path() {
332+
if let Some(qualifier) = outer_path.qualifier() {
333+
if path == &qualifier {
335334
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
336335
}
337336
}
337+
} else if is_path_of_attr {
338+
let res = resolve_hir_path_as_macro(db, &self.resolver, &hir_path);
339+
return match res {
340+
Some(_) => res.map(PathResolution::Macro),
341+
None => path.as_single_name_ref().and_then(|name_ref| {
342+
if let builtin @ Some(_) = BuiltinAttr::by_name(&name_ref.text()) {
343+
builtin.map(PathResolution::BuiltinAttr)
344+
} else if let tool @ Some(_) = ToolModule::by_name(&name_ref.text()) {
345+
tool.map(PathResolution::ToolModule)
346+
} else {
347+
None
348+
}
349+
}),
350+
};
338351
}
339352

340-
if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
353+
let res = if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
341354
resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
342355
} else {
343356
resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
357+
};
358+
match res {
359+
Some(_) => res,
360+
// this labels any path that starts with a tool module as the tool itself, this is technically wrong
361+
// but there is no benefit in differentiating these two cases for the time being
362+
None if is_path_of_attr => path
363+
.first_segment()
364+
.and_then(|seg| seg.name_ref())
365+
.and_then(|name_ref| ToolModule::by_name(&name_ref.text()))
366+
.map(PathResolution::ToolModule),
367+
None => None,
344368
}
345369
}
346370

crates/hir_def/src/builtin_attr.rs

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,100 @@
22
//!
33
//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`.
44
//!
5-
//! It was last synchronized with upstream commit 835150e70288535bc57bb624792229b9dc94991d.
5+
//! It was last synchronized with upstream commit ae90dcf0207c57c3034f00b07048d63f8b2363c8.
66
//!
77
//! The macros were adjusted to only expand to the attribute name, since that is all we need to do
88
//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
99
//! ease updating.
1010
11+
use once_cell::sync::OnceCell;
12+
use rustc_hash::FxHashMap;
13+
1114
/// Ignored attribute namespaces used by tools.
1215
pub const TOOL_MODULES: &[&str] = &["rustfmt", "clippy"];
1316

14-
type BuiltinAttribute = &'static str;
17+
pub struct BuiltinAttribute {
18+
pub name: &'static str,
19+
pub template: AttributeTemplate,
20+
}
21+
22+
/// A template that the attribute input must match.
23+
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
24+
#[derive(Clone, Copy)]
25+
pub struct AttributeTemplate {
26+
pub word: bool,
27+
pub list: Option<&'static str>,
28+
pub name_value_str: Option<&'static str>,
29+
}
30+
31+
pub fn find_builtin_attr_idx(name: &str) -> Option<usize> {
32+
static BUILTIN_LOOKUP_TABLE: OnceCell<FxHashMap<&'static str, usize>> = OnceCell::new();
33+
BUILTIN_LOOKUP_TABLE
34+
.get_or_init(|| {
35+
INERT_ATTRIBUTES.iter().map(|attr| attr.name).enumerate().map(|(a, b)| (b, a)).collect()
36+
})
37+
.get(name)
38+
.copied()
39+
}
40+
41+
// impl AttributeTemplate {
42+
// const DEFAULT: AttributeTemplate =
43+
// AttributeTemplate { word: false, list: None, name_value_str: None };
44+
// }
45+
46+
/// A convenience macro for constructing attribute templates.
47+
/// E.g., `template!(Word, List: "description")` means that the attribute
48+
/// supports forms `#[attr]` and `#[attr(description)]`.
49+
macro_rules! template {
50+
(Word) => { template!(@ true, None, None) };
51+
(List: $descr: expr) => { template!(@ false, Some($descr), None) };
52+
(NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) };
53+
(Word, List: $descr: expr) => { template!(@ true, Some($descr), None) };
54+
(Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) };
55+
(List: $descr1: expr, NameValueStr: $descr2: expr) => {
56+
template!(@ false, Some($descr1), Some($descr2))
57+
};
58+
(Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
59+
template!(@ true, Some($descr1), Some($descr2))
60+
};
61+
(@ $word: expr, $list: expr, $name_value_str: expr) => {
62+
AttributeTemplate {
63+
word: $word, list: $list, name_value_str: $name_value_str
64+
}
65+
};
66+
}
1567

1668
macro_rules! ungated {
1769
($attr:ident, $typ:expr, $tpl:expr $(,)?) => {
18-
stringify!($attr)
70+
BuiltinAttribute { name: stringify!($attr), template: $tpl }
1971
};
2072
}
2173

2274
macro_rules! gated {
23-
($attr:ident $($rest:tt)*) => {
24-
stringify!($attr)
75+
($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => {
76+
BuiltinAttribute { name: stringify!($attr), template: $tpl }
77+
};
78+
($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
79+
BuiltinAttribute { name: stringify!($attr), template: $tpl }
2580
};
2681
}
2782

2883
macro_rules! rustc_attr {
29-
(TEST, $attr:ident $($rest:tt)*) => {
30-
stringify!($attr)
84+
(TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => {
85+
rustc_attr!(
86+
$attr,
87+
$typ,
88+
$tpl,
89+
concat!(
90+
"the `#[",
91+
stringify!($attr),
92+
"]` attribute is just used for rustc unit tests \
93+
and will never be stable",
94+
),
95+
)
3196
};
32-
($attr:ident $($rest:tt)*) => {
33-
stringify!($attr)
97+
($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
98+
BuiltinAttribute { name: stringify!($attr), template: $tpl }
3499
};
35100
}
36101

@@ -158,8 +223,8 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
158223

159224
// Plugins:
160225
// XXX Modified for use in rust-analyzer
161-
gated!(plugin_registrar),
162-
gated!(plugin),
226+
gated!(plugin_registrar, Normal, template!(Word), experimental!()),
227+
gated!(plugin, CrateLevel, template!(Word), experimental!()),
163228

164229
// Testing:
165230
gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)),
@@ -195,6 +260,12 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
195260
),
196261

197262
gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
263+
// RFC 2632
264+
gated!(
265+
default_method_body_is_const, AssumedUsed, template!(Word), const_trait_impl,
266+
"`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
267+
as `const`, which may be removed or renamed in the future."
268+
),
198269

199270
// ==========================================================================
200271
// Internal attributes: Stability, deprecation, and unsafe:
@@ -258,10 +329,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
258329
),
259330
gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)),
260331
gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)),
261-
gated!(
262-
unwind, AssumedUsed, template!(List: "allowed|aborts"), unwind_attributes,
263-
experimental!(unwind),
264-
),
265332
gated!(
266333
compiler_builtins, AssumedUsed, template!(Word),
267334
"the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
@@ -287,7 +354,11 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
287354
// Internal attributes, Macro related:
288355
// ==========================================================================
289356

290-
rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL),
357+
rustc_attr!(
358+
rustc_builtin_macro, AssumedUsed,
359+
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
360+
IMPL_DETAIL,
361+
),
291362
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
292363
rustc_attr!(
293364
rustc_macro_transparency, AssumedUsed,
@@ -344,7 +415,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
344415
lang, Normal, template!(NameValueStr: "name"), lang_items,
345416
"language items are subject to change",
346417
),
347-
gated!(rustc_diagnostic_item), // XXX modified in rust-analyzer
418+
gated!(rustc_diagnostic_item, Normal, template!(NameValueStr: "name"), experimental!()), // XXX Modified for use in rust-analyzer
348419
gated!(
349420
// Used in resolve:
350421
prelude_import, AssumedUsed, template!(Word),
@@ -428,6 +499,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
428499
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
429500
rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)),
430501
rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)),
502+
rustc_attr!(TEST, rustc_dump_vtable, AssumedUsed, template!(Word)),
431503
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
432504
gated!(
433505
omit_gdb_pretty_printer_section, AssumedUsed, template!(Word),

0 commit comments

Comments
 (0)