aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/attr.rs
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-12-07 19:38:28 +0000
committerLukas Wirth <[email protected]>2020-12-07 19:38:28 +0000
commitb064f6da9e4b439d8b7fdb083d65e330fb599ef8 (patch)
treea91c3ab6637b610e5a70a987a3279c621e2c3377 /crates/hir_def/src/attr.rs
parentefe86a42dc922ca2cb38227f3b0bf6a420d3cfca (diff)
Keep doc attribute order
Diffstat (limited to 'crates/hir_def/src/attr.rs')
-rw-r--r--crates/hir_def/src/attr.rs40
1 files changed, 26 insertions, 14 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 4e8b908d0..43f0355e5 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -9,7 +9,7 @@ use itertools::Itertools;
9use mbe::ast_to_token_tree; 9use mbe::ast_to_token_tree;
10use syntax::{ 10use syntax::{
11 ast::{self, AstNode, AttrsOwner}, 11 ast::{self, AstNode, AttrsOwner},
12 SmolStr, 12 AstToken, SmolStr,
13}; 13};
14use tt::Subtree; 14use tt::Subtree;
15 15
@@ -110,18 +110,25 @@ impl Attrs {
110 } 110 }
111 111
112 pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { 112 pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
113 let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map( 113 let docs = ast::CommentIter::from_syntax_node(owner.syntax()).map(|docs_text| {
114 |docs_text| Attr { 114 (
115 input: Some(AttrInput::Literal(SmolStr::new(docs_text))), 115 docs_text.syntax().text_range().start(),
116 path: ModPath::from(hir_expand::name!(doc)), 116 docs_text.doc_comment().map(|doc| Attr {
117 }, 117 input: Some(AttrInput::Literal(SmolStr::new(doc))),
118 ); 118 path: ModPath::from(hir_expand::name!(doc)),
119 let mut attrs = owner.attrs().peekable(); 119 }),
120 let entries = if attrs.peek().is_none() && docs.is_none() { 120 )
121 });
122 let attrs = owner
123 .attrs()
124 .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene)));
125 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
126 let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect();
127 let entries = if attrs.is_empty() {
121 // Avoid heap allocation 128 // Avoid heap allocation
122 None 129 None
123 } else { 130 } else {
124 Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect()) 131 Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect())
125 }; 132 };
126 Attrs { entries } 133 Attrs { entries }
127 } 134 }
@@ -195,10 +202,15 @@ impl Attr {
195 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 202 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
196 let path = ModPath::from_src(ast.path()?, hygiene)?; 203 let path = ModPath::from_src(ast.path()?, hygiene)?;
197 let input = if let Some(lit) = ast.literal() { 204 let input = if let Some(lit) = ast.literal() {
198 let value = if let ast::LiteralKind::String(string) = lit.kind() { 205 // FIXME: escape?
199 string.value()?.into() 206 let value = match lit.kind() {
200 } else { 207 ast::LiteralKind::String(string) if string.is_raw() => {
201 lit.syntax().first_token()?.text().trim_matches('"').into() 208 let text = string.text().as_str();
209 let text = &text[string.text_range_between_quotes()?
210 - string.syntax().text_range().start()];
211 text.into()
212 }
213 _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
202 }; 214 };
203 Some(AttrInput::Literal(value)) 215 Some(AttrInput::Literal(value))
204 } else if let Some(tt) = ast.token_tree() { 216 } else if let Some(tt) = ast.token_tree() {