Skip to content

Commit b8d2699

Browse files
Merge #9060
9060: feat: Diagnose unimplemented built-in macros r=matklad a=jonas-schievink A number of built-in attribute macros are unsupported, I thought it might be useful to put a diagnostic on their definition in libcore. Not sure. Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
2 parents d7cbb49 + cb5454d commit b8d2699

File tree

6 files changed

+87
-18
lines changed

6 files changed

+87
-18
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,27 @@ impl Diagnostic for MacroError {
227227
true
228228
}
229229
}
230+
231+
#[derive(Debug)]
232+
pub struct UnimplementedBuiltinMacro {
233+
pub file: HirFileId,
234+
pub node: SyntaxNodePtr,
235+
}
236+
237+
impl Diagnostic for UnimplementedBuiltinMacro {
238+
fn code(&self) -> DiagnosticCode {
239+
DiagnosticCode("unimplemented-builtin-macro")
240+
}
241+
242+
fn message(&self) -> String {
243+
"unimplemented built-in macro".to_string()
244+
}
245+
246+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
247+
InFile::new(self.file, self.node.clone())
248+
}
249+
250+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
251+
self
252+
}
253+
}

crates/hir/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ use std::{iter, sync::Arc};
3636
use arrayvec::ArrayVec;
3737
use base_db::{CrateDisplayName, CrateId, Edition, FileId};
3838
use diagnostics::{
39-
InactiveCode, MacroError, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
40-
UnresolvedModule, UnresolvedProcMacro,
39+
InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
40+
UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
4141
};
4242
use either::Either;
4343
use hir_def::{
@@ -565,6 +565,14 @@ impl Module {
565565
};
566566
sink.push(MacroError { file, node: ast, message: message.clone() });
567567
}
568+
569+
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
570+
let node = ast.to_node(db.upcast());
571+
// Must have a name, otherwise we wouldn't emit it.
572+
let name = node.name().expect("unimplemented builtin macro with no name");
573+
let ptr = SyntaxNodePtr::from(AstPtr::new(&name));
574+
sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr });
575+
}
568576
}
569577
}
570578
for decl in self.declarations(db) {

crates/hir_def/src/nameres/collector.rs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,14 +1679,22 @@ impl ModCollector<'_, '_> {
16791679
None => &mac.name,
16801680
};
16811681
let krate = self.def_collector.def_map.krate;
1682-
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
1683-
self.def_collector.define_macro_rules(
1684-
self.module_id,
1685-
mac.name.clone(),
1686-
macro_id,
1687-
is_export,
1688-
);
1689-
return;
1682+
match find_builtin_macro(name, krate, ast_id) {
1683+
Some(macro_id) => {
1684+
self.def_collector.define_macro_rules(
1685+
self.module_id,
1686+
mac.name.clone(),
1687+
macro_id,
1688+
is_export,
1689+
);
1690+
return;
1691+
}
1692+
None => {
1693+
self.def_collector
1694+
.def_map
1695+
.diagnostics
1696+
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
1697+
}
16901698
}
16911699
}
16921700

@@ -1715,15 +1723,23 @@ impl ModCollector<'_, '_> {
17151723
let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
17161724
.or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
17171725

1718-
if let Some(macro_id) = macro_id {
1719-
self.def_collector.define_macro_def(
1720-
self.module_id,
1721-
mac.name.clone(),
1722-
macro_id,
1723-
&self.item_tree[mac.visibility],
1724-
);
1726+
match macro_id {
1727+
Some(macro_id) => {
1728+
self.def_collector.define_macro_def(
1729+
self.module_id,
1730+
mac.name.clone(),
1731+
macro_id,
1732+
&self.item_tree[mac.visibility],
1733+
);
1734+
return;
1735+
}
1736+
None => {
1737+
self.def_collector
1738+
.def_map
1739+
.diagnostics
1740+
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
1741+
}
17251742
}
1726-
return;
17271743
}
17281744

17291745
// Case 2: normal `macro`

crates/hir_def/src/nameres/diagnostics.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub enum DefDiagnosticKind {
2727
UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
2828

2929
MacroError { ast: MacroCallKind, message: String },
30+
31+
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
3032
}
3133

3234
#[derive(Debug, PartialEq, Eq)]
@@ -93,4 +95,11 @@ impl DefDiagnostic {
9395
) -> Self {
9496
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
9597
}
98+
99+
pub(super) fn unimplemented_builtin_macro(
100+
container: LocalModuleId,
101+
ast: AstId<ast::Macro>,
102+
) -> Self {
103+
Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } }
104+
}
96105
}

crates/hir_def/src/test_db.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,13 @@ impl TestDB {
298298
DefDiagnosticKind::MacroError { ast, message } => {
299299
(ast.to_node(self.upcast()), message.as_str())
300300
}
301+
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
302+
let node = ast.to_node(self.upcast());
303+
(
304+
InFile::new(ast.file_id, node.syntax().clone()),
305+
"UnimplementedBuiltinMacro",
306+
)
307+
}
301308
};
302309

303310
let frange = node.as_ref().original_file_range(self);

crates/ide/src/diagnostics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ pub(crate) fn diagnostics(
182182
res.borrow_mut()
183183
.push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code())));
184184
})
185+
.on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
186+
let display_range = sema.diagnostics_display_range(d.display_source()).range;
187+
res.borrow_mut()
188+
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
189+
})
185190
// Only collect experimental diagnostics when they're enabled.
186191
.filter(|diag| !(diag.is_experimental() && config.disable_experimental))
187192
.filter(|diag| !config.disabled.contains(diag.code().as_str()));

0 commit comments

Comments
 (0)