Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/item_scope.rs5
-rw-r--r--crates/hir-def/src/nameres.rs8
-rw-r--r--crates/hir-def/src/nameres/collector.rs12
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs6
-rw-r--r--crates/hir-def/src/resolver.rs73
-rw-r--r--crates/hir-ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--crates/hir-ty/src/infer.rs4
-rw-r--r--crates/hir-ty/src/infer/path.rs4
-rw-r--r--crates/hir-ty/src/lower/path.rs10
-rw-r--r--crates/hir-ty/src/mir/lower.rs4
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs4
-rw-r--r--crates/hir-ty/src/tests/simple.rs35
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_macros.html3
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs8
15 files changed, 120 insertions, 60 deletions
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 1303773b59..b11a8bcd90 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -483,6 +483,11 @@ impl ItemScope {
self.declarations.push(def)
}
+ pub(crate) fn remove_from_value_ns(&mut self, name: &Name, def: ModuleDefId) {
+ let entry = self.values.shift_remove(name);
+ assert!(entry.is_some_and(|entry| entry.def == def))
+ }
+
pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<&[MacroId]> {
self.legacy_macros.get(name).map(|it| &**it)
}
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 1e3ea50c5a..5fda1beab4 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -211,6 +211,7 @@ struct DefMapCrateData {
/// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroId, Box<[Name]>>,
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
+ fn_proc_macro_mapping_back: FxHashMap<ProcMacroId, FunctionId>,
/// Custom tool modules registered with `#![register_tool]`.
registered_tools: Vec<Symbol>,
@@ -230,6 +231,7 @@ impl DefMapCrateData {
Self {
exported_derives: FxHashMap::default(),
fn_proc_macro_mapping: FxHashMap::default(),
+ fn_proc_macro_mapping_back: FxHashMap::default(),
registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(),
unstable_features: FxHashSet::default(),
rustc_coherence_is_core: false,
@@ -244,6 +246,7 @@ impl DefMapCrateData {
let Self {
exported_derives,
fn_proc_macro_mapping,
+ fn_proc_macro_mapping_back,
registered_tools,
unstable_features,
rustc_coherence_is_core: _,
@@ -254,6 +257,7 @@ impl DefMapCrateData {
} = self;
exported_derives.shrink_to_fit();
fn_proc_macro_mapping.shrink_to_fit();
+ fn_proc_macro_mapping_back.shrink_to_fit();
registered_tools.shrink_to_fit();
unstable_features.shrink_to_fit();
}
@@ -570,6 +574,10 @@ impl DefMap {
self.data.fn_proc_macro_mapping.get(&id).copied()
}
+ pub fn proc_macro_as_fn(&self, id: ProcMacroId) -> Option<FunctionId> {
+ self.data.fn_proc_macro_mapping_back.get(&id).copied()
+ }
+
pub fn krate(&self) -> Crate {
self.krate
}
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index f51524c1b5..e672e83f01 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -634,6 +634,7 @@ impl<'db> DefCollector<'db> {
crate_data.exported_derives.insert(proc_macro_id.into(), helpers);
}
crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
+ crate_data.fn_proc_macro_mapping_back.insert(proc_macro_id, fn_id);
}
/// Define a macro with `macro_rules`.
@@ -2095,6 +2096,8 @@ impl ModCollector<'_, '_> {
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
+ update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
+
if self.def_collector.def_map.block.is_none()
&& self.def_collector.is_proc_macro
&& self.module_id == self.def_collector.def_map.root
@@ -2105,9 +2108,14 @@ impl ModCollector<'_, '_> {
InFile::new(self.file_id(), id),
fn_id,
);
- }
- update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
+ // A proc macro is implemented as a function, but it's treated as a macro, not a function.
+ // You cannot call it like a function, for example, except in its defining crate.
+ // So we keep the function definition, but remove it from the scope, leaving only the macro.
+ self.def_collector.def_map[module_id]
+ .scope
+ .remove_from_value_ns(&it.name, fn_id.into());
+ }
}
ModItemId::Struct(id) => {
let it = &self.item_tree[id];
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index a943f6f0ac..a013f8b2bc 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -1068,10 +1068,8 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
- AnotherTrait : macro#
- DummyTrait : macro#
- TokenStream : type value
- - attribute_macro : value macro#
- - derive_macro : value
- - derive_macro_2 : value
- - function_like_macro : value macro!
+ - attribute_macro : macro#
+ - function_like_macro : macro!
"#]],
);
}
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index 2ac0f90fb2..d32e53fc6b 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -32,7 +32,7 @@ use crate::{
BindingId, ExprId, LabelId,
generics::{GenericParams, TypeOrConstParamData},
},
- item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
+ item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ItemScope},
lang_item::LangItemTarget,
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
per_ns::PerNs,
@@ -111,8 +111,8 @@ pub enum TypeNs {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ResolveValueResult {
- ValueNs(ValueNs, Option<ImportOrGlob>),
- Partial(TypeNs, usize, Option<ImportOrExternCrate>),
+ ValueNs(ValueNs),
+ Partial(TypeNs, usize),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -332,20 +332,17 @@ impl<'db> Resolver<'db> {
Path::Normal(it) => &it.mod_path,
Path::LangItem(l, None) => {
return Some((
- ResolveValueResult::ValueNs(
- match *l {
- LangItemTarget::FunctionId(it) => ValueNs::FunctionId(it),
- LangItemTarget::StaticId(it) => ValueNs::StaticId(it),
- LangItemTarget::StructId(it) => ValueNs::StructId(it),
- LangItemTarget::EnumVariantId(it) => ValueNs::EnumVariantId(it),
- LangItemTarget::UnionId(_)
- | LangItemTarget::ImplId(_)
- | LangItemTarget::TypeAliasId(_)
- | LangItemTarget::TraitId(_)
- | LangItemTarget::EnumId(_) => return None,
- },
- None,
- ),
+ ResolveValueResult::ValueNs(match *l {
+ LangItemTarget::FunctionId(it) => ValueNs::FunctionId(it),
+ LangItemTarget::StaticId(it) => ValueNs::StaticId(it),
+ LangItemTarget::StructId(it) => ValueNs::StructId(it),
+ LangItemTarget::EnumVariantId(it) => ValueNs::EnumVariantId(it),
+ LangItemTarget::UnionId(_)
+ | LangItemTarget::ImplId(_)
+ | LangItemTarget::TypeAliasId(_)
+ | LangItemTarget::TraitId(_)
+ | LangItemTarget::EnumId(_) => return None,
+ }),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -363,7 +360,7 @@ impl<'db> Resolver<'db> {
};
// Remaining segments start from 0 because lang paths have no segments other than the remaining.
return Some((
- ResolveValueResult::Partial(type_ns, 0, None),
+ ResolveValueResult::Partial(type_ns, 0),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -388,10 +385,7 @@ impl<'db> Resolver<'db> {
if let Some(e) = entry {
return Some((
- ResolveValueResult::ValueNs(
- ValueNs::LocalBinding(e.binding()),
- None,
- ),
+ ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.binding())),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -404,14 +398,14 @@ impl<'db> Resolver<'db> {
&& *first_name == sym::Self_
{
return Some((
- ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None),
+ ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)),
ResolvePathResultPrefixInfo::default(),
));
}
if let Some(id) = params.find_const_by_name(first_name, *def) {
let val = ValueNs::GenericParam(id);
return Some((
- ResolveValueResult::ValueNs(val, None),
+ ResolveValueResult::ValueNs(val),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -431,7 +425,7 @@ impl<'db> Resolver<'db> {
if let &GenericDefId::ImplId(impl_) = def {
if *first_name == sym::Self_ {
return Some((
- ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1, None),
+ ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -440,14 +434,14 @@ impl<'db> Resolver<'db> {
{
let ty = TypeNs::AdtSelfType(adt);
return Some((
- ResolveValueResult::Partial(ty, 1, None),
+ ResolveValueResult::Partial(ty, 1),
ResolvePathResultPrefixInfo::default(),
));
}
if let Some(id) = params.find_type_by_name(first_name, *def) {
let ty = TypeNs::GenericParam(id);
return Some((
- ResolveValueResult::Partial(ty, 1, None),
+ ResolveValueResult::Partial(ty, 1),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -473,7 +467,7 @@ impl<'db> Resolver<'db> {
&& let Some(builtin) = BuiltinType::by_name(first_name)
{
return Some((
- ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None),
+ ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1),
ResolvePathResultPrefixInfo::default(),
));
}
@@ -488,7 +482,7 @@ impl<'db> Resolver<'db> {
hygiene: HygieneId,
) -> Option<ValueNs> {
match self.resolve_path_in_value_ns(db, path, hygiene)? {
- ResolveValueResult::ValueNs(it, _) => Some(it),
+ ResolveValueResult::ValueNs(it) => Some(it),
ResolveValueResult::Partial(..) => None,
}
}
@@ -1153,12 +1147,12 @@ impl<'db> ModuleItemMap<'db> {
);
match unresolved_idx {
None => {
- let (value, import) = to_value_ns(module_def)?;
- Some((ResolveValueResult::ValueNs(value, import), prefix_info))
+ let value = to_value_ns(module_def, self.def_map)?;
+ Some((ResolveValueResult::ValueNs(value), prefix_info))
}
Some(unresolved_idx) => {
- let def = module_def.take_types_full()?;
- let ty = match def.def {
+ let def = module_def.take_types()?;
+ let ty = match def {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
@@ -1171,7 +1165,7 @@ impl<'db> ModuleItemMap<'db> {
| ModuleDefId::MacroId(_)
| ModuleDefId::StaticId(_) => return None,
};
- Some((ResolveValueResult::Partial(ty, unresolved_idx, def.import), prefix_info))
+ Some((ResolveValueResult::Partial(ty, unresolved_idx), prefix_info))
}
}
}
@@ -1194,8 +1188,13 @@ impl<'db> ModuleItemMap<'db> {
}
}
-fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
- let (def, import) = per_ns.take_values_import()?;
+fn to_value_ns(per_ns: PerNs, def_map: &DefMap) -> Option<ValueNs> {
+ let def = per_ns.take_values().or_else(|| {
+ let Some(MacroId::ProcMacroId(proc_macro)) = per_ns.take_macros() else { return None };
+ // If we cannot resolve to value ns, but we can resolve to a proc macro, and this is the crate
+ // defining this proc macro - inside this crate, we should treat the macro as a function.
+ def_map.proc_macro_as_fn(proc_macro).map(ModuleDefId::FunctionId)
+ })?;
let res = match def {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
@@ -1210,7 +1209,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
| ModuleDefId::MacroId(_)
| ModuleDefId::ModuleId(_) => return None,
};
- Some((res, import))
+ Some(res)
}
fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 50d4517d01..21f263723b 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -430,7 +430,7 @@ impl<'db> UnsafeVisitor<'db> {
fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) {
let hygiene = self.body.expr_or_pat_path_hygiene(node);
let value_or_partial = self.resolver.resolve_path_in_value_ns(self.db, path, hygiene);
- if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
+ if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
let static_data = self.db.static_signature(id);
if static_data.flags.contains(StaticFlags::MUTABLE) {
self.on_unsafe_op(node, UnsafetyReason::MutableStatic);
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 35d744e7d1..991acda14b 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -1584,7 +1584,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
return (self.err_ty(), None);
};
match res {
- ResolveValueResult::ValueNs(value, _) => match value {
+ ResolveValueResult::ValueNs(value) => match value {
ValueNs::EnumVariantId(var) => {
let args = path_ctx.substs_from_path(var.into(), true, false);
drop(ctx);
@@ -1608,7 +1608,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
return (self.err_ty(), None);
}
},
- ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)),
+ ResolveValueResult::Partial(typens, unresolved) => (typens, Some(unresolved)),
}
} else {
match path_ctx.resolve_path_in_type_ns() {
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index ef1a610a32..40c6fdf3cc 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -164,11 +164,11 @@ impl<'db> InferenceContext<'_, 'db> {
let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?;
match value_or_partial {
- ResolveValueResult::ValueNs(it, _) => {
+ ResolveValueResult::ValueNs(it) => {
drop_ctx(ctx, no_diagnostics);
(it, None)
}
- ResolveValueResult::Partial(def, remaining_index, _) => {
+ ResolveValueResult::Partial(def, remaining_index) => {
// there may be more intermediate segments between the resolved one and
// the end. Only the last segment needs to be resolved to a value; from
// the segments before that, we need to get either a type or a trait ref.
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index f3d0de1227..517f67b828 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -396,12 +396,10 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
}
let (mod_segments, enum_segment, resolved_segment_idx) = match res {
- ResolveValueResult::Partial(_, unresolved_segment, _) => {
+ ResolveValueResult::Partial(_, unresolved_segment) => {
(segments.take(unresolved_segment - 1), None, unresolved_segment - 1)
}
- ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _)
- if prefix_info.enum_variant =>
- {
+ ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_)) if prefix_info.enum_variant => {
(segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1)
}
ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1),
@@ -431,7 +429,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
}
match &res {
- ResolveValueResult::ValueNs(resolution, _) => {
+ ResolveValueResult::ValueNs(resolution) => {
let resolved_segment_idx = self.current_segment_u32();
let resolved_segment = self.current_or_prev_segment;
@@ -469,7 +467,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
| ValueNs::ConstId(_) => {}
}
}
- ResolveValueResult::Partial(resolution, _, _) => {
+ ResolveValueResult::Partial(resolution, _) => {
if !self.handle_type_ns_resolution(resolution) {
return None;
}
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 199db7a3e7..8d5e5c2e6e 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1429,7 +1429,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
.resolve_path_in_value_ns(self.db, c, HygieneId::ROOT)
.ok_or_else(unresolved_name)?;
match pr {
- ResolveValueResult::ValueNs(v, _) => {
+ ResolveValueResult::ValueNs(v) => {
if let ValueNs::ConstId(c) = v {
self.lower_const_to_operand(
GenericArgs::empty(self.interner()),
@@ -1439,7 +1439,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
not_supported!("bad path in range pattern");
}
}
- ResolveValueResult::Partial(_, _, _) => {
+ ResolveValueResult::Partial(_, _) => {
not_supported!("associated constants in range pattern")
}
}
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index a8aacbff16..83139821e3 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -373,7 +373,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
if let (
MatchingMode::Assign,
- ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding), _),
+ ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding)),
) = (mode, &pr)
{
let local = self.binding_local(*binding)?;
@@ -398,7 +398,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
{
break 'b (c, x.1);
}
- if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr {
+ if let ResolveValueResult::ValueNs(ValueNs::ConstId(c)) = pr {
break 'b (c, GenericArgs::empty(self.interner()));
}
not_supported!("path in pattern position that is not const or variant")
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 7d4f04268a..dab8bdb54b 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -4074,3 +4074,38 @@ static S: &[u8; 158] = include_bytes!("/foo/bar/baz.txt");
"#,
);
}
+
+#[test]
+fn proc_macros_are_functions_inside_defining_crate_and_macros_outside() {
+ check_types(
+ r#"
+//- /pm.rs crate:pm
+#![crate_type = "proc-macro"]
+
+#[proc_macro_attribute]
+pub fn proc_macro() {}
+
+fn foo() {
+ proc_macro;
+ // ^^^^^^^^^^ fn proc_macro()
+}
+
+mod bar {
+ use super::proc_macro;
+
+ fn baz() {
+ super::proc_macro;
+ // ^^^^^^^^^^^^^^^^^ fn proc_macro()
+ proc_macro;
+ // ^^^^^^^^^^ fn proc_macro()
+ }
+}
+
+//- /lib.rs crate:lib deps:pm
+fn foo() {
+ pm::proc_macro;
+ // ^^^^^^^^^^^^^^ {unknown}
+}
+ "#,
+ );
+}
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 5443021988..38ee097033 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -2073,6 +2073,7 @@ fn func() {}
expect![[r#"
identity Attribute FileId(1) 1..107 32..40
+ FileId(0) 17..25 import
FileId(0) 43..51
"#]],
);
@@ -2103,6 +2104,7 @@ mirror$0! {}
expect![[r#"
mirror ProcMacro FileId(1) 1..77 22..28
+ FileId(0) 17..23 import
FileId(0) 26..32
"#]],
)
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index 59612634fd..740a6272a7 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -41,7 +41,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
</style>
-<pre><code><span class="keyword">use</span> <span class="crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="function library">mirror</span><span class="comma">,</span> <span class="function library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
+<pre><code><span class="keyword">use</span> <span class="crate_root library">proc_macros</span><span class="operator">::</span><span class="brace">{</span><span class="proc_macro library">mirror</span><span class="comma">,</span> <span class="attribute library">identity</span><span class="comma">,</span> <span class="derive library">DeriveIdentity</span><span class="brace">}</span><span class="semicolon">;</span>
+<span class="keyword">use</span> <span class="crate_root library">pm</span><span class="operator">::</span><span class="attribute library">proc_macro</span><span class="semicolon">;</span>
<span class="proc_macro library">mirror</span><span class="macro_bang">!</span> <span class="brace">{</span>
<span class="brace macro proc_macro">{</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 8b529cf10f..c6aebd0b0c 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -55,8 +55,9 @@ fn macros() {
r#"
//- proc_macros: mirror, identity, derive_identity
//- minicore: fmt, include, concat
-//- /lib.rs crate:lib
+//- /lib.rs crate:lib deps:pm
use proc_macros::{mirror, identity, DeriveIdentity};
+use pm::proc_macro;
mirror! {
{
@@ -126,6 +127,11 @@ fn main() {
//- /foo/foo.rs crate:foo
mod foo {}
use self::foo as bar;
+//- /pm.rs crate:pm
+#![crate_type = "proc-macro"]
+
+#[proc_macro_attribute]
+pub fn proc_macro() {}
"#,
expect_file!["./test_data/highlight_macros.html"],
false,