Nicer API for attrs

This commit is contained in:
Aleksey Kladov 2019-11-24 16:03:02 +03:00
parent 1956d57ed4
commit 4b74fb1d89
4 changed files with 39 additions and 33 deletions

View file

@ -4,7 +4,6 @@ use std::{ops, sync::Arc};
use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source}; use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source};
use mbe::ast_to_token_tree; use mbe::ast_to_token_tree;
use ra_cfg::CfgOptions;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, AttrsOwner}, ast::{self, AstNode, AttrsOwner},
SmolStr, SmolStr,
@ -85,17 +84,8 @@ impl Attrs {
Attrs { entries } Attrs { entries }
} }
pub fn has_atom(&self, atom: &str) -> bool { pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
self.iter().any(|it| it.is_simple_atom(atom)) AttrQuery { attrs: self, key }
}
pub fn find_string_value(&self, key: &str) -> Option<SmolStr> {
self.iter().filter(|attr| attr.is_simple_atom(key)).find_map(|attr| {
match attr.input.as_ref()? {
AttrInput::Literal(it) => Some(it.clone()),
_ => None,
}
})
} }
} }
@ -128,25 +118,37 @@ impl Attr {
Some(Attr { path, input }) Some(Attr { path, input })
} }
}
pub fn is_simple_atom(&self, name: &str) -> bool { pub struct AttrQuery<'a> {
// FIXME: Avoid cloning attrs: &'a Attrs,
self.path.as_ident().map_or(false, |s| s.to_string() == name) key: &'static str,
} }
// FIXME: handle cfg_attr :-) impl<'a> AttrQuery<'a> {
pub fn as_cfg(&self) -> Option<&Subtree> { pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
if !self.is_simple_atom("cfg") { self.attrs().filter_map(|attr| match attr.input.as_ref()? {
return None; AttrInput::TokenTree(it) => Some(it),
}
match &self.input {
Some(AttrInput::TokenTree(subtree)) => Some(subtree),
_ => None, _ => None,
} })
} }
pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> { pub fn string_value(self) -> Option<&'a SmolStr> {
cfg_options.is_cfg_enabled(self.as_cfg()?) self.attrs().find_map(|attr| match attr.input.as_ref()? {
AttrInput::Literal(it) => Some(it),
_ => None,
})
}
pub fn exists(self) -> bool {
self.attrs().next().is_some()
}
fn attrs(self) -> impl Iterator<Item = &'a Attr> {
let key = self.key;
self.attrs
.iter()
.filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
} }
} }

View file

@ -113,7 +113,7 @@ impl LangItems {
T: Into<AttrDefId> + Copy, T: Into<AttrDefId> + Copy,
{ {
let attrs = db.attrs(item.into()); let attrs = db.attrs(item.into());
if let Some(lang_item_name) = attrs.find_string_value("lang") { if let Some(lang_item_name) = attrs.by_key("lang").string_value() {
self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item)); self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item));
} }
} }

View file

@ -599,8 +599,8 @@ where
} }
fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) { fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) {
let path_attr = attrs.find_string_value("path"); let path_attr = attrs.by_key("path").string_value();
let is_macro_use = attrs.has_atom("macro_use"); let is_macro_use = attrs.by_key("macro_use").exists();
match module { match module {
// inline module, just recurse // inline module, just recurse
raw::ModuleData::Definition { name, items, ast_id } => { raw::ModuleData::Definition { name, items, ast_id } => {
@ -612,7 +612,7 @@ where
module_id, module_id,
file_id: self.file_id, file_id: self.file_id,
raw_items: self.raw_items, raw_items: self.raw_items,
mod_dir: self.mod_dir.descend_into_definition(name, path_attr.as_ref()), mod_dir: self.mod_dir.descend_into_definition(name, path_attr),
} }
.collect(&*items); .collect(&*items);
if is_macro_use { if is_macro_use {
@ -626,7 +626,7 @@ where
self.def_collector.db, self.def_collector.db,
self.file_id, self.file_id,
name, name,
path_attr.as_ref(), path_attr,
) { ) {
Ok((file_id, mod_dir)) => { Ok((file_id, mod_dir)) => {
let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
@ -796,7 +796,11 @@ where
} }
fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false)) // FIXME: handle cfg_attr :-)
attrs
.by_key("cfg")
.tt_values()
.all(|tt| self.def_collector.cfg_options.is_cfg_enabled(tt) != Some(false))
} }
} }

View file

@ -288,7 +288,7 @@ impl Completions {
} }
fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool { fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool {
node.attrs(db).has_atom("deprecated") node.attrs(db).by_key("deprecated").exists()
} }
fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {