Skip to content

Commit 3b1692c

Browse files
Merge #8443 #8446
8443: Rewrite `#[derive]` removal code to be based on AST r=jonas-schievink a=jonas-schievink We now remove any `#[derive]` before and including the one we want to expand, in the `macro_arg` query. The same infra will be needed by attribute macros (except we only remove the attribute we're expanding, not any preceding ones). Part of #8434 (doesn't implement the cfg-expansion yet, because that's more difficult) 8446: Undo path resolution hack for extern prelude r=jonas-schievink a=jonas-schievink Reverts the change made in #7959 We don't populate the extern prelude for block DefMaps anymore, so this is unnecessary bors r+ Co-authored-by: Jonas Schievink <[email protected]>
3 parents 972e1f4 + d6187de + 4ea5f69 commit 3b1692c

File tree

10 files changed

+149
-143
lines changed

10 files changed

+149
-143
lines changed

crates/hir_def/src/attr.rs

+20-17
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{
99
use base_db::CrateId;
1010
use cfg::{CfgExpr, CfgOptions};
1111
use either::Either;
12-
use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile};
12+
use hir_expand::{hygiene::Hygiene, name::AsName, AstId, AttrId, InFile};
1313
use itertools::Itertools;
1414
use la_arena::ArenaMap;
1515
use mbe::ast_to_token_tree;
@@ -98,13 +98,16 @@ impl RawAttrs {
9898
pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
9999
let entries = collect_attrs(owner)
100100
.enumerate()
101-
.flat_map(|(i, attr)| match attr {
102-
Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32),
103-
Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
104-
index: i as u32,
105-
input: Some(AttrInput::Literal(SmolStr::new(doc))),
106-
path: Interned::new(ModPath::from(hir_expand::name!(doc))),
107-
}),
101+
.flat_map(|(i, attr)| {
102+
let index = AttrId(i as u32);
103+
match attr {
104+
Either::Left(attr) => Attr::from_src(attr, hygiene, index),
105+
Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
106+
id: index,
107+
input: Some(AttrInput::Literal(SmolStr::new(doc))),
108+
path: Interned::new(ModPath::from(hir_expand::name!(doc))),
109+
}),
110+
}
108111
})
109112
.collect::<Arc<_>>();
110113

@@ -161,7 +164,7 @@ impl RawAttrs {
161164
let cfg = parts.next().unwrap();
162165
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
163166
let cfg = CfgExpr::parse(&cfg);
164-
let index = attr.index;
167+
let index = attr.id;
165168
let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
166169
let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
167170
let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
@@ -468,7 +471,7 @@ impl AttrsWithOwner {
468471
) -> Option<(Documentation, DocsRangeMap)> {
469472
// FIXME: code duplication in `docs` above
470473
let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? {
471-
AttrInput::Literal(s) => Some((s, attr.index)),
474+
AttrInput::Literal(s) => Some((s, attr.id)),
472475
AttrInput::TokenTree(_) => None,
473476
});
474477
let indent = docs
@@ -560,8 +563,8 @@ impl AttrSourceMap {
560563
/// the attribute represented by `Attr`.
561564
pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
562565
self.attrs
563-
.get(attr.index as usize)
564-
.unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index))
566+
.get(attr.id.0 as usize)
567+
.unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", attr.id))
565568
.as_ref()
566569
}
567570
}
@@ -572,7 +575,7 @@ pub struct DocsRangeMap {
572575
// (docstring-line-range, attr_index, attr-string-range)
573576
// a mapping from the text range of a line of the [`Documentation`] to the attribute index and
574577
// the original (untrimmed) syntax doc line
575-
mapping: Vec<(TextRange, u32, TextRange)>,
578+
mapping: Vec<(TextRange, AttrId, TextRange)>,
576579
}
577580

