charon_lib/ast/
meta_utils.rs

1//! This file groups everything which is linked to implementations about [crate::meta]
2use crate::meta::*;
3use crate::names::{Disambiguator, Name, PathElem};
4use std::borrow::Cow;
5use std::cmp::Ordering;
6use std::iter::Iterator;
7use std::ops::Range;
8
9/// Given a line number within a source file, get the byte of the start of the line. Obviously not
10/// efficient to do many times, but this is used is diagnostic paths only. The line numer is
11/// expected to be 1-based.
12fn line_to_start_byte(source: &str, line_nbr: usize) -> usize {
13    let mut cur_byte = 0;
14    for (i, line) in source.split_inclusive('\n').enumerate() {
15        if line_nbr == i + 1 {
16            break;
17        }
18        cur_byte += line.len();
19    }
20    cur_byte
21}
22
23impl Loc {
24    fn dummy() -> Self {
25        Loc { line: 0, col: 0 }
26    }
27
28    fn min(l0: &Loc, l1: &Loc) -> Loc {
29        match l0.line.cmp(&l1.line) {
30            Ordering::Equal => Loc {
31                line: l0.line,
32                col: std::cmp::min(l0.col, l1.col),
33            },
34            Ordering::Less => *l0,
35            Ordering::Greater => *l1,
36        }
37    }
38
39    fn max(l0: &Loc, l1: &Loc) -> Loc {
40        match l0.line.cmp(&l1.line) {
41            Ordering::Equal => Loc {
42                line: l0.line,
43                col: std::cmp::max(l0.col, l1.col),
44            },
45            Ordering::Greater => *l0,
46            Ordering::Less => *l1,
47        }
48    }
49
50    pub fn to_byte(self, source: &str) -> usize {
51        line_to_start_byte(source, self.line) + self.col
52    }
53}
54
55impl SpanData {
56    pub fn dummy() -> Self {
57        SpanData {
58            file_id: FileId::from_raw(0),
59            beg: Loc::dummy(),
60            end: Loc::dummy(),
61        }
62    }
63
64    /// Value with which we order `SpanDatas`s.
65    fn sort_key(&self) -> impl Ord {
66        (self.file_id, self.beg, self.end)
67    }
68
69    pub fn to_byte_range(self, source: &str) -> Range<usize> {
70        self.beg.to_byte(source)..self.end.to_byte(source)
71    }
72}
73
74/// Manual impls because `SpanData` is not orderable.
75impl PartialOrd for SpanData {
76    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
77        Some(self.cmp(other))
78    }
79}
80impl Ord for SpanData {
81    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
82        self.sort_key().cmp(&other.sort_key())
83    }
84}
85
86impl Span {
87    pub fn dummy() -> Self {
88        Span {
89            data: SpanData::dummy(),
90            generated_from_span: None,
91        }
92    }
93}
94
95/// Combine some span information (useful when we need to compute the
96/// span-information of, say, a sequence).
97pub fn combine_span(m0: &Span, m1: &Span) -> Span {
98    // Merge the spans
99    if m0.data.file_id == m1.data.file_id {
100        let data = SpanData {
101            file_id: m0.data.file_id,
102            beg: Loc::min(&m0.data.beg, &m1.data.beg),
103            end: Loc::max(&m0.data.end, &m1.data.end),
104        };
105
106        // We don't attempt to merge the "generated from" spans: they might
107        // come from different files, and even if they come from the same files
108        // they might come from different macros, etc.
109        Span {
110            data,
111            generated_from_span: None,
112        }
113    } else {
114        // It happens that the spans don't come from the same file. In this
115        // situation, we just return the first span. TODO: improve this.
116        *m0
117    }
118}
119
120/// Combine all the span information in a slice.
121pub fn combine_span_iter<'a, T: Iterator<Item = &'a Span>>(mut ms: T) -> Span {
122    // The iterator should have a next element
123    let mut mc: Span = ms.next().copied().unwrap_or_default();
124    for m in ms {
125        mc = combine_span(&mc, m);
126    }
127
128    mc
129}
130
131impl FileName {
132    pub fn to_string(&self) -> Cow<'_, str> {
133        match self {
134            FileName::Virtual(path_buf) | FileName::Local(path_buf) => path_buf.to_string_lossy(),
135            FileName::NotReal(path) => Cow::Borrowed(path),
136        }
137    }
138}
139
140impl AttrInfo {
141    pub fn dummy_private() -> Self {
142        AttrInfo {
143            public: false,
144            ..Default::default()
145        }
146    }
147
148    pub fn dummy_public() -> Self {
149        AttrInfo {
150            public: true,
151            ..Default::default()
152        }
153    }
154}
155
156impl ItemOpacity {
157    pub fn with_content_visibility(self, contents_are_public: bool) -> Self {
158        use ItemOpacity::*;
159        match self {
160            Invisible => Invisible,
161            Transparent => Transparent,
162            Foreign if contents_are_public => Transparent,
163            Foreign => Opaque,
164            Opaque => Opaque,
165        }
166    }
167
168    pub fn with_private_contents(self) -> Self {
169        self.with_content_visibility(false)
170    }
171}
172
173impl ItemMeta {
174    pub fn renamed_name(&self) -> Name {
175        let mut name = self.name.clone();
176        if let Some(rename) = self.attr_info.rename.clone() {
177            *name.name.last_mut().unwrap() = PathElem::Ident(rename, Disambiguator::new(0));
178        }
179        name
180    }
181}
182
183impl Default for Span {
184    fn default() -> Self {
185        Self::dummy()
186    }
187}