mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
Resolve $crate
in derive paths
This commit is contained in:
parent
2400b36a2e
commit
cf72b6232b
3 changed files with 56 additions and 17 deletions
|
@ -14,6 +14,7 @@ use hir_expand::{
|
||||||
builtin_attr_macro::find_builtin_attr,
|
builtin_attr_macro::find_builtin_attr,
|
||||||
builtin_derive_macro::find_builtin_derive,
|
builtin_derive_macro::find_builtin_derive,
|
||||||
builtin_fn_macro::find_builtin_macro,
|
builtin_fn_macro::find_builtin_macro,
|
||||||
|
hygiene::Hygiene,
|
||||||
name::{name, AsName, Name},
|
name::{name, AsName, Name},
|
||||||
proc_macro::ProcMacroExpander,
|
proc_macro::ProcMacroExpander,
|
||||||
ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
|
ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
|
||||||
|
@ -312,13 +313,14 @@ impl DefCollector<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *attr_name == hir_expand::name![feature] {
|
if *attr_name == hir_expand::name![feature] {
|
||||||
let features =
|
let features = attr
|
||||||
attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
|
.parse_path_comma_token_tree(self.db.upcast(), Hygiene::new_unhygienic())
|
||||||
|feat| match feat.segments() {
|
.into_iter()
|
||||||
[name] => Some(name.to_smol_str()),
|
.flatten()
|
||||||
_ => None,
|
.filter_map(|feat| match feat.segments() {
|
||||||
},
|
[name] => Some(name.to_smol_str()),
|
||||||
);
|
_ => None,
|
||||||
|
});
|
||||||
self.def_map.unstable_features.extend(features);
|
self.def_map.unstable_features.extend(features);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1223,8 +1225,9 @@ impl DefCollector<'_> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let ast_id = ast_id.with_value(ast_adt_id);
|
let ast_id = ast_id.with_value(ast_adt_id);
|
||||||
|
let hygiene = Hygiene::new(self.db.upcast(), file_id);
|
||||||
|
|
||||||
match attr.parse_path_comma_token_tree() {
|
match attr.parse_path_comma_token_tree(self.db.upcast(), hygiene) {
|
||||||
Some(derive_macros) => {
|
Some(derive_macros) => {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
for (idx, path) in derive_macros.enumerate() {
|
for (idx, path) in derive_macros.enumerate() {
|
||||||
|
|
|
@ -664,6 +664,29 @@ pub struct bar;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn macro_dollar_crate_is_correct_in_derive_meta() {
|
||||||
|
let map = compute_crate_def_map(
|
||||||
|
r#"
|
||||||
|
//- minicore: derive, clone
|
||||||
|
//- /main.rs crate:main deps:lib
|
||||||
|
lib::foo!();
|
||||||
|
|
||||||
|
//- /lib.rs crate:lib
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! foo {
|
||||||
|
() => {
|
||||||
|
#[derive($crate::Clone)]
|
||||||
|
struct S;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use core::clone::Clone;
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(map.modules[map.root].scope.impls().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expand_derive() {
|
fn expand_derive() {
|
||||||
let map = compute_crate_def_map(
|
let map = compute_crate_def_map(
|
||||||
|
|
|
@ -12,8 +12,7 @@ use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::ExpandDatabase,
|
db::ExpandDatabase,
|
||||||
hygiene::Hygiene,
|
hygiene::Hygiene,
|
||||||
mod_path::{ModPath, PathKind},
|
mod_path::ModPath,
|
||||||
name::AsName,
|
|
||||||
tt::{self, Subtree},
|
tt::{self, Subtree},
|
||||||
InFile,
|
InFile,
|
||||||
};
|
};
|
||||||
|
@ -267,7 +266,11 @@ impl Attr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses this attribute as a token tree consisting of comma separated paths.
|
/// Parses this attribute as a token tree consisting of comma separated paths.
|
||||||
pub fn parse_path_comma_token_tree(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
|
pub fn parse_path_comma_token_tree<'a>(
|
||||||
|
&'a self,
|
||||||
|
db: &'a dyn ExpandDatabase,
|
||||||
|
hygiene: Hygiene,
|
||||||
|
) -> Option<impl Iterator<Item = ModPath> + 'a> {
|
||||||
let args = self.token_tree_value()?;
|
let args = self.token_tree_value()?;
|
||||||
|
|
||||||
if args.delimiter.kind != DelimiterKind::Parenthesis {
|
if args.delimiter.kind != DelimiterKind::Parenthesis {
|
||||||
|
@ -276,15 +279,25 @@ impl Attr {
|
||||||
let paths = args
|
let paths = args
|
||||||
.token_trees
|
.token_trees
|
||||||
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
|
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
|
||||||
.filter_map(|tts| {
|
.filter_map(move |tts| {
|
||||||
if tts.is_empty() {
|
if tts.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let segments = tts.iter().filter_map(|tt| match tt {
|
// FIXME: This is necessarily a hack. It'd be nice if we could avoid allocation here.
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
|
let subtree = tt::Subtree {
|
||||||
_ => None,
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
});
|
token_trees: tts.into_iter().cloned().collect(),
|
||||||
Some(ModPath::from_segments(PathKind::Plain, segments))
|
};
|
||||||
|
let (parse, _) =
|
||||||
|
mbe::token_tree_to_syntax_node(&subtree, mbe::TopEntryPoint::MetaItem);
|
||||||
|
let meta = ast::Meta::cast(parse.syntax_node())?;
|
||||||
|
// Only simple paths are allowed.
|
||||||
|
if meta.eq_token().is_some() || meta.expr().is_some() || meta.token_tree().is_some()
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let path = meta.path()?;
|
||||||
|
ModPath::from_src(db, path, &hygiene)
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(paths)
|
Some(paths)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue