Skip to content

fix: Properly handle proc-macro crate types for nameres #11664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/base_db/src/fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ impl ChangeFixture {
meta.cfg,
meta.env,
Default::default(),
false,
origin,
);
let prev = crates.insert(crate_name.clone(), crate_id);
Expand Down Expand Up @@ -194,6 +195,7 @@ impl ChangeFixture {
default_cfg,
Env::default(),
Default::default(),
false,
Default::default(),
);
} else {
Expand Down Expand Up @@ -230,6 +232,7 @@ impl ChangeFixture {
CfgOptions::default(),
Env::default(),
Vec::new(),
false,
CrateOrigin::Lang,
);

Expand Down Expand Up @@ -266,6 +269,7 @@ impl ChangeFixture {
CfgOptions::default(),
Env::default(),
proc_macro,
true,
CrateOrigin::Lang,
);

Expand Down
15 changes: 14 additions & 1 deletion crates/base_db/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub enum CrateOrigin {
/// Crates that are provided by the language, like std, core, proc-macro, ...
Lang,
/// 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,
}

Expand Down Expand Up @@ -228,6 +228,7 @@ pub struct CrateData {
pub dependencies: Vec<Dependency>,
pub proc_macro: Vec<ProcMacro>,
pub origin: CrateOrigin,
pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -279,6 +280,7 @@ impl CrateGraph {
potential_cfg_options: CfgOptions,
env: Env,
proc_macro: Vec<ProcMacro>,
is_proc_macro: bool,
origin: CrateOrigin,
) -> CrateId {
let data = CrateData {
Expand All @@ -292,6 +294,7 @@ impl CrateGraph {
proc_macro,
dependencies: Vec::new(),
origin,
is_proc_macro,
};
let crate_id = CrateId(self.arena.len() as u32);
let prev = self.arena.insert(crate_id, data);
Expand Down Expand Up @@ -596,6 +599,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
let crate2 = graph.add_crate_root(
Expand All @@ -607,6 +611,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
let crate3 = graph.add_crate_root(
Expand All @@ -618,6 +623,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
assert!(graph
Expand All @@ -643,6 +649,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
let crate2 = graph.add_crate_root(
Expand All @@ -654,6 +661,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
assert!(graph
Expand All @@ -676,6 +684,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
let crate2 = graph.add_crate_root(
Expand All @@ -687,6 +696,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
let crate3 = graph.add_crate_root(
Expand All @@ -698,6 +708,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
assert!(graph
Expand All @@ -720,6 +731,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
let crate2 = graph.add_crate_root(
Expand All @@ -731,6 +743,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
false,
Default::default(),
);
assert!(graph
Expand Down
130 changes: 67 additions & 63 deletions crates/hir_def/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,21 @@ impl RawAttrs {
return smallvec![attr.clone()];
}

let subtree = match attr.input.as_deref() {
Some(AttrInput::TokenTree(it, _)) => it,
let subtree = match attr.token_tree_value() {
Some(it) => it,
_ => return smallvec![attr.clone()],
};

// Input subtree is: `(cfg, $(attr),+)`
// Split it up into a `cfg` subtree and the `attr` subtrees.
// FIXME: There should be a common API for this.
let mut parts = subtree.token_trees.split(
|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ','),
);
let cfg = parts.next().unwrap();
let mut parts = subtree.token_trees.split(|tt| {
matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))
});
let cfg = match parts.next() {
Some(it) => it,
None => return smallvec![],
};
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
let cfg = CfgExpr::parse(&cfg);
let index = attr.id;
Expand Down Expand Up @@ -259,17 +262,8 @@ impl Attrs {
}

pub fn docs(&self) -> Option<Documentation> {
let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
AttrInput::Literal(s) => Some(s),
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 docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value());
let indent = doc_indent(self);
let mut buf = String::new();
for doc in docs {
// str::lines doesn't yield anything for the empty string
Expand Down Expand Up @@ -507,18 +501,9 @@ impl AttrsWithOwner {
&self,
db: &dyn DefDatabase,
) -> Option<(Documentation, DocsRangeMap)> {
// FIXME: code duplication in `docs` above
let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
AttrInput::Literal(s) => Some((s, attr.id)),
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 docs =
self.by_key("doc").attrs().filter_map(|attr| attr.string_value().map(|s| (s, attr.id)));
let indent = doc_indent(self);
let mut buf = String::new();
let mut mapping = Vec::new();
for (doc, idx) in docs {
Expand Down Expand Up @@ -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(
syntax: &SyntaxNode,
) -> Option<impl Iterator<Item = Either<ast::Attr, ast::Comment>>> {
Expand Down Expand Up @@ -773,45 +770,58 @@ impl Attr {
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.
pub fn parse_path_comma_token_tree(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
let args = match self.input.as_deref() {
Some(AttrInput::TokenTree(args, _)) => args,
_ => return None,
};
let args = self.token_tree_value()?;

if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
return None;
}
let paths = args
.token_trees
.iter()
.group_by(|tt| {
matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))
})
.into_iter()
.filter(|(comma, _)| !*comma)
.map(|(_, tts)| {
let segments = tts.filter_map(|tt| match tt {
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
.map(|tts| {
let segments = tts.iter().filter_map(|tt| match tt {
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
_ => None,
});
ModPath::from_segments(PathKind::Plain, segments)
})
.collect::<Vec<_>>();

Some(paths.into_iter())
}

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,
}
Some(paths)
}
}

Expand All @@ -823,17 +833,11 @@ pub struct AttrQuery<'attr> {

impl<'attr> AttrQuery<'attr> {
pub fn tt_values(self) -> impl Iterator<Item = &'attr Subtree> {
self.attrs().filter_map(|attr| match attr.input.as_deref()? {
AttrInput::TokenTree(it, _) => Some(it),
_ => None,
})
self.attrs().filter_map(|attr| attr.token_tree_value())
}

pub fn string_value(self) -> Option<&'attr SmolStr> {
self.attrs().find_map(|attr| match attr.input.as_deref()? {
AttrInput::Literal(it) => Some(it),
_ => None,
})
self.attrs().find_map(|attr| attr.string_value())
}

pub fn exists(self) -> bool {
Expand Down
Loading