Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 20290b2

Browse files
committed
Auto merge of rust-lang#16909 - Veykril:spans, r=Veykril
fix: Keep the span for `Attr::Literal` around
2 parents 83f9cc6 + 0036762 commit 20290b2

File tree

8 files changed

+115
-87
lines changed

8 files changed

+115
-87
lines changed

crates/hir-def/src/attr.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ impl Attrs {
148148
}
149149
}
150150

151-
pub fn lang(&self) -> Option<&SmolStr> {
151+
pub fn lang(&self) -> Option<&str> {
152152
self.by_key("lang").string_value()
153153
}
154154

155155
pub fn lang_item(&self) -> Option<LangItem> {
156-
self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
156+
self.by_key("lang").string_value().and_then(LangItem::from_str)
157157
}
158158

159159
pub fn has_doc_hidden(&self) -> bool {
@@ -178,7 +178,7 @@ impl Attrs {
178178
self.doc_exprs().flat_map(|doc_expr| doc_expr.aliases().to_vec())
179179
}
180180

181-
pub fn export_name(&self) -> Option<&SmolStr> {
181+
pub fn export_name(&self) -> Option<&str> {
182182
self.by_key("export_name").string_value()
183183
}
184184

@@ -565,7 +565,7 @@ impl<'attr> AttrQuery<'attr> {
565565
self.attrs().filter_map(|attr| attr.token_tree_value())
566566
}
567567

568-
pub fn string_value(self) -> Option<&'attr SmolStr> {
568+
pub fn string_value(self) -> Option<&'attr str> {
569569
self.attrs().find_map(|attr| attr.string_value())
570570
}
571571

crates/hir-def/src/lang_item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl LangItems {
192192

193193
pub(crate) fn lang_attr(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
194194
let attrs = db.attrs(item);
195-
attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
195+
attrs.by_key("lang").string_value().and_then(LangItem::from_str)
196196
}
197197

198198
pub(crate) fn notable_traits_in_deps(

crates/hir-def/src/nameres/collector.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use limit::Limit;
2424
use rustc_hash::{FxHashMap, FxHashSet};
2525
use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
2626
use stdx::always;
27-
use syntax::{ast, SmolStr};
27+
use syntax::ast;
2828
use triomphe::Arc;
2929

3030
use crate::{
@@ -312,7 +312,7 @@ impl DefCollector<'_> {
312312
}
313313
}
314314
() if *attr_name == hir_expand::name![crate_type] => {
315-
if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
315+
if let Some("proc-macro") = attr.string_value() {
316316
self.is_proc_macro = true;
317317
}
318318
}
@@ -1902,7 +1902,7 @@ impl ModCollector<'_, '_> {
19021902
}
19031903

19041904
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
1905-
let path_attr = attrs.by_key("path").string_value().map(SmolStr::as_str);
1905+
let path_attr = attrs.by_key("path").string_value();
19061906
let is_macro_use = attrs.by_key("macro_use").exists();
19071907
let module = &self.item_tree[module_id];
19081908
match &module.kind {
@@ -2146,7 +2146,7 @@ impl ModCollector<'_, '_> {
21462146
Some(it) => {
21472147
// FIXME: a hacky way to create a Name from string.
21482148
name = tt::Ident {
2149-
text: it.clone(),
2149+
text: it.into(),
21502150
span: Span {
21512151
range: syntax::TextRange::empty(syntax::TextSize::new(0)),
21522152
anchor: span::SpanAnchor {

crates/hir-expand/src/attrs.rs

Lines changed: 95 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use intern::Interned;
88
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
99
use smallvec::{smallvec, SmallVec};
1010
use span::{Span, SyntaxContextId};
11-
use syntax::{ast, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
12-
use triomphe::Arc;
11+
use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
12+
use triomphe::ThinArc;
1313

1414
use crate::{
1515
db::ExpandDatabase,
@@ -22,16 +22,15 @@ use crate::{
2222
/// Syntactical attributes, without filtering of `cfg_attr`s.
2323
#[derive(Default, Debug, Clone, PartialEq, Eq)]
2424
pub struct RawAttrs {
25-
// FIXME: Make this a ThinArc
26-
entries: Option<Arc<[Attr]>>,
25+
entries: Option<ThinArc<(), Attr>>,
2726
}
2827

2928
impl ops::Deref for RawAttrs {
3029
type Target = [Attr];
3130

3231
fn deref(&self) -> &[Attr] {
3332
match &self.entries {
34-
Some(it) => it,
33+
Some(it) => &it.slice,
3534
None => &[],
3635
}
3736
}
@@ -45,20 +44,34 @@ impl RawAttrs {
4544
owner: &dyn ast::HasAttrs,
4645
span_map: SpanMapRef<'_>,
4746
) -> Self {
48-
let entries = collect_attrs(owner).filter_map(|(id, attr)| match attr {
49-
Either::Left(attr) => {
50-
attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id))
51-
}
52-
Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
53-
id,
54-
input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
55-
path: Interned::new(ModPath::from(crate::name!(doc))),
56-
ctxt: span_map.span_for_range(comment.syntax().text_range()).ctx,
57-
}),
58-
});
59-
let entries: Arc<[Attr]> = Arc::from_iter(entries);
47+
let entries: Vec<_> = collect_attrs(owner)
48+
.filter_map(|(id, attr)| match attr {
49+
Either::Left(attr) => {
50+
attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id))
51+
}
52+
Either::Right(comment) => comment.doc_comment().map(|doc| {
53+
let span = span_map.span_for_range(comment.syntax().text_range());
54+
Attr {
55+
id,
56+
input: Some(Interned::new(AttrInput::Literal(tt::Literal {
57+
// FIXME: Escape quotes from comment content
58+
text: SmolStr::new(format_smolstr!("\"{doc}\"",)),
59+
span,
60+
}))),
61+
path: Interned::new(ModPath::from(crate::name!(doc))),
62+
ctxt: span.ctx,
63+
}
64+
}),
65+
})
66+
.collect();
6067

61-
Self { entries: if entries.is_empty() { None } else { Some(entries) } }
68+
let entries = if entries.is_empty() {
69+
None
70+
} else {
71+
Some(ThinArc::from_header_and_iter((), entries.into_iter()))
72+
};
73+
74+
RawAttrs { entries }
6275
}
6376

6477
pub fn from_attrs_owner(
@@ -75,16 +88,20 @@ impl RawAttrs {
7588
(None, entries @ Some(_)) => Self { entries },
7689
(Some(entries), None) => Self { entries: Some(entries.clone()) },
7790
(Some(a), Some(b)) => {
78-
let last_ast_index = a.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
79-
Self {
80-
entries: Some(Arc::from_iter(a.iter().cloned().chain(b.iter().map(|it| {
91+
let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
92+
let items = a
93+
.slice
94+
.iter()
95+
.cloned()
96+
.chain(b.slice.iter().map(|it| {
8197
let mut it = it.clone();
8298
it.id.id = (it.id.ast_index() as u32 + last_ast_index)
8399
| (it.id.cfg_attr_index().unwrap_or(0) as u32)
84100
<< AttrId::AST_INDEX_BITS;
85101
it
86-
})))),
87-
}
102+
}))
103+
.collect::<Vec<_>>();
104+
Self { entries: Some(ThinArc::from_header_and_iter((), items.into_iter())) }
88105
}
89106
}
90107
}
@@ -100,41 +117,47 @@ impl RawAttrs {
100117
}
101118

102119
let crate_graph = db.crate_graph();
103-
let new_attrs = Arc::from_iter(self.iter().flat_map(|attr| -> SmallVec<[_; 1]> {
104-
let is_cfg_attr =
105-
attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]);
106-
if !is_cfg_attr {
107-
return smallvec![attr.clone()];
108-
}
109-
110-
let subtree = match attr.token_tree_value() {
111-
Some(it) => it,
112-
_ => return smallvec![attr.clone()],
113-
};
114-
115-
let (cfg, parts) = match parse_cfg_attr_input(subtree) {
116-
Some(it) => it,
117-
None => return smallvec![attr.clone()],
118-
};
119-
let index = attr.id;
120-
let attrs = parts
121-
.enumerate()
122-
.take(1 << AttrId::CFG_ATTR_BITS)
123-
.filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
124-
125-
let cfg_options = &crate_graph[krate].cfg_options;
126-
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
127-
let cfg = CfgExpr::parse(&cfg);
128-
if cfg_options.check(&cfg) == Some(false) {
129-
smallvec![]
130-
} else {
131-
cov_mark::hit!(cfg_attr_active);
132-
133-
attrs.collect()
134-
}
135-
}));
120+
let new_attrs =
121+
self.iter()
122+
.flat_map(|attr| -> SmallVec<[_; 1]> {
123+
let is_cfg_attr =
124+
attr.path.as_ident().map_or(false, |name| *name == crate::name![cfg_attr]);
125+
if !is_cfg_attr {
126+
return smallvec![attr.clone()];
127+
}
136128

137-
RawAttrs { entries: Some(new_attrs) }
129+
let subtree = match attr.token_tree_value() {
130+
Some(it) => it,
131+
_ => return smallvec![attr.clone()],
132+
};
133+
134+
let (cfg, parts) = match parse_cfg_attr_input(subtree) {
135+
Some(it) => it,
136+
None => return smallvec![attr.clone()],
137+
};
138+
let index = attr.id;
139+
let attrs = parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(
140+
|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)),
141+
);
142+
143+
let cfg_options = &crate_graph[krate].cfg_options;
144+
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
145+
let cfg = CfgExpr::parse(&cfg);
146+
if cfg_options.check(&cfg) == Some(false) {
147+
smallvec![]
148+
} else {
149+
cov_mark::hit!(cfg_attr_active);
150+
151+
attrs.collect()
152+
}
153+
})
154+
.collect::<Vec<_>>();
155+
let entries = if new_attrs.is_empty() {
156+
None
157+
} else {
158+
Some(ThinArc::from_header_and_iter((), new_attrs.into_iter()))
159+
};
160+
RawAttrs { entries }
138161
}
139162
}
140163

@@ -179,16 +202,15 @@ pub struct Attr {
179202
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
180203
pub enum AttrInput {
181204
/// `#[attr = "string"]`
182-
// FIXME: This is losing span
183-
Literal(SmolStr),
205+
Literal(tt::Literal),
184206
/// `#[attr(subtree)]`
185207
TokenTree(Box<tt::Subtree>),
186208
}
187209

188210
impl fmt::Display for AttrInput {
189211
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190212
match self {
191-
AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()),
213+
AttrInput::Literal(lit) => write!(f, " = {lit}"),
192214
AttrInput::TokenTree(tt) => tt.fmt(f),
193215
}
194216
}
@@ -208,11 +230,10 @@ impl Attr {
208230
})?);
209231
let span = span_map.span_for_range(range);
210232
let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
211-
let value = match lit.kind() {
212-
ast::LiteralKind::String(string) => string.value()?.into(),
213-
_ => lit.syntax().first_token()?.text().trim_matches('"').into(),
214-
};
215-
Some(Interned::new(AttrInput::Literal(value)))
233+
Some(Interned::new(AttrInput::Literal(tt::Literal {
234+
text: lit.token().text().into(),
235+
span,
236+
})))
216237
} else if let Some(tt) = ast.token_tree() {
217238
let tree = syntax_node_to_token_tree(tt.syntax(), span_map, span);
218239
Some(Interned::new(AttrInput::TokenTree(Box::new(tree))))
@@ -245,9 +266,8 @@ impl Attr {
245266
}
246267
Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. }))) => {
247268
let input = match input.get(1) {
248-
Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text, .. }))) => {
249-
//FIXME the trimming here isn't quite right, raw strings are not handled
250-
Some(Interned::new(AttrInput::Literal(text.trim_matches('"').into())))
269+
Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) => {
270+
Some(Interned::new(AttrInput::Literal(lit.clone())))
251271
}
252272
_ => None,
253273
};
@@ -265,9 +285,14 @@ impl Attr {
265285

266286
impl Attr {
267287
/// #[path = "string"]
268-
pub fn string_value(&self) -> Option<&SmolStr> {
288+
pub fn string_value(&self) -> Option<&str> {
269289
match self.input.as_deref()? {
270-
AttrInput::Literal(it) => Some(it),
290+
AttrInput::Literal(it) => match it.text.strip_prefix('r') {
291+
Some(it) => it.trim_matches('#'),
292+
None => it.text.as_str(),
293+
}
294+
.strip_prefix('"')?
295+
.strip_suffix('"'),
271296
_ => None,
272297
}
273298
}

crates/hir/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,8 +2008,7 @@ impl Function {
20082008
}
20092009
let data = db.function_data(self.id);
20102010

2011-
data.name.to_smol_str() == "main"
2012-
|| data.attrs.export_name().map(core::ops::Deref::deref) == Some("main")
2011+
data.name.to_smol_str() == "main" || data.attrs.export_name() == Some("main")
20132012
}
20142013

20152014
/// Does this function have the ignore attribute?

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ impl CompletionContext<'_> {
540540
/// Whether the given trait is an operator trait or not.
541541
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
542542
match trait_.attrs(self.db).lang() {
543-
Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()),
543+
Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang),
544544
None => false,
545545
}
546546
}