578581
impl DocsRangeMap {
@@ -585,7 +588,7 @@ impl DocsRangeMap {
585588

586589
let relative_range = range - line_docs_range.start();
587590

588-
let &InFile { file_id, value: ref source } = &self.source[idx as usize];
591+
let &InFile { file_id, value: ref source } = &self.source[idx.0 as usize];
589592
match source {
590593
Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here
591594
// as well as for whats done in syntax highlight doc injection
@@ -606,7 +609,7 @@ impl DocsRangeMap {
606609

607610
#[derive(Debug, Clone, PartialEq, Eq)]
608611
pub struct Attr {
609-
index: u32,
612+
pub(crate) id: AttrId,
610613
pub(crate) path: Interned<ModPath>,
611614
pub(crate) input: Option<AttrInput>,
612615
}
@@ -620,7 +623,7 @@ pub enum AttrInput {
620623
}
621624

622625
impl Attr {
623-
fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
626+
fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> {
624627
let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
625628
let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
626629
let value = match lit.kind() {
@@ -633,7 +636,7 @@ impl Attr {
633636
} else {
634637
None
635638
};
636-
Some(Attr { index, path, input })
639+
Some(Attr { id, path, input })
637640
}
638641

639642
/// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths

crates/hir_def/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use hir_expand::{
6262
ast_id_map::FileAstId,
6363
eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
6464
hygiene::Hygiene,
65-
AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
65+
AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
6666
};
6767
use la_arena::Idx;
6868
use nameres::DefMap;
@@ -699,6 +699,7 @@ fn macro_call_as_call_id(
699699

700700
fn derive_macro_as_call_id(
701701
item_attr: &AstIdWithPath<ast::Item>,
702+
derive_attr: AttrId,
702703
db: &dyn db::DefDatabase,
703704
krate: CrateId,
704705
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
@@ -712,6 +713,7 @@ fn derive_macro_as_call_id(
712713
MacroCallKind::Derive {
713714
ast_id: item_attr.ast_id,
714715
derive_name: last_segment.to_string(),
716+
derive_attr,
715717
},
716718
)
717719
.into();

crates/hir_def/src/nameres.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ mod diagnostics {
617617
let node = ast_id.to_node(db.upcast());
618618
(ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
619619
}
620-
MacroCallKind::Derive { ast_id, derive_name } => {
620+
MacroCallKind::Derive { ast_id, derive_name, .. } => {
621621
let node = ast_id.to_node(db.upcast());
622622

623623
// Compute the precise location of the macro name's token in the derive

crates/hir_def/src/nameres/collector.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use hir_expand::{
1313
builtin_macro::find_builtin_macro,
1414
name::{AsName, Name},
1515
proc_macro::ProcMacroExpander,
16-
HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
16+
AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
1717
};
1818
use hir_expand::{InFile, MacroCallLoc};
1919
use rustc_hash::{FxHashMap, FxHashSet};
@@ -216,7 +216,7 @@ struct MacroDirective {
216216
#[derive(Clone, Debug, Eq, PartialEq)]
217217
enum MacroDirectiveKind {
218218
FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
219-
Derive { ast_id: AstIdWithPath<ast::Item> },
219+
Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
220220
}
221221

222222
struct DefData<'a> {
@@ -831,10 +831,14 @@ impl DefCollector<'_> {
831831
Err(UnresolvedMacro) | Ok(Err(_)) => {}
832832
}
833833
}
834-
MacroDirectiveKind::Derive { ast_id } => {
835-
match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| {
836-
self.resolve_derive_macro(directive.module_id, &path)
837-
}) {
834+
MacroDirectiveKind::Derive { ast_id, derive_attr } => {
835+
match derive_macro_as_call_id(
836+
ast_id,
837+
*derive_attr,
838+
self.db,
839+
self.def_map.krate,
840+
|path| self.resolve_derive_macro(directive.module_id, &path),
841+
) {
838842
Ok(call_id) => {
839843
resolved.push((directive.module_id, call_id, directive.depth));
840844
res = ReachedFixedPoint::No;
@@ -1368,7 +1372,7 @@ impl ModCollector<'_, '_> {
13681372
self.def_collector.unexpanded_macros.push(MacroDirective {
13691373
module_id: self.module_id,
13701374
depth: self.macro_depth + 1,
1371-
kind: MacroDirectiveKind::Derive { ast_id },
1375+
kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
13721376
});
13731377
}
13741378
}

crates/hir_def/src/nameres/path_resolution.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -384,15 +384,10 @@ impl DefMap {
384384
}
385385
}
386386
};
387-
// Give precedence to names in outer `DefMap`s over the extern prelude; only check prelude
388-
// from the crate DefMap.
389-
let from_extern_prelude = match self.block {
390-
Some(_) => PerNs::none(),
391-
None => self
392-
.extern_prelude
393-
.get(name)
394-
.map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)),
395-
};
387+
let from_extern_prelude = self
388+
.extern_prelude
389+
.get(name)
390+
.map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
396391

397392
let from_prelude = self.resolve_in_prelude(db, name);
398393

crates/hir_expand/src/builtin_derive.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ mod tests {
269269
use expect_test::{expect, Expect};
270270
use name::AsName;
271271

272-
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
272+
use crate::{test_db::TestDB, AstId, AttrId, MacroCallId, MacroCallKind, MacroCallLoc};
273273

274274
use super::*;
275275

@@ -317,7 +317,11 @@ $0
317317
local_inner: false,
318318
},
319319
krate: CrateId(0),
320-
kind: MacroCallKind::Derive { ast_id, derive_name: name.to_string() },
320+
kind: MacroCallKind::Derive {
321+
ast_id,
322+
derive_name: name.to_string(),
323+
derive_attr: AttrId(0),
324+
},
321325
};
322326

323327
let id: MacroCallId = db.intern_macro(loc).into();

crates/hir_expand/src/db.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use syntax::{
1414
};
1515

1616
use crate::{
17-
ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander,
18-
EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc,
19-
MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
17+
ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander,
18+
BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId,
19+
MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
2020
};
2121

2222
/// Total limit on the number of tokens produced by any macro invocation.
@@ -191,6 +191,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
191191
};
192192
let loc = db.lookup_intern_macro(id);
193193
let arg = loc.kind.arg(db)?;
194+
let arg = process_macro_input(db, arg, id);
194195
Some(arg.green())
195196
}
196197

crates/hir_expand/src/input.rs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//! Macro input conditioning.
2+
3+
use syntax::{
4+
ast::{self, AttrsOwner},
5+
AstNode, SyntaxNode,
6+
};
7+
8+
use crate::{
9+
db::AstDatabase,
10+
name::{name, AsName},
11+
AttrId, LazyMacroId, MacroCallKind, MacroCallLoc,
12+
};
13+
14+
pub(crate) fn process_macro_input(
15+
db: &dyn AstDatabase,
16+
node: SyntaxNode,
17+
id: LazyMacroId,
18+
) -> SyntaxNode {
19+
let loc: MacroCallLoc = db.lookup_intern_macro(id);
20+
21+
match loc.kind {
22+
MacroCallKind::FnLike { .. } => node,
23+
MacroCallKind::Derive { derive_attr, .. } => {
24+
let item = match ast::Item::cast(node.clone()) {
25+
Some(item) => item,
26+
None => return node,
27+
};
28+
29+
remove_derives_up_to(item, derive_attr).syntax().clone()
30+
}
31+
}
32+
}
33+
34+
/// Removes `#[derive]` attributes from `item`, up to `attr`.
35+
fn remove_derives_up_to(item: ast::Item, attr: AttrId) -> ast::Item {
36+
let item = item.clone_for_update();
37+
let idx = attr.0 as usize;
38+
for attr in item.attrs().take(idx + 1) {
39+
if let Some(name) =
40+
attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref())
41+
{
42+
if name.as_name() == name![derive] {
43+
attr.syntax().detach();
44+
}
45+
}
46+
}
47+
item
48+
}
49+
50+
#[cfg(test)]
51+
mod tests {
52+
use base_db::fixture::WithFixture;
53+
use base_db::SourceDatabase;
54+
use expect_test::{expect, Expect};
55+
56+
use crate::test_db::TestDB;
57+
58+
use super::*;
59+
60+
fn test_remove_derives_up_to(attr: AttrId, ra_fixture: &str, expect: Expect) {
61+
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
62+
let parsed = db.parse(file_id);
63+
64+
let mut items: Vec<_> =
65+
parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect();
66+
assert_eq!(items.len(), 1);
67+
68+
let item = remove_derives_up_to(items.pop().unwrap(), attr);
69+
expect.assert_eq(&item.to_string());
70+
}
71+
72+
#[test]
73+
fn remove_derive() {
74+
test_remove_derives_up_to(
75+
AttrId(2),
76+
r#"
77+
#[allow(unused)]
78+
#[derive(Copy)]
79+
#[derive(Hello)]
80+
#[derive(Clone)]
81+
struct A {
82+
bar: u32
83+
}
84+
"#,
85+
expect![[r#"
86+
#[allow(unused)]
87+
88+
89+
#[derive(Clone)]
90+
struct A {
91+
bar: u32
92+
}"#]],
93+
);
94+
}
95+
}

crates/hir_expand/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod builtin_macro;
1414
pub mod proc_macro;
1515
pub mod quote;
1616
pub mod eager;
17+
mod input;
1718

1819
use either::Either;
1920
pub use mbe::{ExpandError, ExpandResult};
@@ -291,9 +292,12 @@ pub struct MacroCallLoc {
291292
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
292293
pub enum MacroCallKind {
293294
FnLike { ast_id: AstId<ast::MacroCall> },
294-
Derive { ast_id: AstId<ast::Item>, derive_name: String },
295+
Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId },
295296
}
296297

298+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
299+
pub struct AttrId(pub u32);
300+
297301
impl MacroCallKind {
298302
fn file_id(&self) -> HirFileId {
299303
match self {

0 commit comments

Comments
 (0)