mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 20:09:19 +00:00
Diagnose unimplemented built-in macros
This commit is contained in:
parent
06b301e2f8
commit
cb5454db86
6 changed files with 87 additions and 18 deletions
|
@ -227,3 +227,27 @@ impl Diagnostic for MacroError {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnimplementedBuiltinMacro {
|
||||||
|
pub file: HirFileId,
|
||||||
|
pub node: SyntaxNodePtr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostic for UnimplementedBuiltinMacro {
|
||||||
|
fn code(&self) -> DiagnosticCode {
|
||||||
|
DiagnosticCode("unimplemented-builtin-macro")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"unimplemented built-in macro".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_source(&self) -> InFile<SyntaxNodePtr> {
|
||||||
|
InFile::new(self.file, self.node.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &(dyn Any + Send + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ use std::{iter, sync::Arc};
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use base_db::{CrateDisplayName, CrateId, Edition, FileId};
|
use base_db::{CrateDisplayName, CrateId, Edition, FileId};
|
||||||
use diagnostics::{
|
use diagnostics::{
|
||||||
InactiveCode, MacroError, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
|
InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
|
||||||
UnresolvedModule, UnresolvedProcMacro,
|
UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
|
||||||
};
|
};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
@ -565,6 +565,14 @@ impl Module {
|
||||||
};
|
};
|
||||||
sink.push(MacroError { file, node: ast, message: message.clone() });
|
sink.push(MacroError { file, node: ast, message: message.clone() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
|
||||||
|
let node = ast.to_node(db.upcast());
|
||||||
|
// Must have a name, otherwise we wouldn't emit it.
|
||||||
|
let name = node.name().expect("unimplemented builtin macro with no name");
|
||||||
|
let ptr = SyntaxNodePtr::from(AstPtr::new(&name));
|
||||||
|
sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for decl in self.declarations(db) {
|
for decl in self.declarations(db) {
|
||||||
|
|
|
@ -1679,7 +1679,8 @@ impl ModCollector<'_, '_> {
|
||||||
None => &mac.name,
|
None => &mac.name,
|
||||||
};
|
};
|
||||||
let krate = self.def_collector.def_map.krate;
|
let krate = self.def_collector.def_map.krate;
|
||||||
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
|
match find_builtin_macro(name, krate, ast_id) {
|
||||||
|
Some(macro_id) => {
|
||||||
self.def_collector.define_macro_rules(
|
self.def_collector.define_macro_rules(
|
||||||
self.module_id,
|
self.module_id,
|
||||||
mac.name.clone(),
|
mac.name.clone(),
|
||||||
|
@ -1688,6 +1689,13 @@ impl ModCollector<'_, '_> {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
|
self.def_collector
|
||||||
|
.def_map
|
||||||
|
.diagnostics
|
||||||
|
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2: normal `macro_rules!` macro
|
// Case 2: normal `macro_rules!` macro
|
||||||
|
@ -1715,16 +1723,24 @@ impl ModCollector<'_, '_> {
|
||||||
let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
|
let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
|
||||||
.or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
|
.or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
|
||||||
|
|
||||||
if let Some(macro_id) = macro_id {
|
match macro_id {
|
||||||
|
Some(macro_id) => {
|
||||||
self.def_collector.define_macro_def(
|
self.def_collector.define_macro_def(
|
||||||
self.module_id,
|
self.module_id,
|
||||||
mac.name.clone(),
|
mac.name.clone(),
|
||||||
macro_id,
|
macro_id,
|
||||||
&self.item_tree[mac.visibility],
|
&self.item_tree[mac.visibility],
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
|
self.def_collector
|
||||||
|
.def_map
|
||||||
|
.diagnostics
|
||||||
|
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Case 2: normal `macro`
|
// Case 2: normal `macro`
|
||||||
let macro_id = MacroDefId {
|
let macro_id = MacroDefId {
|
||||||
|
|
|
@ -27,6 +27,8 @@ pub enum DefDiagnosticKind {
|
||||||
UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
|
UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
|
||||||
|
|
||||||
MacroError { ast: MacroCallKind, message: String },
|
MacroError { ast: MacroCallKind, message: String },
|
||||||
|
|
||||||
|
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -93,4 +95,11 @@ impl DefDiagnostic {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
|
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn unimplemented_builtin_macro(
|
||||||
|
container: LocalModuleId,
|
||||||
|
ast: AstId<ast::Macro>,
|
||||||
|
) -> Self {
|
||||||
|
Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,6 +298,13 @@ impl TestDB {
|
||||||
DefDiagnosticKind::MacroError { ast, message } => {
|
DefDiagnosticKind::MacroError { ast, message } => {
|
||||||
(ast.to_node(self.upcast()), message.as_str())
|
(ast.to_node(self.upcast()), message.as_str())
|
||||||
}
|
}
|
||||||
|
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
|
||||||
|
let node = ast.to_node(self.upcast());
|
||||||
|
(
|
||||||
|
InFile::new(ast.file_id, node.syntax().clone()),
|
||||||
|
"UnimplementedBuiltinMacro",
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let frange = node.as_ref().original_file_range(self);
|
let frange = node.as_ref().original_file_range(self);
|
||||||
|
|
|
@ -182,6 +182,11 @@ pub(crate) fn diagnostics(
|
||||||
res.borrow_mut()
|
res.borrow_mut()
|
||||||
.push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code())));
|
.push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code())));
|
||||||
})
|
})
|
||||||
|
.on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
|
||||||
|
let display_range = sema.diagnostics_display_range(d.display_source()).range;
|
||||||
|
res.borrow_mut()
|
||||||
|
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
|
||||||
|
})
|
||||||
// Only collect experimental diagnostics when they're enabled.
|
// Only collect experimental diagnostics when they're enabled.
|
||||||
.filter(|diag| !(diag.is_experimental() && config.disable_experimental))
|
.filter(|diag| !(diag.is_experimental() && config.disable_experimental))
|
||||||
.filter(|diag| !config.disabled.contains(diag.code().as_str()));
|
.filter(|diag| !config.disabled.contains(diag.code().as_str()));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue