mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
fix: Properly handle proc-macro crate types for nameres
This commit is contained in:
parent
2537ad0d9e
commit
3edc5dcea8
8 changed files with 133 additions and 97 deletions
|
@ -160,6 +160,7 @@ impl ChangeFixture {
|
||||||
meta.cfg,
|
meta.cfg,
|
||||||
meta.env,
|
meta.env,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
origin,
|
origin,
|
||||||
);
|
);
|
||||||
let prev = crates.insert(crate_name.clone(), crate_id);
|
let prev = crates.insert(crate_name.clone(), crate_id);
|
||||||
|
@ -194,6 +195,7 @@ impl ChangeFixture {
|
||||||
default_cfg,
|
default_cfg,
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,6 +232,7 @@ impl ChangeFixture {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
|
false,
|
||||||
CrateOrigin::Lang,
|
CrateOrigin::Lang,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -266,6 +269,7 @@ impl ChangeFixture {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
proc_macro,
|
proc_macro,
|
||||||
|
true,
|
||||||
CrateOrigin::Lang,
|
CrateOrigin::Lang,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ pub enum CrateOrigin {
|
||||||
/// Crates that are provided by the language, like std, core, proc-macro, ...
|
/// Crates that are provided by the language, like std, core, proc-macro, ...
|
||||||
Lang,
|
Lang,
|
||||||
/// Crates that we don't know their origin.
|
/// Crates that we don't know their origin.
|
||||||
// Idealy this enum should cover all cases, and then we remove this variant.
|
// Ideally this enum should cover all cases, and then we remove this variant.
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +228,7 @@ pub struct CrateData {
|
||||||
pub dependencies: Vec<Dependency>,
|
pub dependencies: Vec<Dependency>,
|
||||||
pub proc_macro: Vec<ProcMacro>,
|
pub proc_macro: Vec<ProcMacro>,
|
||||||
pub origin: CrateOrigin,
|
pub origin: CrateOrigin,
|
||||||
|
pub is_proc_macro: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -279,6 +280,7 @@ impl CrateGraph {
|
||||||
potential_cfg_options: CfgOptions,
|
potential_cfg_options: CfgOptions,
|
||||||
env: Env,
|
env: Env,
|
||||||
proc_macro: Vec<ProcMacro>,
|
proc_macro: Vec<ProcMacro>,
|
||||||
|
is_proc_macro: bool,
|
||||||
origin: CrateOrigin,
|
origin: CrateOrigin,
|
||||||
) -> CrateId {
|
) -> CrateId {
|
||||||
let data = CrateData {
|
let data = CrateData {
|
||||||
|
@ -292,6 +294,7 @@ impl CrateGraph {
|
||||||
proc_macro,
|
proc_macro,
|
||||||
dependencies: Vec::new(),
|
dependencies: Vec::new(),
|
||||||
origin,
|
origin,
|
||||||
|
is_proc_macro,
|
||||||
};
|
};
|
||||||
let crate_id = CrateId(self.arena.len() as u32);
|
let crate_id = CrateId(self.arena.len() as u32);
|
||||||
let prev = self.arena.insert(crate_id, data);
|
let prev = self.arena.insert(crate_id, data);
|
||||||
|
@ -596,6 +599,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
|
@ -607,6 +611,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let crate3 = graph.add_crate_root(
|
let crate3 = graph.add_crate_root(
|
||||||
|
@ -618,6 +623,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
|
@ -643,6 +649,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
|
@ -654,6 +661,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
|
@ -676,6 +684,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
|
@ -687,6 +696,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let crate3 = graph.add_crate_root(
|
let crate3 = graph.add_crate_root(
|
||||||
|
@ -698,6 +708,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
|
@ -720,6 +731,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
|
@ -731,6 +743,7 @@ mod tests {
|
||||||
CfgOptions::default(),
|
CfgOptions::default(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
|
|
|
@ -154,18 +154,21 @@ impl RawAttrs {
|
||||||
return smallvec![attr.clone()];
|
return smallvec![attr.clone()];
|
||||||
}
|
}
|
||||||
|
|
||||||
let subtree = match attr.input.as_deref() {
|
let subtree = match attr.token_tree_value() {
|
||||||
Some(AttrInput::TokenTree(it, _)) => it,
|
Some(it) => it,
|
||||||
_ => return smallvec![attr.clone()],
|
_ => return smallvec![attr.clone()],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Input subtree is: `(cfg, $(attr),+)`
|
// Input subtree is: `(cfg, $(attr),+)`
|
||||||
// Split it up into a `cfg` subtree and the `attr` subtrees.
|
// Split it up into a `cfg` subtree and the `attr` subtrees.
|
||||||
// FIXME: There should be a common API for this.
|
// FIXME: There should be a common API for this.
|
||||||
let mut parts = subtree.token_trees.split(
|
let mut parts = subtree.token_trees.split(|tt| {
|
||||||
|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ','),
|
matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))
|
||||||
);
|
});
|
||||||
let cfg = parts.next().unwrap();
|
let cfg = match parts.next() {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return smallvec![],
|
||||||
|
};
|
||||||
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
|
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
|
||||||
let cfg = CfgExpr::parse(&cfg);
|
let cfg = CfgExpr::parse(&cfg);
|
||||||
let index = attr.id;
|
let index = attr.id;
|
||||||
|
@ -259,17 +262,8 @@ impl Attrs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn docs(&self) -> Option<Documentation> {
|
pub fn docs(&self) -> Option<Documentation> {
|
||||||
let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
|
let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value());
|
||||||
AttrInput::Literal(s) => Some(s),
|
let indent = doc_indent(self);
|
||||||
AttrInput::TokenTree(..) => None,
|
|
||||||
});
|
|
||||||
let indent = docs
|
|
||||||
.clone()
|
|
||||||
.flat_map(|s| s.lines())
|
|
||||||
.filter(|line| !line.chars().all(|c| c.is_whitespace()))
|
|
||||||
.map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
|
|
||||||
.min()
|
|
||||||
.unwrap_or(0);
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
for doc in docs {
|
for doc in docs {
|
||||||
// str::lines doesn't yield anything for the empty string
|
// str::lines doesn't yield anything for the empty string
|
||||||
|
@ -507,18 +501,9 @@ impl AttrsWithOwner {
|
||||||
&self,
|
&self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
) -> Option<(Documentation, DocsRangeMap)> {
|
) -> Option<(Documentation, DocsRangeMap)> {
|
||||||
// FIXME: code duplication in `docs` above
|
let docs =
|
||||||
let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
|
self.by_key("doc").attrs().filter_map(|attr| attr.string_value().map(|s| (s, attr.id)));
|
||||||
AttrInput::Literal(s) => Some((s, attr.id)),
|
let indent = doc_indent(self);
|
||||||
AttrInput::TokenTree(..) => None,
|
|
||||||
});
|
|
||||||
let indent = docs
|
|
||||||
.clone()
|
|
||||||
.flat_map(|(s, _)| s.lines())
|
|
||||||
.filter(|line| !line.chars().all(|c| c.is_whitespace()))
|
|
||||||
.map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
|
|
||||||
.min()
|
|
||||||
.unwrap_or(0);
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let mut mapping = Vec::new();
|
let mut mapping = Vec::new();
|
||||||
for (doc, idx) in docs {
|
for (doc, idx) in docs {
|
||||||
|
@ -557,6 +542,18 @@ impl AttrsWithOwner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn doc_indent(attrs: &Attrs) -> usize {
|
||||||
|
attrs
|
||||||
|
.by_key("doc")
|
||||||
|
.attrs()
|
||||||
|
.filter_map(|attr| attr.string_value())
|
||||||
|
.flat_map(|s| s.lines())
|
||||||
|
.filter(|line| !line.chars().all(|c| c.is_whitespace()))
|
||||||
|
.map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
|
||||||
|
.min()
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
fn inner_attributes(
|
fn inner_attributes(
|
||||||
syntax: &SyntaxNode,
|
syntax: &SyntaxNode,
|
||||||
) -> Option<impl Iterator<Item = Either<ast::Attr, ast::Comment>>> {
|
) -> Option<impl Iterator<Item = Either<ast::Attr, ast::Comment>>> {
|
||||||
|
@ -773,45 +770,58 @@ impl Attr {
|
||||||
Self::from_src(db, ast, hygiene, id)
|
Self::from_src(db, ast, hygiene, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> &ModPath {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Attr {
|
||||||
|
/// #[path = "string"]
|
||||||
|
pub fn string_value(&self) -> Option<&SmolStr> {
|
||||||
|
match self.input.as_deref()? {
|
||||||
|
AttrInput::Literal(it) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// #[path(ident)]
|
||||||
|
pub fn single_ident_value(&self) -> Option<&tt::Ident> {
|
||||||
|
match self.input.as_deref()? {
|
||||||
|
AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees {
|
||||||
|
[tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// #[path TokenTree]
|
||||||
|
pub fn token_tree_value(&self) -> Option<&Subtree> {
|
||||||
|
match self.input.as_deref()? {
|
||||||
|
AttrInput::TokenTree(subtree, _) => Some(subtree),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
|
||||||
let args = match self.input.as_deref() {
|
let args = self.token_tree_value()?;
|
||||||
Some(AttrInput::TokenTree(args, _)) => args,
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
|
if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let paths = args
|
let paths = args
|
||||||
.token_trees
|
.token_trees
|
||||||
.iter()
|
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
|
||||||
.group_by(|tt| {
|
.map(|tts| {
|
||||||
matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))
|
let segments = tts.iter().filter_map(|tt| match tt {
|
||||||
})
|
|
||||||
.into_iter()
|
|
||||||
.filter(|(comma, _)| !*comma)
|
|
||||||
.map(|(_, tts)| {
|
|
||||||
let segments = tts.filter_map(|tt| match tt {
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
|
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
ModPath::from_segments(PathKind::Plain, segments)
|
ModPath::from_segments(PathKind::Plain, segments)
|
||||||
})
|
});
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Some(paths.into_iter())
|
Some(paths)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> &ModPath {
|
|
||||||
&self.path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn string_value(&self) -> Option<&SmolStr> {
|
|
||||||
match self.input.as_deref()? {
|
|
||||||
AttrInput::Literal(it) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,17 +833,11 @@ pub struct AttrQuery<'attr> {
|
||||||
|
|
||||||
impl<'attr> AttrQuery<'attr> {
|
impl<'attr> AttrQuery<'attr> {
|
||||||
pub fn tt_values(self) -> impl Iterator<Item = &'attr Subtree> {
|
pub fn tt_values(self) -> impl Iterator<Item = &'attr Subtree> {
|
||||||
self.attrs().filter_map(|attr| match attr.input.as_deref()? {
|
self.attrs().filter_map(|attr| attr.token_tree_value())
|
||||||
AttrInput::TokenTree(it, _) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string_value(self) -> Option<&'attr SmolStr> {
|
pub fn string_value(self) -> Option<&'attr SmolStr> {
|
||||||
self.attrs().find_map(|attr| match attr.input.as_deref()? {
|
self.attrs().find_map(|attr| attr.string_value())
|
||||||
AttrInput::Literal(it) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exists(self) -> bool {
|
pub fn exists(self) -> bool {
|
||||||
|
|
|
@ -22,10 +22,10 @@ use itertools::Itertools;
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
use limit::Limit;
|
use limit::Limit;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use syntax::ast;
|
use syntax::{ast, SmolStr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::{Attr, AttrId, AttrInput, Attrs},
|
attr::{Attr, AttrId, Attrs},
|
||||||
attr_macro_as_call_id,
|
attr_macro_as_call_id,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
derive_macro_as_call_id,
|
derive_macro_as_call_id,
|
||||||
|
@ -61,7 +61,8 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
|
||||||
|
|
||||||
let mut deps = FxHashMap::default();
|
let mut deps = FxHashMap::default();
|
||||||
// populate external prelude and dependency list
|
// populate external prelude and dependency list
|
||||||
for dep in &crate_graph[def_map.krate].dependencies {
|
let krate = &crate_graph[def_map.krate];
|
||||||
|
for dep in &krate.dependencies {
|
||||||
tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
|
tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
|
||||||
let dep_def_map = db.crate_def_map(dep.crate_id);
|
let dep_def_map = db.crate_def_map(dep.crate_id);
|
||||||
let dep_root = dep_def_map.module_id(dep_def_map.root);
|
let dep_root = dep_def_map.module_id(dep_def_map.root);
|
||||||
|
@ -73,9 +74,9 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cfg_options = &crate_graph[def_map.krate].cfg_options;
|
let cfg_options = &krate.cfg_options;
|
||||||
let proc_macros = &crate_graph[def_map.krate].proc_macro;
|
let proc_macros = krate
|
||||||
let proc_macros = proc_macros
|
.proc_macro
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, it)| {
|
.map(|(idx, it)| {
|
||||||
|
@ -87,6 +88,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
let is_proc_macro = krate.is_proc_macro;
|
||||||
|
|
||||||
let mut collector = DefCollector {
|
let mut collector = DefCollector {
|
||||||
db,
|
db,
|
||||||
|
@ -103,6 +105,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
|
||||||
from_glob_import: Default::default(),
|
from_glob_import: Default::default(),
|
||||||
skip_attrs: Default::default(),
|
skip_attrs: Default::default(),
|
||||||
derive_helpers_in_scope: Default::default(),
|
derive_helpers_in_scope: Default::default(),
|
||||||
|
is_proc_macro,
|
||||||
};
|
};
|
||||||
if tree_id.is_block() {
|
if tree_id.is_block() {
|
||||||
collector.seed_with_inner(tree_id);
|
collector.seed_with_inner(tree_id);
|
||||||
|
@ -243,6 +246,7 @@ struct DefCollector<'a> {
|
||||||
/// empty when proc. macro support is disabled (in which case we still do name resolution for
|
/// empty when proc. macro support is disabled (in which case we still do name resolution for
|
||||||
/// them).
|
/// them).
|
||||||
proc_macros: Vec<(Name, ProcMacroExpander)>,
|
proc_macros: Vec<(Name, ProcMacroExpander)>,
|
||||||
|
is_proc_macro: bool,
|
||||||
exports_proc_macros: bool,
|
exports_proc_macros: bool,
|
||||||
from_glob_import: PerNsGlobImports,
|
from_glob_import: PerNsGlobImports,
|
||||||
/// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
|
/// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
|
||||||
|
@ -277,27 +281,29 @@ impl DefCollector<'_> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if *attr_name == hir_expand::name![recursion_limit] {
|
if *attr_name == hir_expand::name![recursion_limit] {
|
||||||
if let Some(input) = &attr.input {
|
if let Some(limit) = attr.string_value() {
|
||||||
if let AttrInput::Literal(limit) = &**input {
|
if let Ok(limit) = limit.parse() {
|
||||||
if let Ok(limit) = limit.parse() {
|
self.def_map.recursion_limit = Some(limit);
|
||||||
self.def_map.recursion_limit = Some(limit);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *attr_name == hir_expand::name![crate_type] {
|
||||||
|
if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
|
||||||
|
self.is_proc_macro = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|
let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|
||||||
|| *attr_name == hir_expand::name![register_tool];
|
|| *attr_name == hir_expand::name![register_tool];
|
||||||
if !attr_is_register_like {
|
if !attr_is_register_like {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let registered_name = match attr.input.as_deref() {
|
let registered_name = match attr.single_ident_value() {
|
||||||
Some(AttrInput::TokenTree(subtree, _)) => match &*subtree.token_trees {
|
Some(ident) => ident.as_name(),
|
||||||
[tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(),
|
|
||||||
_ => continue,
|
|
||||||
},
|
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -404,8 +410,7 @@ impl DefCollector<'_> {
|
||||||
}
|
}
|
||||||
self.unresolved_imports = unresolved_imports;
|
self.unresolved_imports = unresolved_imports;
|
||||||
|
|
||||||
// FIXME: This condition should instead check if this is a `proc-macro` type crate.
|
if self.is_proc_macro {
|
||||||
if self.exports_proc_macros {
|
|
||||||
// A crate exporting procedural macros is not allowed to export anything else.
|
// A crate exporting procedural macros is not allowed to export anything else.
|
||||||
//
|
//
|
||||||
// Additionally, while the proc macro entry points must be `pub`, they are not publicly
|
// Additionally, while the proc macro entry points must be `pub`, they are not publicly
|
||||||
|
@ -1555,22 +1560,21 @@ impl ModCollector<'_, '_> {
|
||||||
let fn_id =
|
let fn_id =
|
||||||
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
|
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
|
||||||
|
|
||||||
let is_proc_macro = attrs.parse_proc_macro_decl(&it.name);
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
||||||
let vis = match is_proc_macro {
|
if self.def_collector.is_proc_macro {
|
||||||
Some(proc_macro) => {
|
if self.module_id == def_map.root {
|
||||||
// FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
|
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
|
||||||
let module_id = def_map.module_id(def_map.root());
|
let crate_root = def_map.module_id(def_map.root);
|
||||||
|
self.def_collector.export_proc_macro(
|
||||||
self.def_collector.export_proc_macro(
|
proc_macro,
|
||||||
proc_macro,
|
ItemTreeId::new(self.tree_id, id),
|
||||||
ItemTreeId::new(self.tree_id, id),
|
fn_id,
|
||||||
fn_id,
|
crate_root,
|
||||||
module_id,
|
);
|
||||||
);
|
}
|
||||||
Visibility::Module(module_id)
|
|
||||||
}
|
}
|
||||||
None => resolve_vis(def_map, &self.item_tree[it.visibility]),
|
}
|
||||||
};
|
|
||||||
update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
|
update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
|
||||||
}
|
}
|
||||||
ModItem::Struct(id) => {
|
ModItem::Struct(id) => {
|
||||||
|
@ -2099,6 +2103,7 @@ mod tests {
|
||||||
from_glob_import: Default::default(),
|
from_glob_import: Default::default(),
|
||||||
skip_attrs: Default::default(),
|
skip_attrs: Default::default(),
|
||||||
derive_helpers_in_scope: Default::default(),
|
derive_helpers_in_scope: Default::default(),
|
||||||
|
is_proc_macro: false,
|
||||||
};
|
};
|
||||||
collector.seed_with_top_level();
|
collector.seed_with_top_level();
|
||||||
collector.collect();
|
collector.collect();
|
||||||
|
|
|
@ -268,6 +268,7 @@ pub mod known {
|
||||||
bench,
|
bench,
|
||||||
cfg_accessible,
|
cfg_accessible,
|
||||||
cfg_eval,
|
cfg_eval,
|
||||||
|
crate_type,
|
||||||
derive,
|
derive,
|
||||||
global_allocator,
|
global_allocator,
|
||||||
test,
|
test,
|
||||||
|
|
|
@ -231,6 +231,7 @@ impl Analysis {
|
||||||
cfg_options,
|
cfg_options,
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
false,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
);
|
);
|
||||||
change.change_file(file_id, Some(Arc::new(text)));
|
change.change_file(file_id, Some(Arc::new(text)));
|
||||||
|
|
|
@ -34,6 +34,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
|
||||||
data.potential_cfg_options.clone(),
|
data.potential_cfg_options.clone(),
|
||||||
data.env.clone(),
|
data.env.clone(),
|
||||||
data.proc_macro.clone(),
|
data.proc_macro.clone(),
|
||||||
|
data.is_proc_macro,
|
||||||
data.origin.clone(),
|
data.origin.clone(),
|
||||||
);
|
);
|
||||||
map.insert(old_id, new_id);
|
map.insert(old_id, new_id);
|
||||||
|
|
|
@ -483,6 +483,7 @@ fn project_json_to_crate_graph(
|
||||||
cfg_options,
|
cfg_options,
|
||||||
env,
|
env,
|
||||||
proc_macro.unwrap_or_default(),
|
proc_macro.unwrap_or_default(),
|
||||||
|
krate.is_proc_macro,
|
||||||
if krate.display_name.is_some() {
|
if krate.display_name.is_some() {
|
||||||
CrateOrigin::CratesIo { repo: krate.repository.clone() }
|
CrateOrigin::CratesIo { repo: krate.repository.clone() }
|
||||||
} else {
|
} else {
|
||||||
|
@ -592,6 +593,7 @@ fn cargo_to_crate_graph(
|
||||||
&mut |path| load_proc_macro(&cargo[tgt].name, path),
|
&mut |path| load_proc_macro(&cargo[tgt].name, path),
|
||||||
file_id,
|
file_id,
|
||||||
&cargo[tgt].name,
|
&cargo[tgt].name,
|
||||||
|
cargo[tgt].is_proc_macro,
|
||||||
);
|
);
|
||||||
if cargo[tgt].kind == TargetKind::Lib {
|
if cargo[tgt].kind == TargetKind::Lib {
|
||||||
lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
|
lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
|
||||||
|
@ -707,6 +709,7 @@ fn detached_files_to_crate_graph(
|
||||||
cfg_options.clone(),
|
cfg_options.clone(),
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
|
false,
|
||||||
CrateOrigin::Unknown,
|
CrateOrigin::Unknown,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -759,6 +762,7 @@ fn handle_rustc_crates(
|
||||||
&mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
|
&mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
|
||||||
file_id,
|
file_id,
|
||||||
&rustc_workspace[tgt].name,
|
&rustc_workspace[tgt].name,
|
||||||
|
rustc_workspace[tgt].is_proc_macro,
|
||||||
);
|
);
|
||||||
pkg_to_lib_crate.insert(pkg, crate_id);
|
pkg_to_lib_crate.insert(pkg, crate_id);
|
||||||
// Add dependencies on core / std / alloc for this crate
|
// Add dependencies on core / std / alloc for this crate
|
||||||
|
@ -813,6 +817,7 @@ fn add_target_crate_root(
|
||||||
load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
|
load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec<ProcMacro>,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
cargo_name: &str,
|
cargo_name: &str,
|
||||||
|
is_proc_macro: bool,
|
||||||
) -> CrateId {
|
) -> CrateId {
|
||||||
let edition = pkg.edition;
|
let edition = pkg.edition;
|
||||||
let cfg_options = {
|
let cfg_options = {
|
||||||
|
@ -857,6 +862,7 @@ fn add_target_crate_root(
|
||||||
potential_cfg_options,
|
potential_cfg_options,
|
||||||
env,
|
env,
|
||||||
proc_macro,
|
proc_macro,
|
||||||
|
is_proc_macro,
|
||||||
CrateOrigin::CratesIo { repo: pkg.repository.clone() },
|
CrateOrigin::CratesIo { repo: pkg.repository.clone() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -901,6 +907,7 @@ fn sysroot_to_crate_graph(
|
||||||
cfg_options.clone(),
|
cfg_options.clone(),
|
||||||
env,
|
env,
|
||||||
proc_macro,
|
proc_macro,
|
||||||
|
false,
|
||||||
CrateOrigin::Lang,
|
CrateOrigin::Lang,
|
||||||
);
|
);
|
||||||
Some((krate, crate_id))
|
Some((krate, crate_id))
|
||||||
|
|
Loading…
Reference in a new issue