mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Merge #7805
7805: For unresolved macros, hightlight only the last segment r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
7ed2da652d
8 changed files with 208 additions and 108 deletions
|
@ -1,5 +1,7 @@
|
||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule, UnresolvedProcMacro};
|
pub use hir_def::diagnostics::{
|
||||||
|
InactiveCode, UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
|
||||||
|
};
|
||||||
pub use hir_expand::diagnostics::{
|
pub use hir_expand::diagnostics::{
|
||||||
Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
|
Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,13 +16,12 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::find_node_at_offset,
|
algo::find_node_at_offset,
|
||||||
ast::{self, GenericParamsOwner, LoopBodyOwner},
|
ast::{self, GenericParamsOwner, LoopBodyOwner},
|
||||||
match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize,
|
match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
code_model::Access,
|
code_model::Access,
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
diagnostics::Diagnostic,
|
|
||||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||||
AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label,
|
AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label,
|
||||||
|
@ -141,7 +140,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
self.imp.original_range(node)
|
self.imp.original_range(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
|
pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
|
||||||
self.imp.diagnostics_display_range(diagnostics)
|
self.imp.diagnostics_display_range(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,8 +384,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
node.as_ref().original_file_range(self.db.upcast())
|
node.as_ref().original_file_range(self.db.upcast())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
|
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
|
||||||
let src = diagnostics.display_source();
|
|
||||||
let root = self.db.parse_or_expand(src.file_id).unwrap();
|
let root = self.db.parse_or_expand(src.file_id).unwrap();
|
||||||
let node = src.value.to_node(&root);
|
let node = src.value.to_node(&root);
|
||||||
self.cache(root, src.file_id);
|
self.cache(root, src.file_id);
|
||||||
|
|
|
@ -123,7 +123,7 @@ impl Expander {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
if err.is_none() {
|
if err.is_none() {
|
||||||
eprintln!("no error despite `as_call_id_with_errors` returning `None`");
|
log::warn!("no error despite `as_call_id_with_errors` returning `None`");
|
||||||
}
|
}
|
||||||
return ExpandResult { value: None, err };
|
return ExpandResult { value: None, err };
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,34 @@ impl Diagnostic for UnresolvedImport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diagnostic: unresolved-macro-call
|
||||||
|
//
|
||||||
|
// This diagnostic is triggered if rust-analyzer is unable to resolove path to a
|
||||||
|
// macro in a macro invocation.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnresolvedMacroCall {
|
||||||
|
pub file: HirFileId,
|
||||||
|
pub node: AstPtr<ast::MacroCall>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostic for UnresolvedMacroCall {
|
||||||
|
fn code(&self) -> DiagnosticCode {
|
||||||
|
DiagnosticCode("unresolved-macro-call")
|
||||||
|
}
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"unresolved macro call".to_string()
|
||||||
|
}
|
||||||
|
fn display_source(&self) -> InFile<SyntaxNodePtr> {
|
||||||
|
InFile::new(self.file, self.node.clone().into())
|
||||||
|
}
|
||||||
|
fn as_any(&self) -> &(dyn Any + Send + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn is_experimental(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Diagnostic: inactive-code
|
// Diagnostic: inactive-code
|
||||||
//
|
//
|
||||||
// This diagnostic is shown for code with inactive `#[cfg]` attributes.
|
// This diagnostic is shown for code with inactive `#[cfg]` attributes.
|
||||||
|
|
|
@ -57,8 +57,10 @@ use std::{
|
||||||
|
|
||||||
use base_db::{impl_intern_key, salsa, CrateId};
|
use base_db::{impl_intern_key, salsa, CrateId};
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile,
|
ast_id_map::FileAstId,
|
||||||
MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
eager::{expand_eager_macro, ErrorEmitted},
|
||||||
|
hygiene::Hygiene,
|
||||||
|
AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
||||||
};
|
};
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
use nameres::DefMap;
|
use nameres::DefMap;
|
||||||
|
@ -592,8 +594,15 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||||
error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
|
error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
AstIdWithPath::new(ast_id.file_id, ast_id.value, path?)
|
macro_call_as_call_id(
|
||||||
.as_call_id_with_errors(db, krate, resolver, error_sink)
|
&AstIdWithPath::new(ast_id.file_id, ast_id.value, path?),
|
||||||
|
db,
|
||||||
|
krate,
|
||||||
|
resolver,
|
||||||
|
error_sink,
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,61 +619,50 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
|
struct UnresolvedMacro;
|
||||||
fn as_call_id_with_errors(
|
|
||||||
&self,
|
|
||||||
db: &dyn db::DefDatabase,
|
|
||||||
krate: CrateId,
|
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
|
||||||
error_sink: &mut dyn FnMut(mbe::ExpandError),
|
|
||||||
) -> Option<MacroCallId> {
|
|
||||||
let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
|
|
||||||
error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
|
|
||||||
None
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if let MacroDefKind::BuiltInEager(_) = def.kind {
|
fn macro_call_as_call_id(
|
||||||
let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast()));
|
call: &AstIdWithPath<ast::MacroCall>,
|
||||||
let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
|
db: &dyn db::DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
|
error_sink: &mut dyn FnMut(mbe::ExpandError),
|
||||||
|
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
|
||||||
|
let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?;
|
||||||
|
|
||||||
Some(
|
let res = if let MacroDefKind::BuiltInEager(_) = def.kind {
|
||||||
expand_eager_macro(
|
let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
|
||||||
db.upcast(),
|
let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id);
|
||||||
krate,
|
|
||||||
macro_call,
|
|
||||||
def,
|
|
||||||
&|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
|
|
||||||
error_sink,
|
|
||||||
)
|
|
||||||
.ok()?
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsMacroCall for AstIdWithPath<ast::Item> {
|
expand_eager_macro(
|
||||||
fn as_call_id_with_errors(
|
db.upcast(),
|
||||||
&self,
|
krate,
|
||||||
db: &dyn db::DefDatabase,
|
macro_call,
|
||||||
krate: CrateId,
|
def,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
&|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
|
||||||
error_sink: &mut dyn FnMut(mbe::ExpandError),
|
error_sink,
|
||||||
) -> Option<MacroCallId> {
|
|
||||||
let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
|
|
||||||
error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
|
|
||||||
None
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Some(
|
|
||||||
def.as_lazy_macro(
|
|
||||||
db.upcast(),
|
|
||||||
krate,
|
|
||||||
MacroCallKind::Attr(self.ast_id, self.path.segments().last()?.to_string()),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
)
|
)
|
||||||
}
|
.map(MacroCallId::from)
|
||||||
|
} else {
|
||||||
|
Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into())
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item_attr_as_call_id(
|
||||||
|
item_attr: &AstIdWithPath<ast::Item>,
|
||||||
|
db: &dyn db::DefDatabase,
|
||||||
|
krate: CrateId,
|
||||||
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
|
) -> Result<MacroCallId, UnresolvedMacro> {
|
||||||
|
let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?;
|
||||||
|
let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?;
|
||||||
|
let res = def
|
||||||
|
.as_lazy_macro(
|
||||||
|
db.upcast(),
|
||||||
|
krate,
|
||||||
|
MacroCallKind::Attr(item_attr.ast_id, last_segment.to_string()),
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,6 +417,8 @@ mod diagnostics {
|
||||||
|
|
||||||
UnresolvedProcMacro { ast: MacroCallKind },
|
UnresolvedProcMacro { ast: MacroCallKind },
|
||||||
|
|
||||||
|
UnresolvedMacroCall { ast: AstId<ast::MacroCall> },
|
||||||
|
|
||||||
MacroError { ast: MacroCallKind, message: String },
|
MacroError { ast: MacroCallKind, message: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,6 +479,13 @@ mod diagnostics {
|
||||||
Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } }
|
Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn unresolved_macro_call(
|
||||||
|
container: LocalModuleId,
|
||||||
|
ast: AstId<ast::MacroCall>,
|
||||||
|
) -> Self {
|
||||||
|
Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } }
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn add_to(
|
pub(super) fn add_to(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
|
@ -589,6 +598,11 @@ mod diagnostics {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiagnosticKind::UnresolvedMacroCall { ast } => {
|
||||||
|
let node = ast.to_node(db.upcast());
|
||||||
|
sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) });
|
||||||
|
}
|
||||||
|
|
||||||
DiagnosticKind::MacroError { ast, message } => {
|
DiagnosticKind::MacroError { ast, message } => {
|
||||||
let (file, ast) = match ast {
|
let (file, ast) = match ast {
|
||||||
MacroCallKind::FnLike(ast) => {
|
MacroCallKind::FnLike(ast) => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use hir_expand::{
|
||||||
builtin_macro::find_builtin_macro,
|
builtin_macro::find_builtin_macro,
|
||||||
name::{AsName, Name},
|
name::{AsName, Name},
|
||||||
proc_macro::ProcMacroExpander,
|
proc_macro::ProcMacroExpander,
|
||||||
HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
|
||||||
};
|
};
|
||||||
use hir_expand::{InFile, MacroCallLoc};
|
use hir_expand::{InFile, MacroCallLoc};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
@ -24,11 +24,13 @@ use tt::{Leaf, TokenTree};
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
item_attr_as_call_id,
|
||||||
item_scope::{ImportType, PerNsGlobImports},
|
item_scope::{ImportType, PerNsGlobImports},
|
||||||
item_tree::{
|
item_tree::{
|
||||||
self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind,
|
self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind,
|
||||||
StructDefKind,
|
StructDefKind,
|
||||||
},
|
},
|
||||||
|
macro_call_as_call_id,
|
||||||
nameres::{
|
nameres::{
|
||||||
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
|
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
|
||||||
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
|
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
|
||||||
|
@ -36,9 +38,9 @@ use crate::{
|
||||||
path::{ImportAlias, ModPath, PathKind},
|
path::{ImportAlias, ModPath, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
visibility::{RawVisibility, Visibility},
|
visibility::{RawVisibility, Visibility},
|
||||||
AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
|
AdtId, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc,
|
||||||
FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc,
|
ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc,
|
||||||
TypeAliasLoc, UnionLoc,
|
UnionLoc, UnresolvedMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
const GLOB_RECURSION_LIMIT: usize = 100;
|
const GLOB_RECURSION_LIMIT: usize = 100;
|
||||||
|
@ -790,8 +792,11 @@ impl DefCollector<'_> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(call_id) =
|
match macro_call_as_call_id(
|
||||||
directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
|
&directive.ast_id,
|
||||||
|
self.db,
|
||||||
|
self.def_map.krate,
|
||||||
|
|path| {
|
||||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||||
self.db,
|
self.db,
|
||||||
ResolveMode::Other,
|
ResolveMode::Other,
|
||||||
|
@ -800,24 +805,29 @@ impl DefCollector<'_> {
|
||||||
BuiltinShadowMode::Module,
|
BuiltinShadowMode::Module,
|
||||||
);
|
);
|
||||||
resolved_res.resolved_def.take_macros()
|
resolved_res.resolved_def.take_macros()
|
||||||
})
|
},
|
||||||
{
|
&mut |_err| (),
|
||||||
resolved.push((directive.module_id, call_id, directive.depth));
|
) {
|
||||||
res = ReachedFixedPoint::No;
|
Ok(Ok(call_id)) => {
|
||||||
return false;
|
resolved.push((directive.module_id, call_id, directive.depth));
|
||||||
|
res = ReachedFixedPoint::No;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Err(UnresolvedMacro) | Ok(Err(_)) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
attribute_macros.retain(|directive| {
|
attribute_macros.retain(|directive| {
|
||||||
if let Some(call_id) =
|
match item_attr_as_call_id(&directive.ast_id, self.db, self.def_map.krate, |path| {
|
||||||
directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
|
self.resolve_attribute_macro(&directive, &path)
|
||||||
self.resolve_attribute_macro(&directive, &path)
|
}) {
|
||||||
})
|
Ok(call_id) => {
|
||||||
{
|
resolved.push((directive.module_id, call_id, 0));
|
||||||
resolved.push((directive.module_id, call_id, 0));
|
res = ReachedFixedPoint::No;
|
||||||
res = ReachedFixedPoint::No;
|
return false;
|
||||||
return false;
|
}
|
||||||
|
Err(UnresolvedMacro) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -902,7 +912,8 @@ impl DefCollector<'_> {
|
||||||
|
|
||||||
for directive in &self.unexpanded_macros {
|
for directive in &self.unexpanded_macros {
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
directive.ast_id.as_call_id_with_errors(
|
match macro_call_as_call_id(
|
||||||
|
&directive.ast_id,
|
||||||
self.db,
|
self.db,
|
||||||
self.def_map.krate,
|
self.def_map.krate,
|
||||||
|path| {
|
|path| {
|
||||||
|
@ -918,15 +929,15 @@ impl DefCollector<'_> {
|
||||||
&mut |e| {
|
&mut |e| {
|
||||||
error.get_or_insert(e);
|
error.get_or_insert(e);
|
||||||
},
|
},
|
||||||
);
|
) {
|
||||||
|
Ok(_) => (),
|
||||||
if let Some(err) = error {
|
Err(UnresolvedMacro) => {
|
||||||
self.def_map.diagnostics.push(DefDiagnostic::macro_error(
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
||||||
directive.module_id,
|
directive.module_id,
|
||||||
MacroCallKind::FnLike(directive.ast_id.ast_id),
|
directive.ast_id.ast_id,
|
||||||
err.to_string(),
|
));
|
||||||
));
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit diagnostics for all remaining unresolved imports.
|
// Emit diagnostics for all remaining unresolved imports.
|
||||||
|
@ -1446,8 +1457,11 @@ impl ModCollector<'_, '_> {
|
||||||
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
||||||
|
|
||||||
// Case 1: try to resolve in legacy scope and expand macro_rules
|
// Case 1: try to resolve in legacy scope and expand macro_rules
|
||||||
if let Some(macro_call_id) =
|
if let Ok(Ok(macro_call_id)) = macro_call_as_call_id(
|
||||||
ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
|
&ast_id,
|
||||||
|
self.def_collector.db,
|
||||||
|
self.def_collector.def_map.krate,
|
||||||
|
|path| {
|
||||||
path.as_ident().and_then(|name| {
|
path.as_ident().and_then(|name| {
|
||||||
self.def_collector.def_map.with_ancestor_maps(
|
self.def_collector.def_map.with_ancestor_maps(
|
||||||
self.def_collector.db,
|
self.def_collector.db,
|
||||||
|
@ -1455,8 +1469,9 @@ impl ModCollector<'_, '_> {
|
||||||
&mut |map, module| map[module].scope.get_legacy_macro(&name),
|
&mut |map, module| map[module].scope.get_legacy_macro(&name),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
},
|
||||||
{
|
&mut |_err| (),
|
||||||
|
) {
|
||||||
self.def_collector.unexpanded_macros.push(MacroDirective {
|
self.def_collector.unexpanded_macros.push(MacroDirective {
|
||||||
module_id: self.module_id,
|
module_id: self.module_id,
|
||||||
ast_id,
|
ast_id,
|
||||||
|
|
|
@ -10,15 +10,16 @@ mod field_shorthand;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
|
db::AstDatabase,
|
||||||
diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
|
diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
|
||||||
Semantics,
|
InFile, Semantics,
|
||||||
};
|
};
|
||||||
use ide_db::{base_db::SourceDatabase, RootDatabase};
|
use ide_db::{base_db::SourceDatabase, RootDatabase};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SyntaxNode, TextRange,
|
SyntaxNode, SyntaxNodePtr, TextRange,
|
||||||
};
|
};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
|
@ -147,20 +148,38 @@ pub(crate) fn diagnostics(
|
||||||
|
|
||||||
// Override severity and mark as unused.
|
// Override severity and mark as unused.
|
||||||
res.borrow_mut().push(
|
res.borrow_mut().push(
|
||||||
Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
|
Diagnostic::hint(
|
||||||
.with_unused(true)
|
sema.diagnostics_display_range(d.display_source()).range,
|
||||||
.with_code(Some(d.code())),
|
d.message(),
|
||||||
|
)
|
||||||
|
.with_unused(true)
|
||||||
|
.with_code(Some(d.code())),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| {
|
.on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| {
|
||||||
// Use more accurate position if available.
|
// Use more accurate position if available.
|
||||||
let display_range =
|
let display_range = d
|
||||||
d.precise_location.unwrap_or_else(|| sema.diagnostics_display_range(d).range);
|
.precise_location
|
||||||
|
.unwrap_or_else(|| sema.diagnostics_display_range(d.display_source()).range);
|
||||||
|
|
||||||
// FIXME: it would be nice to tell the user whether proc macros are currently disabled
|
// FIXME: it would be nice to tell the user whether proc macros are currently disabled
|
||||||
res.borrow_mut()
|
res.borrow_mut()
|
||||||
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
|
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
|
||||||
})
|
})
|
||||||
|
.on::<hir::diagnostics::UnresolvedMacroCall, _>(|d| {
|
||||||
|
let last_path_segment = sema.db.parse_or_expand(d.file).and_then(|root| {
|
||||||
|
d.node
|
||||||
|
.to_node(&root)
|
||||||
|
.path()
|
||||||
|
.and_then(|it| it.segment())
|
||||||
|
.and_then(|it| it.name_ref())
|
||||||
|
.map(|it| InFile::new(d.file, SyntaxNodePtr::new(it.syntax())))
|
||||||
|
});
|
||||||
|
let diagnostics = last_path_segment.unwrap_or_else(|| d.display_source());
|
||||||
|
let display_range = sema.diagnostics_display_range(diagnostics).range;
|
||||||
|
res.borrow_mut()
|
||||||
|
.push(Diagnostic::error(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()));
|
||||||
|
@ -170,8 +189,11 @@ pub(crate) fn diagnostics(
|
||||||
// Diagnostics not handled above get no fix and default treatment.
|
// Diagnostics not handled above get no fix and default treatment.
|
||||||
.build(|d| {
|
.build(|d| {
|
||||||
res.borrow_mut().push(
|
res.borrow_mut().push(
|
||||||
Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())
|
Diagnostic::error(
|
||||||
.with_code(Some(d.code())),
|
sema.diagnostics_display_range(d.display_source()).range,
|
||||||
|
d.message(),
|
||||||
|
)
|
||||||
|
.with_code(Some(d.code())),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -183,13 +205,13 @@ pub(crate) fn diagnostics(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
|
fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
|
||||||
Diagnostic::error(sema.diagnostics_display_range(d).range, d.message())
|
Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
|
||||||
.with_fix(d.fix(&sema))
|
.with_fix(d.fix(&sema))
|
||||||
.with_code(Some(d.code()))
|
.with_code(Some(d.code()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
|
fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic {
|
||||||
Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
|
Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
|
||||||
.with_fix(d.fix(&sema))
|
.with_fix(d.fix(&sema))
|
||||||
.with_code(Some(d.code()))
|
.with_code(Some(d.code()))
|
||||||
}
|
}
|
||||||
|
@ -645,6 +667,29 @@ fn test_fn() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unresolved_macro_range() {
|
||||||
|
check_expect(
|
||||||
|
r#"foo::bar!(92);"#,
|
||||||
|
expect![[r#"
|
||||||
|
[
|
||||||
|
Diagnostic {
|
||||||
|
message: "unresolved macro call",
|
||||||
|
range: 5..8,
|
||||||
|
severity: Error,
|
||||||
|
fix: None,
|
||||||
|
unused: false,
|
||||||
|
code: Some(
|
||||||
|
DiagnosticCode(
|
||||||
|
"unresolved-macro-call",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn range_mapping_out_of_macros() {
|
fn range_mapping_out_of_macros() {
|
||||||
// FIXME: this is very wrong, but somewhat tricky to fix.
|
// FIXME: this is very wrong, but somewhat tricky to fix.
|
||||||
|
|
Loading…
Reference in a new issue