mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +00:00
Introduce ra_cfg to parse and evaluate CfgExpr
This commit is contained in:
parent
ffe179a736
commit
b1ed887d81
11 changed files with 315 additions and 27 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -922,6 +922,16 @@ dependencies = [
|
|||
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ra_cfg"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ra_mbe 0.1.0",
|
||||
"ra_syntax 0.1.0",
|
||||
"ra_tt 0.1.0",
|
||||
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ra_cli"
|
||||
version = "0.1.0"
|
||||
|
@ -941,6 +951,7 @@ dependencies = [
|
|||
name = "ra_db"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ra_cfg 0.1.0",
|
||||
"ra_prof 0.1.0",
|
||||
"ra_syntax 0.1.0",
|
||||
"relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -971,6 +982,7 @@ dependencies = [
|
|||
"once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ra_arena 0.1.0",
|
||||
"ra_cfg 0.1.0",
|
||||
"ra_db 0.1.0",
|
||||
"ra_mbe 0.1.0",
|
||||
"ra_prof 0.1.0",
|
||||
|
@ -993,6 +1005,7 @@ dependencies = [
|
|||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ra_assists 0.1.0",
|
||||
"ra_cfg 0.1.0",
|
||||
"ra_db 0.1.0",
|
||||
"ra_fmt 0.1.0",
|
||||
"ra_hir 0.1.0",
|
||||
|
@ -1075,6 +1088,7 @@ dependencies = [
|
|||
"cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ra_arena 0.1.0",
|
||||
"ra_cfg 0.1.0",
|
||||
"ra_db 0.1.0",
|
||||
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
14
crates/ra_cfg/Cargo.toml
Normal file
14
crates/ra_cfg/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "ra_cfg"
|
||||
version = "0.1.0"
|
||||
authors = ["rust-analyzer developers"]
|
||||
|
||||
[dependencies]
|
||||
rustc-hash = "1.0.1"
|
||||
|
||||
ra_syntax = { path = "../ra_syntax" }
|
||||
tt = { path = "../ra_tt", package = "ra_tt" }
|
||||
|
||||
[dev-dependencies]
|
||||
mbe = { path = "../ra_mbe", package = "ra_mbe" }
|
128
crates/ra_cfg/src/cfg_expr.rs
Normal file
128
crates/ra_cfg/src/cfg_expr.rs
Normal file
|
@ -0,0 +1,128 @@
|
|||
use std::slice::Iter as SliceIter;
|
||||
|
||||
use ra_syntax::SmolStr;
|
||||
use tt::{Leaf, Subtree, TokenTree};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum CfgExpr {
|
||||
Invalid,
|
||||
Atom(SmolStr),
|
||||
KeyValue { key: SmolStr, value: SmolStr },
|
||||
All(Vec<CfgExpr>),
|
||||
Any(Vec<CfgExpr>),
|
||||
Not(Box<CfgExpr>),
|
||||
}
|
||||
|
||||
impl CfgExpr {
|
||||
/// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
|
||||
pub fn fold(&self, query: &impl Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> {
|
||||
match self {
|
||||
CfgExpr::Invalid => None,
|
||||
CfgExpr::Atom(name) => Some(query(name, None)),
|
||||
CfgExpr::KeyValue { key, value } => Some(query(key, Some(value))),
|
||||
CfgExpr::All(preds) => {
|
||||
preds.iter().try_fold(true, |s, pred| Some(s && pred.fold(query)?))
|
||||
}
|
||||
CfgExpr::Any(preds) => {
|
||||
preds.iter().try_fold(false, |s, pred| Some(s || pred.fold(query)?))
|
||||
}
|
||||
CfgExpr::Not(pred) => pred.fold(query).map(|s| !s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_cfg(tt: &Subtree) -> CfgExpr {
|
||||
next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
|
||||
}
|
||||
|
||||
fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> {
|
||||
let name = match it.next() {
|
||||
None => return None,
|
||||
Some(TokenTree::Leaf(Leaf::Ident(ident))) => ident.text.clone(),
|
||||
Some(_) => return Some(CfgExpr::Invalid),
|
||||
};
|
||||
|
||||
// Peek
|
||||
let ret = match it.as_slice().first() {
|
||||
Some(TokenTree::Leaf(Leaf::Punct(punct))) if punct.char == '=' => {
|
||||
match it.as_slice().get(1) {
|
||||
Some(TokenTree::Leaf(Leaf::Literal(literal))) => {
|
||||
it.next();
|
||||
it.next();
|
||||
// FIXME: escape? raw string?
|
||||
let value =
|
||||
SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"'));
|
||||
CfgExpr::KeyValue { key: name, value }
|
||||
}
|
||||
_ => return Some(CfgExpr::Invalid),
|
||||
}
|
||||
}
|
||||
Some(TokenTree::Subtree(subtree)) => {
|
||||
it.next();
|
||||
let mut sub_it = subtree.token_trees.iter();
|
||||
let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect();
|
||||
match name.as_str() {
|
||||
"all" => CfgExpr::All(subs),
|
||||
"any" => CfgExpr::Any(subs),
|
||||
"not" => CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))),
|
||||
_ => CfgExpr::Invalid,
|
||||
}
|
||||
}
|
||||
_ => CfgExpr::Atom(name),
|
||||
};
|
||||
|
||||
// Eat comma separator
|
||||
if let Some(TokenTree::Leaf(Leaf::Punct(punct))) = it.as_slice().first() {
|
||||
if punct.char == ',' {
|
||||
it.next();
|
||||
}
|
||||
}
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use mbe::ast_to_token_tree;
|
||||
use ra_syntax::ast::{self, AstNode};
|
||||
|
||||
fn assert_parse_result(input: &str, expected: CfgExpr) {
|
||||
let source_file = ast::SourceFile::parse(input).ok().unwrap();
|
||||
let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
|
||||
let (tt, _) = ast_to_token_tree(&tt).unwrap();
|
||||
assert_eq!(parse_cfg(&tt), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cfg_expr_parser() {
|
||||
assert_parse_result("#![cfg(foo)]", CfgExpr::Atom("foo".into()));
|
||||
assert_parse_result("#![cfg(foo,)]", CfgExpr::Atom("foo".into()));
|
||||
assert_parse_result(
|
||||
"#![cfg(not(foo))]",
|
||||
CfgExpr::Not(Box::new(CfgExpr::Atom("foo".into()))),
|
||||
);
|
||||
assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid);
|
||||
|
||||
// Only take the first
|
||||
assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgExpr::Atom("foo".into()));
|
||||
|
||||
assert_parse_result(
|
||||
r#"#![cfg(all(foo, bar = "baz"))]"#,
|
||||
CfgExpr::All(vec![
|
||||
CfgExpr::Atom("foo".into()),
|
||||
CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() },
|
||||
]),
|
||||
);
|
||||
|
||||
assert_parse_result(
|
||||
r#"#![cfg(any(not(), all(), , bar = "baz",))]"#,
|
||||
CfgExpr::Any(vec![
|
||||
CfgExpr::Not(Box::new(CfgExpr::Invalid)),
|
||||
CfgExpr::All(vec![]),
|
||||
CfgExpr::Invalid,
|
||||
CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() },
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
43
crates/ra_cfg/src/lib.rs
Normal file
43
crates/ra_cfg/src/lib.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
//! ra_cfg defines conditional compiling options, `cfg` attibute parser and evaluator
|
||||
use ra_syntax::SmolStr;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
mod cfg_expr;
|
||||
|
||||
pub use cfg_expr::{parse_cfg, CfgExpr};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct CfgOptions {
|
||||
atoms: FxHashSet<SmolStr>,
|
||||
features: FxHashSet<SmolStr>,
|
||||
options: FxHashMap<SmolStr, SmolStr>,
|
||||
}
|
||||
|
||||
impl CfgOptions {
|
||||
pub fn check(&self, cfg: &CfgExpr) -> Option<bool> {
|
||||
cfg.fold(&|key, value| match value {
|
||||
None => self.atoms.contains(key),
|
||||
Some(value) if key == "feature" => self.features.contains(value),
|
||||
Some(value) => self.options.get(key).map_or(false, |v| v == value),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_cfg_enabled(&self, attr: &tt::Subtree) -> Option<bool> {
|
||||
self.check(&parse_cfg(attr))
|
||||
}
|
||||
|
||||
pub fn atom(mut self, name: SmolStr) -> CfgOptions {
|
||||
self.atoms.insert(name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn feature(mut self, name: SmolStr) -> CfgOptions {
|
||||
self.features.insert(name);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn option(mut self, key: SmolStr, value: SmolStr) -> CfgOptions {
|
||||
self.options.insert(key, value);
|
||||
self
|
||||
}
|
||||
}
|
|
@ -10,4 +10,5 @@ relative-path = "0.4.0"
|
|||
rustc-hash = "1.0"
|
||||
|
||||
ra_syntax = { path = "../ra_syntax" }
|
||||
ra_cfg = { path = "../ra_cfg" }
|
||||
ra_prof = { path = "../ra_prof" }
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
use relative_path::{RelativePath, RelativePathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_syntax::SmolStr;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
|
@ -109,11 +110,13 @@ struct CrateData {
|
|||
file_id: FileId,
|
||||
edition: Edition,
|
||||
dependencies: Vec<Dependency>,
|
||||
cfg_options: CfgOptions,
|
||||
}
|
||||
|
||||
impl CrateData {
|
||||
fn new(file_id: FileId, edition: Edition) -> CrateData {
|
||||
CrateData { file_id, edition, dependencies: Vec::new() }
|
||||
// FIXME: cfg options
|
||||
CrateData { file_id, edition, dependencies: Vec::new(), cfg_options: CfgOptions::default() }
|
||||
}
|
||||
|
||||
fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
|
||||
|
@ -141,6 +144,10 @@ impl CrateGraph {
|
|||
crate_id
|
||||
}
|
||||
|
||||
pub fn cfg_options(&self, crate_id: CrateId) -> &CfgOptions {
|
||||
&self.arena[&crate_id].cfg_options
|
||||
}
|
||||
|
||||
pub fn add_dep(
|
||||
&mut self,
|
||||
from: CrateId,
|
||||
|
|
|
@ -15,6 +15,7 @@ once_cell = "1.0.1"
|
|||
|
||||
ra_syntax = { path = "../ra_syntax" }
|
||||
ra_arena = { path = "../ra_arena" }
|
||||
ra_cfg = { path = "../ra_cfg" }
|
||||
ra_db = { path = "../ra_db" }
|
||||
mbe = { path = "../ra_mbe", package = "ra_mbe" }
|
||||
tt = { path = "../ra_tt", package = "ra_tt" }
|
||||
|
|
58
crates/ra_hir/src/attr.rs
Normal file
58
crates/ra_hir/src/attr.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use mbe::ast_to_token_tree;
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode},
|
||||
SmolStr,
|
||||
};
|
||||
use tt::Subtree;
|
||||
|
||||
use crate::{db::AstDatabase, path::Path, Source};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct Attr {
|
||||
pub(crate) path: Path,
|
||||
pub(crate) input: Option<AttrInput>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum AttrInput {
|
||||
Literal(SmolStr),
|
||||
TokenTree(Subtree),
|
||||
}
|
||||
|
||||
impl Attr {
|
||||
pub(crate) fn from_src(
|
||||
Source { file_id, ast }: Source<ast::Attr>,
|
||||
db: &impl AstDatabase,
|
||||
) -> Option<Attr> {
|
||||
let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?;
|
||||
let input = match ast.input() {
|
||||
None => None,
|
||||
Some(ast::AttrInput::Literal(lit)) => {
|
||||
// FIXME: escape? raw string?
|
||||
let value = lit.syntax().first_token()?.text().trim_matches('"').into();
|
||||
Some(AttrInput::Literal(value))
|
||||
}
|
||||
Some(ast::AttrInput::TokenTree(tt)) => {
|
||||
Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
|
||||
}
|
||||
};
|
||||
|
||||
Some(Attr { path, input })
|
||||
}
|
||||
|
||||
pub(crate) fn is_simple_atom(&self, name: &str) -> bool {
|
||||
// FIXME: Avoid cloning
|
||||
self.path.as_ident().map_or(false, |s| s.to_string() == name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_cfg(&self) -> Option<&Subtree> {
|
||||
if self.is_simple_atom("cfg") {
|
||||
match &self.input {
|
||||
Some(AttrInput::TokenTree(subtree)) => Some(subtree),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ mod traits;
|
|||
mod type_alias;
|
||||
mod type_ref;
|
||||
mod ty;
|
||||
mod attr;
|
||||
mod impl_block;
|
||||
mod expr;
|
||||
mod lang_item;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
//! FIXME: write short doc here
|
||||
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_db::FileId;
|
||||
use ra_syntax::{ast, SmolStr};
|
||||
use rustc_hash::FxHashMap;
|
||||
use test_utils::tested_by;
|
||||
|
||||
use crate::{
|
||||
attr::Attr,
|
||||
db::DefDatabase,
|
||||
ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
|
||||
name::MACRO_RULES,
|
||||
|
@ -35,6 +37,9 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
|
|||
}
|
||||
}
|
||||
|
||||
let crate_graph = db.crate_graph();
|
||||
let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
|
||||
|
||||
let mut collector = DefCollector {
|
||||
db,
|
||||
def_map,
|
||||
|
@ -42,6 +47,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
|
|||
unresolved_imports: Vec::new(),
|
||||
unexpanded_macros: Vec::new(),
|
||||
macro_stack_monitor: MacroStackMonitor::default(),
|
||||
cfg_options,
|
||||
};
|
||||
collector.collect();
|
||||
collector.finish()
|
||||
|
@ -76,8 +82,8 @@ impl MacroStackMonitor {
|
|||
}
|
||||
|
||||
/// Walks the tree of module recursively
|
||||
struct DefCollector<DB> {
|
||||
db: DB,
|
||||
struct DefCollector<'a, DB> {
|
||||
db: &'a DB,
|
||||
def_map: CrateDefMap,
|
||||
glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
|
||||
unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
|
||||
|
@ -86,9 +92,11 @@ struct DefCollector<DB> {
|
|||
/// Some macro use `$tt:tt which mean we have to handle the macro perfectly
|
||||
/// To prevent stack overflow, we add a deep counter here for prevent that.
|
||||
macro_stack_monitor: MacroStackMonitor,
|
||||
|
||||
cfg_options: &'a CfgOptions,
|
||||
}
|
||||
|
||||
impl<'a, DB> DefCollector<&'a DB>
|
||||
impl<DB> DefCollector<'_, DB>
|
||||
where
|
||||
DB: DefDatabase,
|
||||
{
|
||||
|
@ -506,7 +514,7 @@ struct ModCollector<'a, D> {
|
|||
parent_module: Option<ParentModule<'a>>,
|
||||
}
|
||||
|
||||
impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>>
|
||||
impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
|
||||
where
|
||||
DB: DefDatabase,
|
||||
{
|
||||
|
@ -523,6 +531,7 @@ where
|
|||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
for item in items {
|
||||
if self.is_cfg_enabled(&item.attrs) {
|
||||
if let raw::RawItemKind::Import(import_id) = item.kind {
|
||||
let import = self.raw_items[import_id].clone();
|
||||
if import.is_extern_crate && import.is_macro_use {
|
||||
|
@ -530,8 +539,10 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for item in items {
|
||||
if self.is_cfg_enabled(&item.attrs) {
|
||||
match item.kind {
|
||||
raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]),
|
||||
raw::RawItemKind::Import(import_id) => self
|
||||
|
@ -543,6 +554,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_module(&mut self, module: &raw::ModuleData) {
|
||||
match module {
|
||||
|
@ -702,6 +714,13 @@ where
|
|||
self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_cfg_enabled(&self, attrs: &[Attr]) -> bool {
|
||||
attrs
|
||||
.iter()
|
||||
.flat_map(|attr| attr.as_cfg())
|
||||
.all(|cfg| self.def_collector.cfg_options.is_cfg_enabled(cfg).unwrap_or(true))
|
||||
}
|
||||
}
|
||||
|
||||
fn is_macro_rules(path: &Path) -> bool {
|
||||
|
@ -729,6 +748,7 @@ mod tests {
|
|||
unresolved_imports: Vec::new(),
|
||||
unexpanded_macros: Vec::new(),
|
||||
macro_stack_monitor: monitor,
|
||||
cfg_options: &CfgOptions::default(),
|
||||
};
|
||||
collector.collect();
|
||||
collector.finish()
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::{ops::Index, sync::Arc};
|
||||
|
||||
use mbe::ast_to_token_tree;
|
||||
use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
|
||||
use ra_syntax::{
|
||||
ast::{self, AttrsOwner, NameOwner},
|
||||
|
@ -11,6 +10,7 @@ use ra_syntax::{
|
|||
use test_utils::tested_by;
|
||||
|
||||
use crate::{
|
||||
attr::Attr,
|
||||
db::{AstDatabase, DefDatabase},
|
||||
AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
|
||||
};
|
||||
|
@ -29,8 +29,6 @@ pub struct RawItems {
|
|||
items: Vec<RawItem>,
|
||||
}
|
||||
|
||||
type Attrs = Arc<[tt::Subtree]>;
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct ImportSourceMap {
|
||||
map: ArenaMap<ImportId, ImportSourcePtr>,
|
||||
|
@ -124,7 +122,7 @@ impl Index<Macro> for RawItems {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub(super) struct RawItem {
|
||||
pub(super) attrs: Attrs,
|
||||
pub(super) attrs: Arc<[Attr]>,
|
||||
pub(super) kind: RawItemKind,
|
||||
}
|
||||
|
||||
|
@ -285,6 +283,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
let attrs = self.parse_attrs(&module);
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(&module);
|
||||
// FIXME: cfg_attr
|
||||
let is_macro_use = module.has_atom_attr("macro_use");
|
||||
if module.has_semi() {
|
||||
let attr_path = extract_mod_path_attribute(&module);
|
||||
|
@ -315,6 +314,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
}
|
||||
|
||||
fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
|
||||
// FIXME: cfg_attr
|
||||
let is_prelude = use_item.has_atom_attr("prelude_import");
|
||||
let attrs = self.parse_attrs(&use_item);
|
||||
|
||||
|
@ -349,6 +349,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
let path = Path::from_name_ref(&name_ref);
|
||||
let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
|
||||
let attrs = self.parse_attrs(&extern_crate);
|
||||
// FIXME: cfg_attr
|
||||
let is_macro_use = extern_crate.has_atom_attr("macro_use");
|
||||
let import_data = ImportData {
|
||||
path,
|
||||
|
@ -368,6 +369,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
}
|
||||
|
||||
fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
|
||||
let attrs = self.parse_attrs(&m);
|
||||
let path = match m
|
||||
.path()
|
||||
.and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db))
|
||||
|
@ -378,6 +380,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
|
||||
let name = m.name().map(|it| it.as_name());
|
||||
let ast_id = self.source_ast_id_map.ast_id(&m);
|
||||
// FIXME: cfg_attr
|
||||
let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
|
||||
|
||||
let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
|
||||
|
@ -387,7 +390,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
fn push_import(
|
||||
&mut self,
|
||||
current_module: Option<Module>,
|
||||
attrs: Attrs,
|
||||
attrs: Arc<[Attr]>,
|
||||
data: ImportData,
|
||||
source: ImportSourcePtr,
|
||||
) {
|
||||
|
@ -396,7 +399,7 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
self.push_item(current_module, attrs, RawItemKind::Import(import))
|
||||
}
|
||||
|
||||
fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) {
|
||||
fn push_item(&mut self, current_module: Option<Module>, attrs: Arc<[Attr]>, kind: RawItemKind) {
|
||||
match current_module {
|
||||
Some(module) => match &mut self.raw_items.modules[module] {
|
||||
ModuleData::Definition { items, .. } => items,
|
||||
|
@ -407,11 +410,9 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
|
|||
.push(RawItem { attrs, kind })
|
||||
}
|
||||
|
||||
fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
|
||||
fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Arc<[Attr]> {
|
||||
item.attrs()
|
||||
.flat_map(|attr| attr.value())
|
||||
.flat_map(|tt| ast_to_token_tree(&tt))
|
||||
.map(|(tt, _)| tt)
|
||||
.flat_map(|ast| Attr::from_src(Source { ast, file_id: self.file_id }, self.db))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue