Skip to content

Commit da5a5ba

Browse files
bors[bot]Veykril
andauthored
Merge #9943
9943: fix: Do not replace items annotated with builtin attrs with the attr input r=Veykril a=Veykril This causes runnables to work for paths that actually resolve to the `test` attribute now. ![Code_aUhX1KQfw3](https://user-images.githubusercontent.com/3757771/129917168-bd9ed3f8-3a08-49d2-930a-4b93efaa8acf.png) Prior to this we replaced items annotated with builtin attributes by the attribute input instead of the item in our dummy expansion which is why the fully written path didn't work as we actually discarded the item while `test` was just ignored. Fixes #9935 Co-authored-by: Lukas Wirth <[email protected]>
2 parents 8dd3a71 + 557df6f commit da5a5ba

File tree

7 files changed

+56
-27
lines changed

7 files changed

+56
-27
lines changed

crates/hir/src/semantics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
173173
self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
174174
}
175175

176+
pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
177+
self.imp.find_file(syntax_node.clone()).file_id
178+
}
179+
176180
pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
177181
self.imp.original_range(node)
178182
}

crates/hir_def/src/builtin_attr.rs

-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ macro_rules! rustc_attr {
3434
};
3535
}
3636

37-
/// Built-in macro-like attributes.
38-
pub const EXTRA_ATTRIBUTES: &[BuiltinAttribute] = &["test", "bench"];
39-
4037
/// "Inert" built-in attributes that have a special meaning to rustc or rustdoc.
4138
#[rustfmt::skip]
4239
pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[

crates/hir_def/src/nameres/collector.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -1712,27 +1712,24 @@ impl ModCollector<'_, '_> {
17121712
if path.kind == PathKind::Plain {
17131713
if let Some(tool_module) = path.segments().first() {
17141714
let tool_module = tool_module.to_string();
1715-
if builtin_attr::TOOL_MODULES
1715+
let is_tool = builtin_attr::TOOL_MODULES
17161716
.iter()
17171717
.copied()
1718-
.chain(self.def_collector.registered_tools.iter().map(|s| &**s))
1719-
.any(|m| tool_module == *m)
1720-
{
1718+
.chain(self.def_collector.registered_tools.iter().map(AsRef::as_ref))
1719+
.any(|m| tool_module == *m);
1720+
if is_tool {
17211721
return true;
17221722
}
17231723
}
17241724

17251725
if let Some(name) = path.as_ident() {
17261726
let name = name.to_string();
1727-
if builtin_attr::INERT_ATTRIBUTES
1727+
let is_inert = builtin_attr::INERT_ATTRIBUTES
17281728
.iter()
1729-
.chain(builtin_attr::EXTRA_ATTRIBUTES)
17301729
.copied()
1731-
.chain(self.def_collector.registered_attrs.iter().map(|s| &**s))
1732-
.any(|attr| name == *attr)
1733-
{
1734-
return true;
1735-
}
1730+
.chain(self.def_collector.registered_attrs.iter().map(AsRef::as_ref))
1731+
.any(|attr| name == *attr);
1732+
return is_inert;
17361733
}
17371734
}
17381735

crates/hir_expand/src/builtin_attr.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ macro_rules! register_builtin {
1717
db: &dyn AstDatabase,
1818
id: MacroCallId,
1919
tt: &tt::Subtree,
20+
item: &tt::Subtree,
2021
) -> Result<tt::Subtree, mbe::ExpandError> {
2122
let expander = match *self {
2223
$( BuiltinAttrExpander::$variant => $expand, )*
2324
};
24-
expander(db, id, tt)
25+
expander(db, id, tt, item)
2526
}
2627

2728
fn find_by_name(name: &name::Name) -> Option<Self> {
@@ -61,7 +62,8 @@ pub fn find_builtin_attr(
6162
fn dummy_attr_expand(
6263
_db: &dyn AstDatabase,
6364
_id: MacroCallId,
64-
tt: &tt::Subtree,
65+
_tt: &tt::Subtree,
66+
item: &tt::Subtree,
6567
) -> Result<tt::Subtree, mbe::ExpandError> {
66-
Ok(tt.clone())
68+
Ok(item.clone())
6769
}

crates/hir_expand/src/db.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ impl TokenExpander {
5454
TokenExpander::MacroDef { mac, .. } => mac.expand(tt),
5555
TokenExpander::Builtin(it) => it.expand(db, id, tt),
5656
// FIXME switch these to ExpandResult as well
57-
TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt).into(),
57+
TokenExpander::BuiltinAttr(it) => match db.macro_arg(id) {
58+
Some(macro_arg) => it.expand(db, id, tt, &macro_arg.0).into(),
59+
None => mbe::ExpandResult::only_err(
60+
mbe::ExpandError::Other("No item argument for attribute".to_string()).into(),
61+
),
62+
},
5863
TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
5964
TokenExpander::ProcMacro(_) => {
6065
// We store the result in salsa db to prevent non-deterministic behavior in

crates/hir_expand/src/lib.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use either::Either;
2222
pub use mbe::{ExpandError, ExpandResult};
2323
pub use parser::FragmentKind;
2424

25-
use std::{hash::Hash, sync::Arc};
25+
use std::{hash::Hash, iter, sync::Arc};
2626

2727
use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
2828
use syntax::{
@@ -454,7 +454,7 @@ impl InFile<SyntaxNode> {
454454
self,
455455
db: &dyn db::AstDatabase,
456456
) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
457-
std::iter::successors(Some(self), move |node| match node.value.parent() {
457+
iter::successors(Some(self), move |node| match node.value.parent() {
458458
Some(parent) => Some(node.with_value(parent)),
459459
None => {
460460
let parent_node = node.file_id.call_node(db)?;
@@ -562,6 +562,23 @@ impl<N: AstNode> InFile<N> {
562562
pub fn syntax(&self) -> InFile<&SyntaxNode> {
563563
self.with_value(self.value.syntax())
564564
}
565+
566+
pub fn nodes_with_attributes<'db>(
567+
self,
568+
db: &'db dyn db::AstDatabase,
569+
) -> impl Iterator<Item = InFile<N>> + 'db
570+
where
571+
N: 'db,
572+
{
573+
iter::successors(Some(self), move |node| {
574+
let InFile { file_id, value } = node.file_id.call_node(db)?;
575+
N::cast(value).map(|n| InFile::new(file_id, n))
576+
})
577+
}
578+
579+
pub fn node_with_attributes(self, db: &dyn db::AstDatabase) -> InFile<N> {
580+
self.nodes_with_attributes(db).last().unwrap()
581+
}
565582
}
566583

567584
/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.

crates/ide/src/runnables.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt;
33
use ast::NameOwner;
44
use cfg::CfgExpr;
55
use either::Either;
6-
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
6+
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, InFile, Semantics};
77
use ide_assists::utils::test_related_attribute;
88
use ide_db::{
99
base_db::{FilePosition, FileRange},
@@ -232,22 +232,26 @@ fn find_related_tests(
232232
let functions = refs.iter().filter_map(|(range, _)| {
233233
let token = file.token_at_offset(range.start()).next()?;
234234
let token = sema.descend_into_macros(token);
235-
token.ancestors().find_map(ast::Fn::cast)
235+
token
236+
.ancestors()
237+
.find_map(ast::Fn::cast)
238+
.map(|f| hir::InFile::new(sema.hir_file_for(f.syntax()), f))
236239
});
237240

238241
for fn_def in functions {
239-
if let Some(runnable) = as_test_runnable(sema, &fn_def) {
242+
// #[test/bench] expands to just the item causing us to lose the attribute, so recover them by going out of the attribute
243+
let InFile { value: fn_def, .. } = &fn_def.node_with_attributes(sema.db);
244+
if let Some(runnable) = as_test_runnable(sema, fn_def) {
240245
// direct test
241246
tests.insert(runnable);
242-
} else if let Some(module) = parent_test_module(sema, &fn_def) {
247+
} else if let Some(module) = parent_test_module(sema, fn_def) {
243248
// indirect test
244-
find_related_tests_in_module(sema, &fn_def, &module, tests);
249+
find_related_tests_in_module(sema, fn_def, &module, tests);
245250
}
246251
}
247252
}
248253
}
249254
}
250-
251255
fn find_related_tests_in_module(
252256
sema: &Semantics<RootDatabase>,
253257
fn_def: &ast::Fn,
@@ -292,7 +296,8 @@ fn parent_test_module(sema: &Semantics<RootDatabase>, fn_def: &ast::Fn) -> Optio
292296
}
293297

294298
pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> {
295-
let func = def.source(sema.db)?;
299+
// #[test/bench] expands to just the item causing us to lose the attribute, so recover them by going out of the attribute
300+
let func = def.source(sema.db)?.node_with_attributes(sema.db);
296301
let name_string = def.name(sema.db).to_string();
297302

298303
let root = def.module(sema.db).krate().root_module(sema.db);
@@ -499,6 +504,8 @@ fn has_test_function_or_multiple_test_submodules(
499504
match item {
500505
hir::ModuleDef::Function(f) => {
501506
if let Some(it) = f.source(sema.db) {
507+
// #[test/bench] expands to just the item causing us to lose the attribute, so recover them by going out of the attribute
508+
let it = it.node_with_attributes(sema.db);
502509
if test_related_attribute(&it.value).is_some() {
503510
return true;
504511
}

0 commit comments

Comments
 (0)