mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 18:53:39 +00:00
internal: move derived tests to the unified macro infra
This commit is contained in:
parent
55d8be5a24
commit
5af80d8372
@ -11,6 +11,7 @@
|
||||
|
||||
mod mbe;
|
||||
mod builtin_fn_macro;
|
||||
mod builtin_derive_macro;
|
||||
|
||||
use std::{iter, ops::Range};
|
||||
|
||||
@ -26,7 +27,8 @@ use syntax::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, test_db::TestDB, AsMacroCall,
|
||||
db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, src::HasSource, test_db::TestDB,
|
||||
AsMacroCall, Lookup,
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
@ -43,6 +45,21 @@ fn check(ra_fixture: &str, mut expect: Expect) {
|
||||
ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(),
|
||||
};
|
||||
|
||||
// What we want to do is to replace all macros (fn-like, derive, attr) with
|
||||
// their expansions. Turns out, we don't actually store enough information
|
||||
// to do this precisely though! Specifically, if a macro expands to nothing,
|
||||
// it leaves zero traces in def-map, so we can't get its expansion after the
|
||||
// fact.
|
||||
//
|
||||
// This is the usual
|
||||
// <https://github.com/rust-analyzer/rust-analyzer/issues/3407>
|
||||
// resolve/record tension!
|
||||
//
|
||||
// So here we try to do a resolve, which is necessary a heuristic. For macro
|
||||
// calls, we use `as_call_id_with_errors`. For derives, we look at the impls
|
||||
// in the module and assume that, if impls's source is a different
|
||||
// `HirFileId`, than it came from macro expansion.
|
||||
|
||||
let mut expansions = Vec::new();
|
||||
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
||||
@ -63,6 +80,7 @@ fn check(ra_fixture: &str, mut expect: Expect) {
|
||||
}
|
||||
|
||||
let mut expanded_text = source_file.to_string();
|
||||
|
||||
for (call, exp) in expansions.into_iter().rev() {
|
||||
let mut tree = false;
|
||||
let mut expect_errors = false;
|
||||
@ -106,6 +124,14 @@ fn check(ra_fixture: &str, mut expect: Expect) {
|
||||
expanded_text.replace_range(range, &expn_text)
|
||||
}
|
||||
|
||||
for impl_id in def_map[local_id].scope.impls() {
|
||||
let src = impl_id.lookup(&db).source(&db);
|
||||
if src.file_id.is_builtin_derive(&db).is_some() {
|
||||
let pp = pretty_print_macro_expansion(src.value.syntax().clone());
|
||||
format_to!(expanded_text, "\n{}", pp)
|
||||
}
|
||||
}
|
||||
|
||||
expect.indent(false);
|
||||
expect.assert_eq(&expanded_text);
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
//! Tests for `builtin_derive_macro.rs` from `hir_expand`.
|
||||
|
||||
use expect_test::expect;
|
||||
|
||||
use crate::macro_expansion_tests::check;
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_simple() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: derive, copy
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r##"
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
|
||||
impl < > core::marker::Copy for Foo< > {}"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_with_type_params() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: derive, copy
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B>;
|
||||
"#,
|
||||
expect![[r##"
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B>;
|
||||
|
||||
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_with_lifetimes() {
|
||||
// We currently just ignore lifetimes
|
||||
check(
|
||||
r#"
|
||||
//- minicore: derive, copy
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B, 'a, 'b>;
|
||||
"#,
|
||||
expect![[r##"
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B, 'a, 'b>;
|
||||
|
||||
impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_expand() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: derive, clone
|
||||
#[derive(Clone)]
|
||||
struct Foo<A, B>;
|
||||
"#,
|
||||
expect![[r##"
|
||||
#[derive(Clone)]
|
||||
struct Foo<A, B>;
|
||||
|
||||
impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
|
||||
);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//! Tests for builtin macros (see `builtin_macro.rs` in `hir_expand`).
|
||||
//! Tests for `builtin_fn_macro.rs` from `hir_expand`.
|
||||
|
||||
use expect_test::expect;
|
||||
|
||||
|
@ -258,128 +258,3 @@ fn partial_ord_expand(
|
||||
let krate = find_builtin_crate(db, id);
|
||||
expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use base_db::{fixture::WithFixture, CrateId, SourceDatabase};
|
||||
use expect_test::{expect, Expect};
|
||||
use name::AsName;
|
||||
|
||||
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn expand_builtin_derive(ra_fixture: &str) -> String {
|
||||
let fixture = format!(
|
||||
r#"//- /main.rs crate:main deps:core
|
||||
$0
|
||||
{}
|
||||
//- /lib.rs crate:core
|
||||
// empty
|
||||
"#,
|
||||
ra_fixture
|
||||
);
|
||||
|
||||
let (db, file_pos) = TestDB::with_position(&fixture);
|
||||
let file_id = file_pos.file_id;
|
||||
let ast_id_map = db.ast_id_map(file_id.into());
|
||||
let parsed = db.parse(file_id);
|
||||
let macros: Vec<_> =
|
||||
parsed.syntax_node().descendants().filter_map(ast::Macro::cast).collect();
|
||||
let items: Vec<_> = parsed
|
||||
.syntax_node()
|
||||
.descendants()
|
||||
.filter(|node| !ast::Macro::can_cast(node.kind()))
|
||||
.filter_map(ast::Item::cast)
|
||||
.collect();
|
||||
|
||||
assert_eq!(macros.len(), 1, "test must contain exactly 1 macro definition");
|
||||
assert_eq!(items.len(), 1, "test must contain exactly 1 item");
|
||||
|
||||
let macro_ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯os[0]));
|
||||
let name = match ¯os[0] {
|
||||
ast::Macro::MacroRules(rules) => rules.name().unwrap().as_name(),
|
||||
ast::Macro::MacroDef(def) => def.name().unwrap().as_name(),
|
||||
};
|
||||
|
||||
let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
|
||||
|
||||
let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
|
||||
|
||||
let loc = MacroCallLoc {
|
||||
def: MacroDefId {
|
||||
krate: CrateId(0),
|
||||
kind: MacroDefKind::BuiltInDerive(expander, macro_ast_id),
|
||||
local_inner: false,
|
||||
},
|
||||
krate: CrateId(0),
|
||||
eager: None,
|
||||
kind: MacroCallKind::Derive {
|
||||
ast_id,
|
||||
derive_name: name.to_string(),
|
||||
derive_attr_index: 0,
|
||||
},
|
||||
};
|
||||
|
||||
let id: MacroCallId = db.intern_macro(loc);
|
||||
let parsed = db.parse_or_expand(id.as_file()).unwrap();
|
||||
|
||||
// FIXME text() for syntax nodes parsed from token tree looks weird
|
||||
// because there's no whitespace, see below
|
||||
parsed.text().to_string()
|
||||
}
|
||||
|
||||
fn check_derive(ra_fixture: &str, expected: Expect) {
|
||||
let expanded = expand_builtin_derive(ra_fixture);
|
||||
expected.assert_eq(&expanded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_simple() {
|
||||
check_derive(
|
||||
r#"
|
||||
macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![["impl< >core::marker::CopyforFoo< >{}"]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_with_type_params() {
|
||||
check_derive(
|
||||
r#"
|
||||
macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B>;
|
||||
"#,
|
||||
expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_expand_with_lifetimes() {
|
||||
check_derive(
|
||||
r#"
|
||||
macro Copy {}
|
||||
#[derive(Copy)]
|
||||
struct Foo<A, B, 'a, 'b>;
|
||||
"#,
|
||||
// We currently just ignore lifetimes
|
||||
expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_expand() {
|
||||
check_derive(
|
||||
r#"
|
||||
macro Clone {}
|
||||
#[derive(Clone)]
|
||||
struct Foo<A, B>;
|
||||
"#,
|
||||
expect![["impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user