From b1ed887d813bf5775a16624694939fdf836f97b1 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Mon, 30 Sep 2019 06:52:15 +0800 Subject: Introduce ra_cfg to parse and evaluate CfgExpr --- crates/ra_hir/src/attr.rs | 58 ++++++++++++++++++++++++++++++++++ crates/ra_hir/src/lib.rs | 1 + crates/ra_hir/src/nameres/collector.rs | 52 ++++++++++++++++++++---------- crates/ra_hir/src/nameres/raw.rs | 21 ++++++------ 4 files changed, 106 insertions(+), 26 deletions(-) create mode 100644 crates/ra_hir/src/attr.rs (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs new file mode 100644 index 000000000..19be6de32 --- /dev/null +++ b/crates/ra_hir/src/attr.rs @@ -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, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AttrInput { + Literal(SmolStr), + TokenTree(Subtree), +} + +impl Attr { + pub(crate) fn from_src( + Source { file_id, ast }: Source, + db: &impl AstDatabase, + ) -> Option { + 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 + } + } +} diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 00031deba..4340e9d34 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -44,6 +44,7 @@ mod traits; mod type_alias; mod type_ref; mod ty; +mod attr; mod impl_block; mod expr; mod lang_item; diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 40e56dfe0..f0e790e4c 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -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, +struct DefCollector<'a, DB> { + db: &'a DB, def_map: CrateDefMap, glob_imports: FxHashMap>, unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, @@ -86,9 +92,11 @@ struct DefCollector { /// 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 DefCollector<'_, DB> where DB: DefDatabase, { @@ -506,7 +514,7 @@ struct ModCollector<'a, D> { parent_module: Option>, } -impl ModCollector<'_, &'_ mut DefCollector<&'_ DB>> +impl ModCollector<'_, &'_ mut DefCollector<'_, DB>> where DB: DefDatabase, { @@ -523,23 +531,27 @@ where // `#[macro_use] extern crate` is hoisted to imports macros before collecting // any other items. for item in items { - 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 { - self.def_collector.import_macros_from_extern_crate(self.module_id, &import); + 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 { + self.def_collector.import_macros_from_extern_crate(self.module_id, &import); + } } } } for item in items { - match item.kind { - raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]), - raw::RawItemKind::Import(import_id) => self - .def_collector - .unresolved_imports - .push((self.module_id, import_id, self.raw_items[import_id].clone())), - raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), - raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), + 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 + .def_collector + .unresolved_imports + .push((self.module_id, import_id, self.raw_items[import_id].clone())), + raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), + raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), + } } } } @@ -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() diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index cacbcb517..ff079bcf1 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs @@ -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, } -type Attrs = Arc<[tt::Subtree]>; - #[derive(Debug, Default, PartialEq, Eq)] pub struct ImportSourceMap { map: ArenaMap, @@ -124,7 +122,7 @@ impl Index 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 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 RawItemsCollector<&DB> { } fn add_use_item(&mut self, current_module: Option, 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 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 RawItemsCollector<&DB> { } fn add_macro(&mut self, current_module: Option, 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 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 RawItemsCollector<&DB> { fn push_import( &mut self, current_module: Option, - attrs: Attrs, + attrs: Arc<[Attr]>, data: ImportData, source: ImportSourcePtr, ) { @@ -396,7 +399,7 @@ impl RawItemsCollector<&DB> { self.push_item(current_module, attrs, RawItemKind::Import(import)) } - fn push_item(&mut self, current_module: Option, attrs: Attrs, kind: RawItemKind) { + fn push_item(&mut self, current_module: Option, 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 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() } } -- cgit v1.2.3