aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/attr.rs')
-rw-r--r--crates/ra_hir_def/src/attr.rs108
1 files changed, 50 insertions, 58 deletions
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 48ce8cd93..53456fc08 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,9 +2,8 @@
2 2
3use std::{ops, sync::Arc}; 3use std::{ops, sync::Arc};
4 4
5use hir_expand::{either::Either, hygiene::Hygiene, AstId}; 5use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source};
6use mbe::ast_to_token_tree; 6use mbe::ast_to_token_tree;
7use ra_cfg::CfgOptions;
8use ra_syntax::{ 7use ra_syntax::{
9 ast::{self, AstNode, AttrsOwner}, 8 ast::{self, AstNode, AttrsOwner},
10 SmolStr, 9 SmolStr,
@@ -40,50 +39,53 @@ impl Attrs {
40 Some(it) => it, 39 Some(it) => it,
41 None => return Attrs::default(), 40 None => return Attrs::default(),
42 }; 41 };
43 let hygiene = Hygiene::new(db, src.file_id); 42 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
44 Attr::from_attrs_owner(&src.value, &hygiene)
45 } 43 }
46 AttrDefId::StructFieldId(it) => { 44 AttrDefId::StructFieldId(it) => {
47 let src = it.parent.child_source(db); 45 let src = it.parent.child_source(db);
48 match &src.value[it.local_id] { 46 match &src.value[it.local_id] {
49 Either::A(_tuple) => Attrs::default(), 47 Either::A(_tuple) => Attrs::default(),
50 Either::B(record) => { 48 Either::B(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
51 let hygiene = Hygiene::new(db, src.file_id);
52 Attr::from_attrs_owner(record, &hygiene)
53 }
54 } 49 }
55 } 50 }
56 AttrDefId::EnumVariantId(it) => { 51 AttrDefId::EnumVariantId(var_id) => {
57 let src = it.parent.child_source(db); 52 let src = var_id.parent.child_source(db);
58 let hygiene = Hygiene::new(db, src.file_id); 53 let src = src.as_ref().map(|it| &it[var_id.local_id]);
59 Attr::from_attrs_owner(&src.value[it.local_id], &hygiene) 54 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
60 } 55 }
61 AttrDefId::AdtId(it) => match it { 56 AttrDefId::AdtId(it) => match it {
62 AdtId::StructId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db), 57 AdtId::StructId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
63 AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 58 AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
64 AdtId::UnionId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db), 59 AdtId::UnionId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
65 }, 60 },
66 AttrDefId::StaticId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
67 AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 61 AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
68 AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db), 62 AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db),
69 AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 63 AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
70 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), 64 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db),
65 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db),
71 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), 66 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db),
72 AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), 67 AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db),
73 } 68 }
74 } 69 }
75 70
76 pub fn has_atom(&self, atom: &str) -> bool { 71 fn from_attrs_owner(db: &impl DefDatabase, owner: Source<&dyn AttrsOwner>) -> Attrs {
77 self.iter().any(|it| it.is_simple_atom(atom)) 72 let hygiene = Hygiene::new(db, owner.file_id);
73 Attrs::new(owner.value, &hygiene)
78 } 74 }
79 75
80 pub fn find_string_value(&self, key: &str) -> Option<SmolStr> { 76 pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
81 self.iter().filter(|attr| attr.is_simple_atom(key)).find_map(|attr| { 77 let mut attrs = owner.attrs().peekable();
82 match attr.input.as_ref()? { 78 let entries = if attrs.peek().is_none() {
83 AttrInput::Literal(it) => Some(it.clone()), 79 // Avoid heap allocation
84 _ => None, 80 None
85 } 81 } else {
86 }) 82 Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
83 };
84 Attrs { entries }
85 }
86
87 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
88 AttrQuery { attrs: self, key }
87 } 89 }
88} 90}
89 91
@@ -100,7 +102,7 @@ pub enum AttrInput {
100} 102}
101 103
102impl Attr { 104impl Attr {
103 pub(crate) fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 105 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
104 let path = Path::from_src(ast.path()?, hygiene)?; 106 let path = Path::from_src(ast.path()?, hygiene)?;
105 let input = match ast.input() { 107 let input = match ast.input() {
106 None => None, 108 None => None,
@@ -116,46 +118,37 @@ impl Attr {
116 118
117 Some(Attr { path, input }) 119 Some(Attr { path, input })
118 } 120 }
121}
119 122
120 pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { 123pub struct AttrQuery<'a> {
121 let mut attrs = owner.attrs().peekable(); 124 attrs: &'a Attrs,
122 let entries = if attrs.peek().is_none() { 125 key: &'static str,
123 // Avoid heap allocation 126}
124 None
125 } else {
126 Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
127 };
128 Attrs { entries }
129 }
130 127
131 pub fn is_simple_atom(&self, name: &str) -> bool { 128impl<'a> AttrQuery<'a> {
132 // FIXME: Avoid cloning 129 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
133 self.path.as_ident().map_or(false, |s| s.to_string() == name) 130 self.attrs().filter_map(|attr| match attr.input.as_ref()? {
131 AttrInput::TokenTree(it) => Some(it),
132 _ => None,
133 })
134 } 134 }
135 135
136 // FIXME: handle cfg_attr :-) 136 pub fn string_value(self) -> Option<&'a SmolStr> {
137 pub fn as_cfg(&self) -> Option<&Subtree> { 137 self.attrs().find_map(|attr| match attr.input.as_ref()? {
138 if !self.is_simple_atom("cfg") { 138 AttrInput::Literal(it) => Some(it),
139 return None;
140 }
141 match &self.input {
142 Some(AttrInput::TokenTree(subtree)) => Some(subtree),
143 _ => None, 139 _ => None,
144 } 140 })
145 } 141 }
146 142
147 pub fn as_path(&self) -> Option<&SmolStr> { 143 pub fn exists(self) -> bool {
148 if !self.is_simple_atom("path") { 144 self.attrs().next().is_some()
149 return None;
150 }
151 match &self.input {
152 Some(AttrInput::Literal(it)) => Some(it),
153 _ => None,
154 }
155 } 145 }
156 146
157 pub fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> { 147 fn attrs(self) -> impl Iterator<Item = &'a Attr> {
158 cfg_options.is_cfg_enabled(self.as_cfg()?) 148 let key = self.key;
149 self.attrs
150 .iter()
151 .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
159 } 152 }
160} 153}
161 154
@@ -164,8 +157,8 @@ where
164 N: ast::AttrsOwner, 157 N: ast::AttrsOwner,
165 D: DefDatabase, 158 D: DefDatabase,
166{ 159{
167 let hygiene = Hygiene::new(db, src.file_id()); 160 let src = Source::new(src.file_id(), src.to_node(db));
168 Attr::from_attrs_owner(&src.to_node(db), &hygiene) 161 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
169} 162}
170 163
171fn attrs_from_loc<T, D>(node: T, db: &D) -> Attrs 164fn attrs_from_loc<T, D>(node: T, db: &D) -> Attrs
@@ -175,6 +168,5 @@ where
175 D: DefDatabase, 168 D: DefDatabase,
176{ 169{
177 let src = node.source(db); 170 let src = node.source(db);
178 let hygiene = Hygiene::new(db, src.file_id); 171 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
179 Attr::from_attrs_owner(&src.value, &hygiene)
180} 172}