Skip to content

Commit 4360734

Browse files
bors[bot]matklad
andauthored
Merge #10510
10510: internal: move derived tests to the unified macro infra r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 4ff0377 + 5af80d8 commit 4360734

File tree

4 files changed

+98
-127
lines changed

4 files changed

+98
-127
lines changed

crates/hir_def/src/macro_expansion_tests.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
mod mbe;
1313
mod builtin_fn_macro;
14+
mod builtin_derive_macro;
1415

1516
use std::{iter, ops::Range};
1617

@@ -26,7 +27,8 @@ use syntax::{
2627
};
2728

2829
use crate::{
29-
db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, test_db::TestDB, AsMacroCall,
30+
db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, src::HasSource, test_db::TestDB,
31+
AsMacroCall, Lookup,
3032
};
3133

3234
#[track_caller]
@@ -43,6 +45,21 @@ fn check(ra_fixture: &str, mut expect: Expect) {
4345
ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(),
4446
};
4547

48+
// What we want to do is to replace all macros (fn-like, derive, attr) with
49+
// their expansions. Turns out, we don't actually store enough information
50+
// to do this precisely though! Specifically, if a macro expands to nothing,
51+
// it leaves zero traces in def-map, so we can't get its expansion after the
52+
// fact.
53+
//
54+
// This is the usual
55+
// <https://github.com/rust-analyzer/rust-analyzer/issues/3407>
56+
// resolve/record tension!
57+
//
58+
// So here we try to do a resolve, which is necessary a heuristic. For macro
59+
// calls, we use `as_call_id_with_errors`. For derives, we look at the impls
60+
// in the module and assume that, if impls's source is a different
61+
// `HirFileId`, than it came from macro expansion.
62+
4663
let mut expansions = Vec::new();
4764
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
4865
let macro_call = InFile::new(source.file_id, &macro_call);
@@ -63,6 +80,7 @@ fn check(ra_fixture: &str, mut expect: Expect) {
6380
}
6481

6582
let mut expanded_text = source_file.to_string();
83+
6684
for (call, exp) in expansions.into_iter().rev() {
6785
let mut tree = false;
6886
let mut expect_errors = false;
@@ -106,6 +124,14 @@ fn check(ra_fixture: &str, mut expect: Expect) {
106124
expanded_text.replace_range(range, &expn_text)
107125
}
108126

127+
for impl_id in def_map[local_id].scope.impls() {
128+
let src = impl_id.lookup(&db).source(&db);
129+
if src.file_id.is_builtin_derive(&db).is_some() {
130+
let pp = pretty_print_macro_expansion(src.value.syntax().clone());
131+
format_to!(expanded_text, "\n{}", pp)
132+
}
133+
}
134+
109135
expect.indent(false);
110136
expect.assert_eq(&expanded_text);
111137
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! Tests for `builtin_derive_macro.rs` from `hir_expand`.
2+
3+
use expect_test::expect;
4+
5+
use crate::macro_expansion_tests::check;
6+
7+
#[test]
8+
fn test_copy_expand_simple() {
9+
check(
10+
r#"
11+
//- minicore: derive, copy
12+
#[derive(Copy)]
13+
struct Foo;
14+
"#,
15+
expect![[r##"
16+
#[derive(Copy)]
17+
struct Foo;
18+
19+
impl < > core::marker::Copy for Foo< > {}"##]],
20+
);
21+
}
22+
23+
#[test]
24+
fn test_copy_expand_with_type_params() {
25+
check(
26+
r#"
27+
//- minicore: derive, copy
28+
#[derive(Copy)]
29+
struct Foo<A, B>;
30+
"#,
31+
expect![[r##"
32+
#[derive(Copy)]
33+
struct Foo<A, B>;
34+
35+
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
36+
);
37+
}
38+
39+
#[test]
40+
fn test_copy_expand_with_lifetimes() {
41+
// We currently just ignore lifetimes
42+
check(
43+
r#"
44+
//- minicore: derive, copy
45+
#[derive(Copy)]
46+
struct Foo<A, B, 'a, 'b>;
47+
"#,
48+
expect![[r##"
49+
#[derive(Copy)]
50+
struct Foo<A, B, 'a, 'b>;
51+
52+
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
53+
);
54+
}
55+
56+
#[test]
57+
fn test_clone_expand() {
58+
check(
59+
r#"
60+
//- minicore: derive, clone
61+
#[derive(Clone)]
62+
struct Foo<A, B>;
63+
"#,
64+
expect![[r##"
65+
#[derive(Clone)]
66+
struct Foo<A, B>;
67+
68+
impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
69+
);
70+
}

crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Tests for builtin macros (see `builtin_macro.rs` in `hir_expand`).
1+
//! Tests for `builtin_fn_macro.rs` from `hir_expand`.
22
33
use expect_test::expect;
44

crates/hir_expand/src/builtin_derive_macro.rs

Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -258,128 +258,3 @@ fn partial_ord_expand(
258258
let krate = find_builtin_crate(db, id);
259259
expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd })
260260
}
261-
262-
#[cfg(test)]
263-
mod tests {
264-
use base_db::{fixture::WithFixture, CrateId, SourceDatabase};
265-
use expect_test::{expect, Expect};
266-
use name::AsName;
267-
268-
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
269-
270-
use super::*;
271-
272-
fn expand_builtin_derive(ra_fixture: &str) -> String {
273-
let fixture = format!(
274-
r#"//- /main.rs crate:main deps:core
275-
$0
276-
{}
277-
//- /lib.rs crate:core
278-
// empty
279-
"#,
280-
ra_fixture
281-
);
282-
283-
let (db, file_pos) = TestDB::with_position(&fixture);
284-
let file_id = file_pos.file_id;
285-
let ast_id_map = db.ast_id_map(file_id.into());
286-
let parsed = db.parse(file_id);
287-
let macros: Vec<_> =
288-
parsed.syntax_node().descendants().filter_map(ast::Macro::cast).collect();
289-
let items: Vec<_> = parsed
290-
.syntax_node()
291-
.descendants()
292-
.filter(|node| !ast::Macro::can_cast(node.kind()))
293-
.filter_map(ast::Item::cast)
294-
.collect();
295-
296-
assert_eq!(macros.len(), 1, "test must contain exactly 1 macro definition");
297-
assert_eq!(items.len(), 1, "test must contain exactly 1 item");
298-
299-
let macro_ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macros[0]));
300-
let name = match &macros[0] {
301-
ast::Macro::MacroRules(rules) => rules.name().unwrap().as_name(),
302-
ast::Macro::MacroDef(def) => def.name().unwrap().as_name(),
303-
};
304-
305-
let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
306-
307-
let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
308-
309-
let loc = MacroCallLoc {
310-
def: MacroDefId {
311-
krate: CrateId(0),
312-
kind: MacroDefKind::BuiltInDerive(expander, macro_ast_id),
313-
local_inner: false,
314-
},
315-
krate: CrateId(0),
316-
eager: None,
317-
kind: MacroCallKind::Derive {
318-
ast_id,
319-
derive_name: name.to_string(),
320-
derive_attr_index: 0,
321-
},
322-
};
323-
324-
let id: MacroCallId = db.intern_macro(loc);
325-
let parsed = db.parse_or_expand(id.as_file()).unwrap();
326-
327-
// FIXME text() for syntax nodes parsed from token tree looks weird
328-
// because there's no whitespace, see below
329-
parsed.text().to_string()
330-
}
331-
332-
fn check_derive(ra_fixture: &str, expected: Expect) {
333-
let expanded = expand_builtin_derive(ra_fixture);
334-
expected.assert_eq(&expanded);
335-
}
336-
337-
#[test]
338-
fn test_copy_expand_simple() {
339-
check_derive(
340-
r#"
341-
macro Copy {}
342-
#[derive(Copy)]
343-
struct Foo;
344-
"#,
345-
expect![["impl< >core::marker::CopyforFoo< >{}"]],
346-
);
347-
}
348-
349-
#[test]
350-
fn test_copy_expand_with_type_params() {
351-
check_derive(
352-
r#"
353-
macro Copy {}
354-
#[derive(Copy)]
355-
struct Foo<A, B>;
356-
"#,
357-
expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
358-
);
359-
}
360-
361-
#[test]
362-
fn test_copy_expand_with_lifetimes() {
363-
check_derive(
364-
r#"
365-
macro Copy {}
366-
#[derive(Copy)]
367-
struct Foo<A, B, 'a, 'b>;
368-
"#,
369-
// We currently just ignore lifetimes
370-
expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
371-
);
372-
}
373-
374-
#[test]
375-
fn test_clone_expand() {
376-
check_derive(
377-
r#"
378-
macro Clone {}
379-
#[derive(Clone)]
380-
struct Foo<A, B>;
381-
"#,
382-
expect![["impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"]],
383-
);
384-
}
385-
}

0 commit comments

Comments
 (0)