mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-01 03:03:40 +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 mbe;
|
||||||
mod builtin_fn_macro;
|
mod builtin_fn_macro;
|
||||||
|
mod builtin_derive_macro;
|
||||||
|
|
||||||
use std::{iter, ops::Range};
|
use std::{iter, ops::Range};
|
||||||
|
|
||||||
@ -26,7 +27,8 @@ use syntax::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
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]
|
#[track_caller]
|
||||||
@ -43,6 +45,21 @@ fn check(ra_fixture: &str, mut expect: Expect) {
|
|||||||
ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(),
|
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();
|
let mut expansions = Vec::new();
|
||||||
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
||||||
let macro_call = InFile::new(source.file_id, ¯o_call);
|
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();
|
let mut expanded_text = source_file.to_string();
|
||||||
|
|
||||||
for (call, exp) in expansions.into_iter().rev() {
|
for (call, exp) in expansions.into_iter().rev() {
|
||||||
let mut tree = false;
|
let mut tree = false;
|
||||||
let mut expect_errors = 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)
|
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.indent(false);
|
||||||
expect.assert_eq(&expanded_text);
|
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;
|
use expect_test::expect;
|
||||||
|
|
||||||
|
@ -258,128 +258,3 @@ fn partial_ord_expand(
|
|||||||
let krate = find_builtin_crate(db, id);
|
let krate = find_builtin_crate(db, id);
|
||||||
expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd })
|
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