Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/item_tree/attrs.rs')
-rw-r--r--crates/hir-def/src/item_tree/attrs.rs59
1 files changed, 50 insertions, 9 deletions
diff --git a/crates/hir-def/src/item_tree/attrs.rs b/crates/hir-def/src/item_tree/attrs.rs
index 5c635a4b38..81a9b28b62 100644
--- a/crates/hir-def/src/item_tree/attrs.rs
+++ b/crates/hir-def/src/item_tree/attrs.rs
@@ -16,9 +16,9 @@ use hir_expand::{
attrs::{Attr, AttrId, AttrInput, Meta, collect_item_tree_attrs},
mod_path::ModPath,
name::Name,
- span_map::SpanMapRef,
};
use intern::{Interned, Symbol, sym};
+use span::Span;
use syntax::{AstNode, T, ast};
use syntax_bridge::DocCommentDesugarMode;
use tt::token_to_literal;
@@ -42,12 +42,15 @@ impl Default for AttrsOrCfg {
}
impl AttrsOrCfg {
- pub(crate) fn lower<'a>(
+ pub(crate) fn lower<'a, S>(
db: &dyn DefDatabase,
owner: &dyn ast::HasAttrs,
cfg_options: &dyn Fn() -> &'a CfgOptions,
- span_map: SpanMapRef<'_>,
- ) -> AttrsOrCfg {
+ span_map: S,
+ ) -> AttrsOrCfg
+ where
+ S: syntax_bridge::SpanMapper<Span> + Copy,
+ {
let mut attrs = Vec::new();
let result =
collect_item_tree_attrs::<Infallible>(owner, cfg_options, |meta, container, _, _| {
@@ -55,17 +58,17 @@ impl AttrsOrCfg {
// tracking.
let (span, path_range, input) = match meta {
Meta::NamedKeyValue { path_range, name: _, value } => {
- let span = span_map.span_for_range(path_range);
+ let span = span_map.span_for(path_range);
let input = value.map(|value| {
Box::new(AttrInput::Literal(token_to_literal(
value.text(),
- span_map.span_for_range(value.text_range()),
+ span_map.span_for(value.text_range()),
)))
});
(span, path_range, input)
}
Meta::TokenTree { path, tt } => {
- let span = span_map.span_for_range(path.range);
+ let span = span_map.span_for(path.range);
let tt = syntax_bridge::syntax_node_to_token_tree(
tt.syntax(),
span_map,
@@ -76,7 +79,7 @@ impl AttrsOrCfg {
(span, path.range, input)
}
Meta::Path { path } => {
- let span = span_map.span_for_range(path.range);
+ let span = span_map.span_for(path.range);
(span, path.range, None)
}
};
@@ -90,7 +93,7 @@ impl AttrsOrCfg {
.filter(|it| it.kind().is_any_identifier());
ModPath::from_tokens(
db,
- &mut |range| span_map.span_for_range(range).ctx,
+ &mut |range| span_map.span_for(range).ctx,
is_abs,
segments,
)
@@ -107,6 +110,44 @@ impl AttrsOrCfg {
None => AttrsOrCfg::Enabled { attrs },
}
}
+
+ // Merges two `AttrsOrCfg`s, assuming `self` is placed before `other` in the source code.
+ // The operation follows these rules:
+ //
+ // - If `self` and `other` are both `AttrsOrCfg::Enabled`, the result is a new
+ // `AttrsOrCfg::Enabled`. It contains the concatenation of `self`'s attributes followed by
+ // `other`'s.
+ // - If `self` is `AttrsOrCfg::Enabled` but `other` is `AttrsOrCfg::CfgDisabled`, the result
+ // is a new `AttrsOrCfg::CfgDisabled`. It contains the concatenation of `self`'s attributes
+ // followed by `other`'s.
+ // - If `self` is `AttrsOrCfg::CfgDisabled`, return `self` as-is.
+ //
+ // The rationale is that attribute collection is sequential and order-sensitive. This operation
+ // preserves those semantics when combining attributes from two different sources.
+ // `AttrsOrCfg::CfgDisabled` marks a point where collection stops due to a false `#![cfg(...)]`
+ // condition. It acts as a "breakpoint": attributes beyond it are not collected. Therefore,
+ // when merging, an `AttrsOrCfg::CfgDisabled` on the left-hand side short-circuits the
+ // operation, while an `AttrsOrCfg::CfgDisabled` on the right-hand side preserves all
+ // attributes collected up to that point.
+ //
+ // Note that this operation is neither commutative nor associative.
+ pub(crate) fn merge(self, other: AttrsOrCfg) -> AttrsOrCfg {
+ match (self, other) {
+ (AttrsOrCfg::Enabled { attrs }, AttrsOrCfg::Enabled { attrs: other_attrs }) => {
+ let mut v = attrs.0.into_vec();
+ v.extend(other_attrs.0);
+ AttrsOrCfg::Enabled { attrs: AttrsOwned(v.into_boxed_slice()) }
+ }
+ (AttrsOrCfg::Enabled { attrs }, AttrsOrCfg::CfgDisabled(mut other)) => {
+ let other_attrs = &mut other.1;
+ let mut v = attrs.0.into_vec();
+ v.extend(std::mem::take(&mut other_attrs.0));
+ other_attrs.0 = v.into_boxed_slice();
+ AttrsOrCfg::CfgDisabled(other)
+ }
+ (this @ AttrsOrCfg::CfgDisabled(_), _) => this,
+ }
+ }
}
#[derive(Debug, PartialEq, Eq)]