Auto merge of #12864 - Veykril:derive-helpers, r=Veykril
feat: Resolve derive helper attributes in IDE layer  Also downmaps tokens inside deriver helpers to the derive expansion  This does not handle the case where multiple derives make use of the same helper name though, unsure how to tackle that yet. Partially addresses https://github.com/rust-lang/rust-analyzer/issues/10935
This commit is contained in:
commit
e36a20c24f
@ -12,7 +12,7 @@ use crate::{
|
||||
db::DefDatabase,
|
||||
intern::Interned,
|
||||
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
|
||||
nameres::{attr_resolution::ResolvedAttr, DefMap},
|
||||
nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap},
|
||||
type_ref::{TraitRef, TypeBound, TypeRef},
|
||||
visibility::RawVisibility,
|
||||
AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
|
||||
@ -348,7 +348,8 @@ impl MacroRulesData {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ProcMacroData {
|
||||
pub name: Name,
|
||||
// FIXME: Record deriver helper here?
|
||||
/// Derive helpers, if this is a derive
|
||||
pub helpers: Option<Box<[Name]>>,
|
||||
}
|
||||
|
||||
impl ProcMacroData {
|
||||
@ -360,17 +361,23 @@ impl ProcMacroData {
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let makro = &item_tree[loc.id.value];
|
||||
|
||||
let name = if let Some(def) = item_tree
|
||||
let (name, helpers) = if let Some(def) = item_tree
|
||||
.attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
|
||||
.parse_proc_macro_decl(&makro.name)
|
||||
{
|
||||
def.name
|
||||
(
|
||||
def.name,
|
||||
match def.kind {
|
||||
ProcMacroKind::CustomDerive { helpers } => Some(helpers),
|
||||
ProcMacroKind::FnLike | ProcMacroKind::Attr => None,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// eeeh...
|
||||
stdx::never!("proc macro declaration is not a proc macro");
|
||||
makro.name.clone()
|
||||
(makro.name.clone(), None)
|
||||
};
|
||||
Arc::new(ProcMacroData { name })
|
||||
Arc::new(ProcMacroData { name, helpers })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,10 +66,14 @@ pub struct ItemScope {
|
||||
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
|
||||
/// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
|
||||
/// paired with the derive macro invocations for the specific attribute.
|
||||
derive_macros: FxHashMap<
|
||||
AstId<ast::Adt>,
|
||||
SmallVec<[(AttrId, MacroCallId, SmallVec<[Option<MacroCallId>; 1]>); 1]>,
|
||||
>,
|
||||
derive_macros: FxHashMap<AstId<ast::Adt>, SmallVec<[DeriveMacroInvocation; 1]>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct DeriveMacroInvocation {
|
||||
attr_id: AttrId,
|
||||
attr_call_id: MacroCallId,
|
||||
derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
|
||||
}
|
||||
|
||||
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
|
||||
@ -210,12 +214,14 @@ impl ItemScope {
|
||||
&mut self,
|
||||
adt: AstId<ast::Adt>,
|
||||
call: MacroCallId,
|
||||
attr_id: AttrId,
|
||||
id: AttrId,
|
||||
idx: usize,
|
||||
) {
|
||||
if let Some(derives) = self.derive_macros.get_mut(&adt) {
|
||||
if let Some((.., invocs)) = derives.iter_mut().find(|&&mut (id, ..)| id == attr_id) {
|
||||
invocs[idx] = Some(call);
|
||||
if let Some(DeriveMacroInvocation { derive_call_ids, .. }) =
|
||||
derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id)
|
||||
{
|
||||
derive_call_ids[idx] = Some(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,10 +233,14 @@ impl ItemScope {
|
||||
&mut self,
|
||||
adt: AstId<ast::Adt>,
|
||||
attr_id: AttrId,
|
||||
call_id: MacroCallId,
|
||||
attr_call_id: MacroCallId,
|
||||
len: usize,
|
||||
) {
|
||||
self.derive_macros.entry(adt).or_default().push((attr_id, call_id, smallvec![None; len]));
|
||||
self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
|
||||
attr_id,
|
||||
attr_call_id,
|
||||
derive_call_ids: smallvec![None; len],
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn derive_macro_invocs(
|
||||
@ -242,7 +252,12 @@ impl ItemScope {
|
||||
),
|
||||
> + '_ {
|
||||
self.derive_macros.iter().map(|(k, v)| {
|
||||
(*k, v.iter().map(|&(attr_id, call_id, ref invocs)| (attr_id, call_id, &**invocs)))
|
||||
(
|
||||
*k,
|
||||
v.iter().map(|DeriveMacroInvocation { attr_id, attr_call_id, derive_call_ids }| {
|
||||
(*attr_id, *attr_call_id, &**derive_call_ids)
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -934,11 +934,11 @@ fn derive_macro_as_call_id(
|
||||
derive_attr: AttrId,
|
||||
derive_pos: u32,
|
||||
krate: CrateId,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Result<MacroCallId, UnresolvedMacro> {
|
||||
let def: MacroDefId = resolver(item_attr.path.clone())
|
||||
resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
|
||||
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
|
||||
let (macro_id, def_id) = resolver(item_attr.path.clone())
|
||||
.ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
|
||||
let res = def.as_lazy_macro(
|
||||
let call_id = def_id.as_lazy_macro(
|
||||
db.upcast(),
|
||||
krate,
|
||||
MacroCallKind::Derive {
|
||||
@ -947,7 +947,7 @@ fn derive_macro_as_call_id(
|
||||
derive_attr_index: derive_attr.ast_index,
|
||||
},
|
||||
);
|
||||
Ok(res)
|
||||
Ok((macro_id, def_id, call_id))
|
||||
}
|
||||
|
||||
fn attr_macro_as_call_id(
|
||||
|
@ -48,19 +48,19 @@
|
||||
//! the result
|
||||
|
||||
pub mod attr_resolution;
|
||||
mod collector;
|
||||
pub mod proc_macro;
|
||||
pub mod diagnostics;
|
||||
mod collector;
|
||||
mod mod_resolution;
|
||||
mod path_resolution;
|
||||
mod proc_macro;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::{cmp::Ord, sync::Arc};
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use base_db::{CrateId, Edition, FileId};
|
||||
use hir_expand::{name::Name, InFile, MacroDefId};
|
||||
use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
|
||||
use itertools::Itertools;
|
||||
use la_arena::Arena;
|
||||
use profile::Count;
|
||||
@ -76,7 +76,7 @@ use crate::{
|
||||
path::ModPath,
|
||||
per_ns::PerNs,
|
||||
visibility::Visibility,
|
||||
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, ModuleId, ProcMacroId,
|
||||
AstId, BlockId, BlockLoc, FunctionId, LocalModuleId, MacroId, ModuleId, ProcMacroId,
|
||||
};
|
||||
|
||||
/// Contains the results of (early) name resolution.
|
||||
@ -106,6 +106,9 @@ pub struct DefMap {
|
||||
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
|
||||
/// The error that occurred when failing to load the proc-macro dll.
|
||||
proc_macro_loading_error: Option<Box<str>>,
|
||||
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
|
||||
/// attributes.
|
||||
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
|
||||
|
||||
/// Custom attributes registered with `#![register_attr]`.
|
||||
registered_attrs: Vec<SmolStr>,
|
||||
@ -275,6 +278,7 @@ impl DefMap {
|
||||
exported_derives: FxHashMap::default(),
|
||||
fn_proc_macro_mapping: FxHashMap::default(),
|
||||
proc_macro_loading_error: None,
|
||||
derive_helpers_in_scope: FxHashMap::default(),
|
||||
prelude: None,
|
||||
root,
|
||||
modules,
|
||||
@ -294,12 +298,22 @@ impl DefMap {
|
||||
pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
|
||||
self.modules.iter()
|
||||
}
|
||||
|
||||
pub fn derive_helpers_in_scope(
|
||||
&self,
|
||||
id: AstId<ast::Adt>,
|
||||
) -> Option<&[(Name, MacroId, MacroCallId)]> {
|
||||
self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref)
|
||||
}
|
||||
|
||||
pub fn registered_tools(&self) -> &[SmolStr] {
|
||||
&self.registered_tools
|
||||
}
|
||||
|
||||
pub fn registered_attrs(&self) -> &[SmolStr] {
|
||||
&self.registered_attrs
|
||||
}
|
||||
|
||||
pub fn root(&self) -> LocalModuleId {
|
||||
self.root
|
||||
}
|
||||
@ -307,6 +321,7 @@ impl DefMap {
|
||||
pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
|
||||
self.fn_proc_macro_mapping.get(&id).copied()
|
||||
}
|
||||
|
||||
pub fn proc_macro_loading_error(&self) -> Option<&str> {
|
||||
self.proc_macro_loading_error.as_deref()
|
||||
}
|
||||
@ -467,6 +482,7 @@ impl DefMap {
|
||||
registered_attrs,
|
||||
registered_tools,
|
||||
fn_proc_macro_mapping,
|
||||
derive_helpers_in_scope,
|
||||
proc_macro_loading_error: _,
|
||||
block: _,
|
||||
edition: _,
|
||||
@ -483,6 +499,7 @@ impl DefMap {
|
||||
registered_attrs.shrink_to_fit();
|
||||
registered_tools.shrink_to_fit();
|
||||
fn_proc_macro_mapping.shrink_to_fit();
|
||||
derive_helpers_in_scope.shrink_to_fit();
|
||||
for (_, module) in modules.iter_mut() {
|
||||
module.children.shrink_to_fit();
|
||||
module.scope.shrink_to_fit();
|
||||
|
@ -18,7 +18,7 @@ use hir_expand::{
|
||||
ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
|
||||
MacroDefKind,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use itertools::{izip, Itertools};
|
||||
use la_arena::Idx;
|
||||
use limit::Limit;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@ -110,7 +110,6 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
|
||||
proc_macros,
|
||||
from_glob_import: Default::default(),
|
||||
skip_attrs: Default::default(),
|
||||
derive_helpers_in_scope: Default::default(),
|
||||
is_proc_macro,
|
||||
};
|
||||
if tree_id.is_block() {
|
||||
@ -258,9 +257,6 @@ struct DefCollector<'a> {
|
||||
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
|
||||
/// non-builtin attributes in general.
|
||||
skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
|
||||
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
|
||||
/// attributes.
|
||||
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
|
||||
}
|
||||
|
||||
impl DefCollector<'_> {
|
||||
@ -1059,7 +1055,7 @@ impl DefCollector<'_> {
|
||||
};
|
||||
let mut res = ReachedFixedPoint::Yes;
|
||||
macros.retain(|directive| {
|
||||
let resolver = |path| {
|
||||
let resolver2 = |path| {
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
ResolveMode::Other,
|
||||
@ -1067,8 +1063,12 @@ impl DefCollector<'_> {
|
||||
&path,
|
||||
BuiltinShadowMode::Module,
|
||||
);
|
||||
resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(self.db, it))
|
||||
resolved_res
|
||||
.resolved_def
|
||||
.take_macros()
|
||||
.map(|it| (it, macro_id_to_def_id(self.db, it)))
|
||||
};
|
||||
let resolver = |path| resolver2(path).map(|(_, it)| it);
|
||||
|
||||
match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||
@ -1087,21 +1087,37 @@ impl DefCollector<'_> {
|
||||
}
|
||||
}
|
||||
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
|
||||
let call_id = derive_macro_as_call_id(
|
||||
let id = derive_macro_as_call_id(
|
||||
self.db,
|
||||
ast_id,
|
||||
*derive_attr,
|
||||
*derive_pos as u32,
|
||||
self.def_map.krate,
|
||||
&resolver,
|
||||
&resolver2,
|
||||
);
|
||||
if let Ok(call_id) = call_id {
|
||||
|
||||
if let Ok((macro_id, def_id, call_id)) = id {
|
||||
self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc(
|
||||
ast_id.ast_id,
|
||||
call_id,
|
||||
*derive_attr,
|
||||
*derive_pos,
|
||||
);
|
||||
// Record its helper attributes.
|
||||
if def_id.krate != self.def_map.krate {
|
||||
let def_map = self.db.crate_def_map(def_id.krate);
|
||||
if let Some(helpers) = def_map.exported_derives.get(&def_id) {
|
||||
self.def_map
|
||||
.derive_helpers_in_scope
|
||||
.entry(ast_id.ast_id.map(|it| it.upcast()))
|
||||
.or_default()
|
||||
.extend(izip!(
|
||||
helpers.iter().cloned(),
|
||||
iter::repeat(macro_id),
|
||||
iter::repeat(call_id),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
push_resolved(directive, call_id);
|
||||
res = ReachedFixedPoint::No;
|
||||
@ -1132,8 +1148,8 @@ impl DefCollector<'_> {
|
||||
};
|
||||
|
||||
if let Some(ident) = path.as_ident() {
|
||||
if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id) {
|
||||
if helpers.contains(ident) {
|
||||
if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) {
|
||||
if helpers.iter().any(|(it, ..)| it == ident) {
|
||||
cov_mark::hit!(resolved_derive_helper);
|
||||
// Resolved to derive helper. Collect the item's attributes again,
|
||||
// starting after the derive helper.
|
||||
@ -1148,7 +1164,7 @@ impl DefCollector<'_> {
|
||||
};
|
||||
if matches!(
|
||||
def,
|
||||
MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. }
|
||||
MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. }
|
||||
if expander.is_derive()
|
||||
) {
|
||||
// Resolved to `#[derive]`
|
||||
@ -1317,19 +1333,6 @@ impl DefCollector<'_> {
|
||||
self.def_map.diagnostics.push(diag);
|
||||
}
|
||||
|
||||
// If we've just resolved a derive, record its helper attributes.
|
||||
if let MacroCallKind::Derive { ast_id, .. } = &loc.kind {
|
||||
if loc.def.krate != self.def_map.krate {
|
||||
let def_map = self.db.crate_def_map(loc.def.krate);
|
||||
if let Some(helpers) = def_map.exported_derives.get(&loc.def) {
|
||||
self.derive_helpers_in_scope
|
||||
.entry(ast_id.map(|it| it.upcast()))
|
||||
.or_default()
|
||||
.extend(helpers.iter().cloned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then, fetch and process the item tree. This will reuse the expansion result from above.
|
||||
let item_tree = self.db.file_item_tree(file_id);
|
||||
let mod_dir = self.mod_dirs[&module_id].clone();
|
||||
@ -2140,7 +2143,6 @@ mod tests {
|
||||
proc_macros: Default::default(),
|
||||
from_glob_import: Default::default(),
|
||||
skip_attrs: Default::default(),
|
||||
derive_helpers_in_scope: Default::default(),
|
||||
is_proc_macro: false,
|
||||
};
|
||||
collector.seed_with_top_level();
|
||||
|
@ -149,6 +149,7 @@ impl Resolver {
|
||||
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
|
||||
}
|
||||
|
||||
// FIXME: This shouldn't exist
|
||||
pub fn resolve_module_path_in_trait_assoc_items(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
@ -448,10 +449,14 @@ impl Resolver {
|
||||
}
|
||||
|
||||
pub fn krate(&self) -> CrateId {
|
||||
self.def_map().krate()
|
||||
}
|
||||
|
||||
pub fn def_map(&self) -> &DefMap {
|
||||
self.scopes
|
||||
.get(0)
|
||||
.and_then(|scope| match scope {
|
||||
Scope::ModuleScope(m) => Some(m.def_map.krate()),
|
||||
Scope::ModuleScope(m) => Some(&m.def_map),
|
||||
_ => None,
|
||||
})
|
||||
.expect("module scope invariant violated")
|
||||
|
@ -2252,6 +2252,32 @@ impl Local {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DeriveHelper {
|
||||
pub(crate) derive: MacroId,
|
||||
pub(crate) idx: usize,
|
||||
}
|
||||
|
||||
impl DeriveHelper {
|
||||
pub fn derive(&self) -> Macro {
|
||||
Macro { id: self.derive.into() }
|
||||
}
|
||||
|
||||
pub fn name(&self, db: &dyn HirDatabase) -> Name {
|
||||
match self.derive {
|
||||
MacroId::Macro2Id(_) => None,
|
||||
MacroId::MacroRulesId(_) => None,
|
||||
MacroId::ProcMacroId(proc_macro) => db
|
||||
.proc_macro_data(proc_macro)
|
||||
.helpers
|
||||
.as_ref()
|
||||
.and_then(|it| it.get(self.idx))
|
||||
.cloned(),
|
||||
}
|
||||
.unwrap_or_else(|| Name::missing())
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Wrong name? This is could also be a registered attribute
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct BuiltinAttr {
|
||||
|
@ -29,9 +29,9 @@ use crate::{
|
||||
db::HirDatabase,
|
||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||
Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
|
||||
HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path,
|
||||
ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
||||
Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function,
|
||||
HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
|
||||
Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -47,6 +47,7 @@ pub enum PathResolution {
|
||||
SelfType(Impl),
|
||||
BuiltinAttr(BuiltinAttr),
|
||||
ToolModule(ToolModule),
|
||||
DeriveHelper(DeriveHelper),
|
||||
}
|
||||
|
||||
impl PathResolution {
|
||||
@ -71,6 +72,7 @@ impl PathResolution {
|
||||
PathResolution::BuiltinAttr(_)
|
||||
| PathResolution::ToolModule(_)
|
||||
| PathResolution::Local(_)
|
||||
| PathResolution::DeriveHelper(_)
|
||||
| PathResolution::ConstParam(_) => None,
|
||||
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
|
||||
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
|
||||
@ -733,6 +735,8 @@ impl<'db> SemanticsImpl<'db> {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
let def_map = sa.resolver.def_map();
|
||||
|
||||
let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)];
|
||||
let mut cache = self.expansion_info_cache.borrow_mut();
|
||||
let mut mcache = self.macro_call_cache.borrow_mut();
|
||||
@ -764,7 +768,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||
while let Some(token) = stack.pop() {
|
||||
self.db.unwind_if_cancelled();
|
||||
let was_not_remapped = (|| {
|
||||
// are we inside an attribute macro call
|
||||
// First expand into attribute invocations
|
||||
let containing_attribute_macro_call = self.with_ctx(|ctx| {
|
||||
token.value.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
|
||||
if item.attrs().next().is_none() {
|
||||
@ -784,53 +788,19 @@ impl<'db> SemanticsImpl<'db> {
|
||||
);
|
||||
}
|
||||
|
||||
// or are we inside a function-like macro call
|
||||
if let Some(tt) =
|
||||
// FIXME replace map.while_some with take_while once stable
|
||||
token
|
||||
.value
|
||||
.parent_ancestors()
|
||||
.map(ast::TokenTree::cast)
|
||||
.while_some()
|
||||
.last()
|
||||
{
|
||||
let parent = tt.syntax().parent()?;
|
||||
// check for derive attribute here
|
||||
let macro_call = match_ast! {
|
||||
match parent {
|
||||
ast::MacroCall(mcall) => mcall,
|
||||
// attribute we failed expansion for earlier, this might be a derive invocation
|
||||
// so try downmapping the token into the pseudo derive expansion
|
||||
// see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
|
||||
ast::Meta(meta) => {
|
||||
let attr = meta.parent_attr()?;
|
||||
let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
|
||||
let call_id = self.with_ctx(|ctx| {
|
||||
let (_, call_id, _) = ctx.attr_to_derive_macro_call(
|
||||
token.with_value(&adt),
|
||||
token.with_value(attr),
|
||||
)?;
|
||||
Some(call_id)
|
||||
})?;
|
||||
let file_id = call_id.as_file();
|
||||
return process_expansion_for_token(
|
||||
&mut stack,
|
||||
file_id,
|
||||
Some(adt.into()),
|
||||
token.as_ref(),
|
||||
);
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
// Then check for token trees, that means we are either in a function-like macro or
|
||||
// secondary attribute inputs
|
||||
let tt = token.value.parent_ancestors().map_while(ast::TokenTree::cast).last()?;
|
||||
let parent = tt.syntax().parent()?;
|
||||
|
||||
if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
|
||||
return None;
|
||||
}
|
||||
if tt.right_delimiter_token().map_or(false, |it| it == token.value) {
|
||||
return None;
|
||||
}
|
||||
if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
|
||||
return None;
|
||||
}
|
||||
if tt.right_delimiter_token().map_or(false, |it| it == token.value) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(macro_call) = ast::MacroCall::cast(parent.clone()) {
|
||||
let mcall = token.with_value(macro_call);
|
||||
let file_id = match mcache.get(&mcall) {
|
||||
Some(&it) => it,
|
||||
@ -840,11 +810,77 @@ impl<'db> SemanticsImpl<'db> {
|
||||
it
|
||||
}
|
||||
};
|
||||
return process_expansion_for_token(&mut stack, file_id, None, token.as_ref());
|
||||
}
|
||||
process_expansion_for_token(&mut stack, file_id, None, token.as_ref())
|
||||
} else if let Some(meta) = ast::Meta::cast(parent.clone()) {
|
||||
// attribute we failed expansion for earlier, this might be a derive invocation
|
||||
// or derive helper attribute
|
||||
let attr = meta.parent_attr()?;
|
||||
|
||||
// outside of a macro invocation so this is a "final" token
|
||||
None
|
||||
let adt = if let Some(adt) = attr.syntax().parent().and_then(ast::Adt::cast) {
|
||||
// this might be a derive, or a derive helper on an ADT
|
||||
let derive_call = self.with_ctx(|ctx| {
|
||||
// so try downmapping the token into the pseudo derive expansion
|
||||
// see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
|
||||
ctx.attr_to_derive_macro_call(
|
||||
token.with_value(&adt),
|
||||
token.with_value(attr.clone()),
|
||||
)
|
||||
.map(|(_, call_id, _)| call_id)
|
||||
});
|
||||
|
||||
match derive_call {
|
||||
Some(call_id) => {
|
||||
// resolved to a derive
|
||||
let file_id = call_id.as_file();
|
||||
return process_expansion_for_token(
|
||||
&mut stack,
|
||||
file_id,
|
||||
Some(adt.into()),
|
||||
token.as_ref(),
|
||||
);
|
||||
}
|
||||
None => Some(adt),
|
||||
}
|
||||
} else {
|
||||
// Otherwise this could be a derive helper on a variant or field
|
||||
if let Some(field) = attr.syntax().parent().and_then(ast::RecordField::cast)
|
||||
{
|
||||
field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
|
||||
} else if let Some(field) =
|
||||
attr.syntax().parent().and_then(ast::TupleField::cast)
|
||||
{
|
||||
field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
|
||||
} else if let Some(variant) =
|
||||
attr.syntax().parent().and_then(ast::Variant::cast)
|
||||
{
|
||||
variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}?;
|
||||
if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(token.file_id, &adt))) {
|
||||
return None;
|
||||
}
|
||||
// Not an attribute, nor a derive, so it's either a builtin or a derive helper
|
||||
// Try to resolve to a derive helper and downmap
|
||||
let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
|
||||
let id = self.db.ast_id_map(token.file_id).ast_id(&adt);
|
||||
let helpers =
|
||||
def_map.derive_helpers_in_scope(InFile::new(token.file_id, id))?;
|
||||
let item = Some(adt.into());
|
||||
let mut res = None;
|
||||
for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) {
|
||||
res = res.or(process_expansion_for_token(
|
||||
&mut stack,
|
||||
derive.as_file(),
|
||||
item.clone(),
|
||||
token.as_ref(),
|
||||
));
|
||||
}
|
||||
res
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})()
|
||||
.is_none();
|
||||
|
||||
|
@ -247,6 +247,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||
map[keys::ATTR_MACRO_CALL].get(&src.value).copied()
|
||||
}
|
||||
|
||||
/// (AttrId, derive attribute call id, derive call ids)
|
||||
pub(super) fn attr_to_derive_macro_call(
|
||||
&mut self,
|
||||
item: InFile<&ast::Adt>,
|
||||
@ -257,6 +258,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||
.get(&src.value)
|
||||
.map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids))
|
||||
}
|
||||
|
||||
pub(super) fn has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool {
|
||||
self.dyn_map(adt).as_ref().map_or(false, |map| !map[keys::DERIVE_MACRO_CALL].is_empty())
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ use hir_ty::{
|
||||
method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution,
|
||||
TyExt, TyKind, TyLoweringContext,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use smallvec::SmallVec;
|
||||
use syntax::{
|
||||
ast::{self, AstNode},
|
||||
@ -43,8 +44,8 @@ use syntax::{
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
|
||||
BuiltinType, Callable, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct,
|
||||
ToolModule, Trait, Type, TypeAlias, Variant,
|
||||
BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
|
||||
Struct, ToolModule, Trait, Type, TypeAlias, Variant,
|
||||
};
|
||||
|
||||
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
|
||||
@ -429,19 +430,21 @@ impl SourceAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
let is_path_of_attr = path
|
||||
let meta_path = path
|
||||
.syntax()
|
||||
.ancestors()
|
||||
.map(|it| it.kind())
|
||||
.take_while(|&kind| ast::Path::can_cast(kind) || ast::Meta::can_cast(kind))
|
||||
.take_while(|it| {
|
||||
let kind = it.kind();
|
||||
ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
|
||||
})
|
||||
.last()
|
||||
.map_or(false, ast::Meta::can_cast);
|
||||
.and_then(ast::Meta::cast);
|
||||
|
||||
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
|
||||
// trying to resolve foo::bar.
|
||||
if path.parent_path().is_some() {
|
||||
return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
|
||||
None if is_path_of_attr => {
|
||||
None if meta_path.is_some() => {
|
||||
path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
|
||||
ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
|
||||
.map(PathResolution::ToolModule)
|
||||
@ -449,16 +452,56 @@ impl SourceAnalyzer {
|
||||
}
|
||||
res => res,
|
||||
};
|
||||
} else if is_path_of_attr {
|
||||
} else if let Some(meta_path) = meta_path {
|
||||
// Case where we are resolving the final path segment of a path in an attribute
|
||||
// in this case we have to check for inert/builtin attributes and tools and prioritize
|
||||
// resolution of attributes over other namespaces
|
||||
let name_ref = path.as_single_name_ref();
|
||||
let builtin = name_ref.as_ref().and_then(|name_ref| {
|
||||
BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text())
|
||||
});
|
||||
if let Some(_) = builtin {
|
||||
return builtin.map(PathResolution::BuiltinAttr);
|
||||
if let Some(name_ref) = path.as_single_name_ref() {
|
||||
let builtin =
|
||||
BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text());
|
||||
if let Some(_) = builtin {
|
||||
return builtin.map(PathResolution::BuiltinAttr);
|
||||
}
|
||||
|
||||
if let Some(attr) = meta_path.parent_attr() {
|
||||
let adt = if let Some(field) =
|
||||
attr.syntax().parent().and_then(ast::RecordField::cast)
|
||||
{
|
||||
field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
|
||||
} else if let Some(field) =
|
||||
attr.syntax().parent().and_then(ast::TupleField::cast)
|
||||
{
|
||||
field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
|
||||
} else if let Some(variant) =
|
||||
attr.syntax().parent().and_then(ast::Variant::cast)
|
||||
{
|
||||
variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(adt) = adt {
|
||||
let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
|
||||
if let Some(helpers) = self
|
||||
.resolver
|
||||
.def_map()
|
||||
.derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
|
||||
{
|
||||
// FIXME: Multiple derives can have the same helper
|
||||
let name_ref = name_ref.as_name();
|
||||
for (macro_id, mut helpers) in
|
||||
helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter()
|
||||
{
|
||||
if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
|
||||
{
|
||||
return Some(PathResolution::DeriveHelper(DeriveHelper {
|
||||
derive: *macro_id,
|
||||
idx,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
|
||||
Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
|
||||
|
@ -292,6 +292,7 @@ impl CompletionItemKind {
|
||||
SymbolKind::Const => "ct",
|
||||
SymbolKind::ConstParam => "cp",
|
||||
SymbolKind::Derive => "de",
|
||||
SymbolKind::DeriveHelper => "dh",
|
||||
SymbolKind::Enum => "en",
|
||||
SymbolKind::Field => "fd",
|
||||
SymbolKind::Function => "fn",
|
||||
|
@ -7,9 +7,9 @@
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, Field, Function,
|
||||
GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef, Name,
|
||||
PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility,
|
||||
Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field,
|
||||
Function, GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef,
|
||||
Name, PathResolution, Semantics, Static, ToolModule, Trait, TypeAlias, Variant, Visibility,
|
||||
};
|
||||
use stdx::impl_from;
|
||||
use syntax::{
|
||||
@ -37,6 +37,7 @@ pub enum Definition {
|
||||
Local(Local),
|
||||
GenericParam(GenericParam),
|
||||
Label(Label),
|
||||
DeriveHelper(DeriveHelper),
|
||||
BuiltinAttr(BuiltinAttr),
|
||||
ToolModule(ToolModule),
|
||||
}
|
||||
@ -69,6 +70,7 @@ impl Definition {
|
||||
Definition::Local(it) => it.module(db),
|
||||
Definition::GenericParam(it) => it.module(db),
|
||||
Definition::Label(it) => it.module(db),
|
||||
Definition::DeriveHelper(it) => it.derive().module(db),
|
||||
Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => {
|
||||
return None
|
||||
}
|
||||
@ -94,7 +96,8 @@ impl Definition {
|
||||
| Definition::SelfType(_)
|
||||
| Definition::Local(_)
|
||||
| Definition::GenericParam(_)
|
||||
| Definition::Label(_) => return None,
|
||||
| Definition::Label(_)
|
||||
| Definition::DeriveHelper(_) => return None,
|
||||
};
|
||||
Some(vis)
|
||||
}
|
||||
@ -118,6 +121,7 @@ impl Definition {
|
||||
Definition::Label(it) => it.name(db),
|
||||
Definition::BuiltinAttr(_) => return None, // FIXME
|
||||
Definition::ToolModule(_) => return None, // FIXME
|
||||
Definition::DeriveHelper(it) => it.name(db),
|
||||
};
|
||||
Some(name)
|
||||
}
|
||||
@ -500,6 +504,7 @@ impl From<PathResolution> for Definition {
|
||||
PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
|
||||
PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
|
||||
PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
|
||||
PathResolution::DeriveHelper(helper) => Definition::DeriveHelper(helper),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,6 +173,7 @@ pub enum SymbolKind {
|
||||
Const,
|
||||
ConstParam,
|
||||
Derive,
|
||||
DeriveHelper,
|
||||
Enum,
|
||||
Field,
|
||||
Function,
|
||||
|
@ -224,7 +224,8 @@ impl<'a> Ctx<'a> {
|
||||
| hir::PathResolution::SelfType(_)
|
||||
| hir::PathResolution::Def(_)
|
||||
| hir::PathResolution::BuiltinAttr(_)
|
||||
| hir::PathResolution::ToolModule(_) => (),
|
||||
| hir::PathResolution::ToolModule(_)
|
||||
| hir::PathResolution::DeriveHelper(_) => (),
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
@ -156,6 +156,8 @@ impl Definition {
|
||||
Definition::SelfType(_) => return None,
|
||||
Definition::BuiltinAttr(_) => return None,
|
||||
Definition::ToolModule(_) => return None,
|
||||
// FIXME: This should be doable in theory
|
||||
Definition::DeriveHelper(_) => return None,
|
||||
};
|
||||
return res;
|
||||
|
||||
@ -316,14 +318,20 @@ pub fn source_edit_from_references(
|
||||
// macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far
|
||||
let mut edited_ranges = Vec::new();
|
||||
for &FileReference { range, ref name, .. } in references {
|
||||
let name_range = name.syntax().text_range();
|
||||
if name_range.len() != range.len() {
|
||||
// This usage comes from a different token kind that was downmapped to a NameLike in a macro
|
||||
// Renaming this will most likely break things syntax-wise
|
||||
continue;
|
||||
}
|
||||
let has_emitted_edit = match name {
|
||||
// if the ranges differ then the node is inside a macro call, we can't really attempt
|
||||
// to make special rewrites like shorthand syntax and such, so just rename the node in
|
||||
// the macro input
|
||||
ast::NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == range => {
|
||||
ast::NameLike::NameRef(name_ref) if name_range == range => {
|
||||
source_edit_from_name_ref(&mut edit, name_ref, new_name, def)
|
||||
}
|
||||
ast::NameLike::Name(name) if name.syntax().text_range() == range => {
|
||||
ast::NameLike::Name(name) if name_range == range => {
|
||||
source_edit_from_name(&mut edit, name, new_name)
|
||||
}
|
||||
_ => false,
|
||||
|
@ -54,7 +54,9 @@ impl IntoIterator for UsageSearchResult {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileReference {
|
||||
/// The range of the reference in the original file
|
||||
pub range: TextRange,
|
||||
/// The node of the reference in the (macro-)file
|
||||
pub name: ast::NameLike,
|
||||
pub category: Option<ReferenceCategory>,
|
||||
}
|
||||
@ -276,16 +278,16 @@ impl Definition {
|
||||
}
|
||||
}
|
||||
hir::MacroKind::BuiltIn => SearchScope::crate_graph(db),
|
||||
// FIXME: We don't actually see derives in derive attributes as these do not
|
||||
// expand to something that references the derive macro in the output.
|
||||
// We could get around this by doing pseudo expansions for proc_macro_derive like we
|
||||
// do for the derive attribute
|
||||
hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => {
|
||||
SearchScope::reverse_dependencies(db, module.krate())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if let Definition::DeriveHelper(_) = self {
|
||||
return SearchScope::reverse_dependencies(db, module.krate());
|
||||
}
|
||||
|
||||
let vis = self.visibility(db);
|
||||
if let Some(Visibility::Public) = vis {
|
||||
return SearchScope::reverse_dependencies(db, module.krate());
|
||||
|
@ -190,7 +190,8 @@ pub(crate) fn resolve_doc_path_for_def(
|
||||
| Definition::SelfType(_)
|
||||
| Definition::Local(_)
|
||||
| Definition::GenericParam(_)
|
||||
| Definition::Label(_) => None,
|
||||
| Definition::Label(_)
|
||||
| Definition::DeriveHelper(_) => None,
|
||||
}
|
||||
.map(Definition::from)
|
||||
}
|
||||
@ -515,7 +516,8 @@ fn filename_and_frag_for_def(
|
||||
| Definition::GenericParam(_)
|
||||
| Definition::Label(_)
|
||||
| Definition::BuiltinAttr(_)
|
||||
| Definition::ToolModule(_) => return None,
|
||||
| Definition::ToolModule(_)
|
||||
| Definition::DeriveHelper(_) => return None,
|
||||
};
|
||||
|
||||
Some((def, res, None))
|
||||
|
@ -115,7 +115,12 @@ pub(crate) fn hover(
|
||||
});
|
||||
}
|
||||
|
||||
let descended = sema.descend_into_macros_with_same_text(original_token.clone());
|
||||
let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())));
|
||||
let descended = if in_attr {
|
||||
[sema.descend_into_macros_with_kind_preference(original_token.clone())].into()
|
||||
} else {
|
||||
sema.descend_into_macros_with_same_text(original_token.clone())
|
||||
};
|
||||
|
||||
// FIXME: Definition should include known lints and the like instead of having this special case here
|
||||
let hovered_lint = descended.iter().find_map(|token| {
|
||||
|
@ -370,6 +370,7 @@ pub(super) fn definition(
|
||||
// FIXME: We should be able to show more info about these
|
||||
Definition::BuiltinAttr(it) => return render_builtin_attr(db, it),
|
||||
Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))),
|
||||
Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None),
|
||||
};
|
||||
|
||||
let docs = match config.documentation {
|
||||
|
@ -196,6 +196,8 @@ impl TryToNav for Definition {
|
||||
Definition::BuiltinType(_) => None,
|
||||
Definition::ToolModule(_) => None,
|
||||
Definition::BuiltinAttr(_) => None,
|
||||
// FIXME: The focus range should be set to the helper declaration
|
||||
Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +237,8 @@ fn signature_help_for_generics(
|
||||
| hir::PathResolution::Local(_)
|
||||
| hir::PathResolution::TypeParam(_)
|
||||
| hir::PathResolution::ConstParam(_)
|
||||
| hir::PathResolution::SelfType(_) => return None,
|
||||
| hir::PathResolution::SelfType(_)
|
||||
| hir::PathResolution::DeriveHelper(_) => return None,
|
||||
};
|
||||
|
||||
generic_def
|
||||
|
@ -107,6 +107,7 @@ pub struct HlRange {
|
||||
// builtinType:: Emitted for builtin types like `u32`, `str` and `f32`.
|
||||
// comment:: Emitted for comments.
|
||||
// constParameter:: Emitted for const parameters.
|
||||
// deriveHelper:: Emitted for derive helper attributes.
|
||||
// enumMember:: Emitted for enum variants.
|
||||
// generic:: Emitted for generic tokens that have no mapping.
|
||||
// keyword:: Emitted for keywords.
|
||||
@ -431,6 +432,13 @@ fn traverse(
|
||||
// let the editor do its highlighting for these tokens instead
|
||||
continue;
|
||||
}
|
||||
if highlight.tag == HlTag::UnresolvedReference
|
||||
&& matches!(attr_or_derive_item, Some(AttrOrDerive::Derive(_)) if inside_attribute)
|
||||
{
|
||||
// do not emit unresolved references in derive helpers if the token mapping maps to
|
||||
// something unresolvable. FIXME: There should be a way to prevent that
|
||||
continue;
|
||||
}
|
||||
if inside_attribute {
|
||||
highlight |= HlMod::Attribute
|
||||
}
|
||||
|
@ -472,6 +472,7 @@ fn highlight_def(
|
||||
Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)),
|
||||
Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)),
|
||||
Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)),
|
||||
Definition::DeriveHelper(_) => Highlight::new(HlTag::Symbol(SymbolKind::DeriveHelper)),
|
||||
};
|
||||
|
||||
let def_crate = def.krate(db);
|
||||
|
@ -270,6 +270,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag {
|
||||
Definition::Label(_) => SymbolKind::Label,
|
||||
Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr,
|
||||
Definition::ToolModule(_) => SymbolKind::ToolModule,
|
||||
Definition::DeriveHelper(_) => SymbolKind::DeriveHelper,
|
||||
};
|
||||
HlTag::Symbol(symbol)
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ impl HlTag {
|
||||
SymbolKind::Const => "constant",
|
||||
SymbolKind::ConstParam => "const_param",
|
||||
SymbolKind::Derive => "derive",
|
||||
SymbolKind::DeriveHelper => "derive_helper",
|
||||
SymbolKind::Enum => "enum",
|
||||
SymbolKind::Field => "field",
|
||||
SymbolKind::Function => "function",
|
||||
|
@ -54,6 +54,7 @@ define_semantic_token_types![
|
||||
(COMPARISON, "comparison"),
|
||||
(CONST_PARAMETER, "constParameter"),
|
||||
(DERIVE, "derive"),
|
||||
(DERIVE_HELPER, "deriveHelper"),
|
||||
(DOT, "dot"),
|
||||
(ESCAPE_SEQUENCE, "escapeSequence"),
|
||||
(FORMAT_SPECIFIER, "formatSpecifier"),
|
||||
|
@ -53,7 +53,8 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
|
||||
SymbolKind::Macro
|
||||
| SymbolKind::BuiltinAttr
|
||||
| SymbolKind::Attribute
|
||||
| SymbolKind::Derive => lsp_types::SymbolKind::FUNCTION,
|
||||
| SymbolKind::Derive
|
||||
| SymbolKind::DeriveHelper => lsp_types::SymbolKind::FUNCTION,
|
||||
SymbolKind::Module | SymbolKind::ToolModule => lsp_types::SymbolKind::MODULE,
|
||||
SymbolKind::TypeAlias | SymbolKind::TypeParam | SymbolKind::SelfType => {
|
||||
lsp_types::SymbolKind::TYPE_PARAMETER
|
||||
@ -117,6 +118,7 @@ pub(crate) fn completion_item_kind(
|
||||
SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT,
|
||||
SymbolKind::ConstParam => lsp_types::CompletionItemKind::TYPE_PARAMETER,
|
||||
SymbolKind::Derive => lsp_types::CompletionItemKind::FUNCTION,
|
||||
SymbolKind::DeriveHelper => lsp_types::CompletionItemKind::FUNCTION,
|
||||
SymbolKind::Enum => lsp_types::CompletionItemKind::ENUM,
|
||||
SymbolKind::Field => lsp_types::CompletionItemKind::FIELD,
|
||||
SymbolKind::Function => lsp_types::CompletionItemKind::FUNCTION,
|
||||
@ -561,6 +563,7 @@ fn semantic_token_type_and_modifiers(
|
||||
HlTag::Symbol(symbol) => match symbol {
|
||||
SymbolKind::Attribute => semantic_tokens::ATTRIBUTE,
|
||||
SymbolKind::Derive => semantic_tokens::DERIVE,
|
||||
SymbolKind::DeriveHelper => semantic_tokens::DERIVE_HELPER,
|
||||
SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE,
|
||||
SymbolKind::Impl => semantic_tokens::TYPE_ALIAS,
|
||||
SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
|
||||
|
Loading…
x
Reference in New Issue
Block a user