crates/ide-diagnostics/src/tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ fn test_disabled_diagnostics() {
283283

284284
#[test]
285285
fn minicore_smoke_test() {
286+
if test_utils::skip_slow_tests() {
287+
return;
288+
}
289+
286290
fn check(minicore: MiniCore) {
287291
let source = minicore.source_code();
288292
let mut config = DiagnosticsConfig::test_sample();

crates/ide/src/status.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use ide_db::{
1010
debug::{DebugQueryTable, TableEntry},
1111
Query, QueryTable,
1212
},
13-
CrateData, FileId, FileTextQuery, ParseQuery, SourceDatabase, SourceRootId,
13+
CompressedFileTextQuery, CrateData, FileId, ParseQuery, SourceDatabase, SourceRootId,
1414
},
1515
symbol_index::ModuleSymbolsQuery,
1616
};
@@ -38,7 +38,7 @@ use triomphe::Arc;
3838
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
3939
let mut buf = String::new();
4040

41-
format_to!(buf, "{}\n", collect_query(FileTextQuery.in_db(db)));
41+
format_to!(buf, "{}\n", collect_query(CompressedFileTextQuery.in_db(db)));
4242
format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db)));
4343
format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db)));
4444
format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db)));
@@ -160,7 +160,7 @@ impl QueryCollect for ParseMacroExpansionQuery {
160160
type Collector = SyntaxTreeStats<true>;
161161
}
162162

163-
impl QueryCollect for FileTextQuery {
163+
impl QueryCollect for CompressedFileTextQuery {
164164
type Collector = FilesStats;
165165
}
166166

@@ -188,8 +188,8 @@ impl fmt::Display for FilesStats {
188188
}
189189
}
190190

191-
impl StatCollect<FileId, Arc<str>> for FilesStats {
192-
fn collect_entry(&mut self, _: FileId, value: Option<Arc<str>>) {
191+
impl StatCollect<FileId, Arc<[u8]>> for FilesStats {
192+
fn collect_entry(&mut self, _: FileId, value: Option<Arc<[u8]>>) {
193193
self.total += 1;
194194
self.size += value.unwrap().len();
195195
}

0 commit comments

Comments
 (0)