1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! The source positions and related helper functions
15 //! This API is completely unstable and subject to change.
17 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
18 html_favicon_url
= "https://doc.rust-lang.org/favicon.ico",
19 html_root_url
= "https://doc.rust-lang.org/nightly/")]
22 #![feature(crate_visibility_modifier)]
23 #![feature(custom_attribute)]
25 #![feature(non_exhaustive)]
26 #![feature(optin_builtin_traits)]
27 #![feature(specialization)]
28 #![cfg_attr(not(stage0), feature(stdsimd))]
32 use std
::cmp
::{self, Ordering}
;
34 use std
::hash
::{Hasher, Hash}
;
35 use std
::ops
::{Add, Sub}
;
36 use std
::path
::PathBuf
;
38 use rustc_data_structures
::stable_hasher
::StableHasher
;
39 use rustc_data_structures
::sync
::{Lrc, Lock}
;
42 extern crate rustc_data_structures
;
45 extern crate scoped_tls
;
47 use serialize
::{Encodable, Decodable, Encoder, Decoder}
;
49 extern crate serialize
;
50 extern crate serialize
as rustc_serialize
; // used by deriving
55 extern crate unicode_width
;
59 pub use hygiene
::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, CompilerDesugaringKind}
;
62 pub use span_encoding
::{Span, DUMMY_SP}
;
66 mod analyze_source_file
;
69 symbol_interner
: Lock
<symbol
::Interner
>,
70 span_interner
: Lock
<span_encoding
::SpanInterner
>,
71 hygiene_data
: Lock
<hygiene
::HygieneData
>,
75 pub fn new() -> Globals
{
77 symbol_interner
: Lock
::new(symbol
::Interner
::fresh()),
78 span_interner
: Lock
::new(span_encoding
::SpanInterner
::default()),
79 hygiene_data
: Lock
::new(hygiene
::HygieneData
::new()),
84 scoped_thread_local
!(pub static GLOBALS
: Globals
);
86 /// Differentiates between real files and common virtual files
87 #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)]
90 /// A macro. This includes the full name of the macro, so that there are no clashes.
96 /// Hack in src/libsyntax/parse.rs
100 /// Strings provided as --cfg [cfgspec] stored in a crate_cfg
102 /// Strings provided as crate attributes in the CLI
104 /// Custom sources for explicit parser calls from plugins and drivers
108 impl std
::fmt
::Display
for FileName
{
109 fn fmt(&self, fmt
: &mut std
::fmt
::Formatter
) -> std
::fmt
::Result
{
110 use self::FileName
::*;
112 Real(ref path
) => write
!(fmt
, "{}", path
.display()),
113 Macros(ref name
) => write
!(fmt
, "<{} macros>", name
),
114 QuoteExpansion
=> write
!(fmt
, "<quote expansion>"),
115 MacroExpansion
=> write
!(fmt
, "<macro expansion>"),
116 Anon
=> write
!(fmt
, "<anon>"),
117 ProcMacroSourceCode
=> write
!(fmt
, "<proc-macro source code>"),
118 CfgSpec
=> write
!(fmt
, "cfgspec"),
119 CliCrateAttr
=> write
!(fmt
, "<crate attribute>"),
120 Custom(ref s
) => write
!(fmt
, "<{}>", s
),
125 impl From
<PathBuf
> for FileName
{
126 fn from(p
: PathBuf
) -> Self {
127 assert
!(!p
.to_string_lossy().ends_with('
>'
));
133 pub fn is_real(&self) -> bool
{
134 use self::FileName
::*;
140 ProcMacroSourceCode
|
144 QuoteExpansion
=> false,
148 pub fn is_macros(&self) -> bool
{
149 use self::FileName
::*;
154 ProcMacroSourceCode
|
158 QuoteExpansion
=> false,
164 /// Spans represent a region of code, used for error reporting. Positions in spans
165 /// are *absolute* positions from the beginning of the source_map, not positions
166 /// relative to SourceFiles. Methods on the SourceMap can be used to relate spans back
167 /// to the original source.
168 /// You must be careful if the span crosses more than one file - you will not be
169 /// able to use many of the functions on spans in source_map and you cannot assume
170 /// that the length of the span = hi - lo; there may be space in the BytePos
171 /// range between files.
173 /// `SpanData` is public because `Span` uses a thread-local interner and can't be
174 /// sent to other threads, but some pieces of performance infra run in a separate thread.
175 /// Using `Span` is generally preferred.
176 #[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
177 pub struct SpanData
{
180 /// Information about where the macro came from, if this piece of
181 /// code was created by a macro expansion.
182 pub ctxt
: SyntaxContext
,
187 pub fn with_lo(&self, lo
: BytePos
) -> Span
{
188 Span
::new(lo
, self.hi
, self.ctxt
)
191 pub fn with_hi(&self, hi
: BytePos
) -> Span
{
192 Span
::new(self.lo
, hi
, self.ctxt
)
195 pub fn with_ctxt(&self, ctxt
: SyntaxContext
) -> Span
{
196 Span
::new(self.lo
, self.hi
, ctxt
)
200 // The interner is pointed to by a thread local value which is only set on the main thread
201 // with parallelization is disabled. So we don't allow Span to transfer between threads
202 // to avoid panics and other errors, even though it would be memory safe to do so.
203 #[cfg(not(parallel_queries))]
204 impl !Send
for Span {}
205 #[cfg(not(parallel_queries))]
206 impl !Sync
for Span {}
208 impl PartialOrd
for Span
{
209 fn partial_cmp(&self, rhs
: &Self) -> Option
<Ordering
> {
210 PartialOrd
::partial_cmp(&self.data(), &rhs
.data())
214 fn cmp(&self, rhs
: &Self) -> Ordering
{
215 Ord
::cmp(&self.data(), &rhs
.data())
219 /// A collection of spans. Spans have two orthogonal attributes:
221 /// - they can be *primary spans*. In this case they are the locus of
222 /// the error, and would be rendered with `^^^`.
223 /// - they can have a *label*. In this case, the label is written next
224 /// to the mark in the snippet when we render.
225 #[derive(Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)]
226 pub struct MultiSpan
{
227 primary_spans
: Vec
<Span
>,
228 span_labels
: Vec
<(Span
, String
)>,
233 pub fn lo(self) -> BytePos
{
237 pub fn with_lo(self, lo
: BytePos
) -> Span
{
238 self.data().with_lo(lo
)
241 pub fn hi(self) -> BytePos
{
245 pub fn with_hi(self, hi
: BytePos
) -> Span
{
246 self.data().with_hi(hi
)
249 pub fn ctxt(self) -> SyntaxContext
{
253 pub fn with_ctxt(self, ctxt
: SyntaxContext
) -> Span
{
254 self.data().with_ctxt(ctxt
)
257 /// Returns `true` if this is a dummy span with any hygienic context.
259 pub fn is_dummy(self) -> bool
{
260 let span
= self.data();
261 span
.lo
.0 == 0 && span
.hi
.0 == 0
264 /// Returns a new span representing an empty span at the beginning of this span
266 pub fn shrink_to_lo(self) -> Span
{
267 let span
= self.data();
268 span
.with_hi(span
.lo
)
270 /// Returns a new span representing an empty span at the end of this span
272 pub fn shrink_to_hi(self) -> Span
{
273 let span
= self.data();
274 span
.with_lo(span
.hi
)
277 /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
278 pub fn substitute_dummy(self, other
: Span
) -> Span
{
279 if self.is_dummy() { other }
else { self }
282 /// Return true if `self` fully encloses `other`.
283 pub fn contains(self, other
: Span
) -> bool
{
284 let span
= self.data();
285 let other
= other
.data();
286 span
.lo
<= other
.lo
&& other
.hi
<= span
.hi
289 /// Return true if the spans are equal with regards to the source text.
291 /// Use this instead of `==` when either span could be generated code,
292 /// and you only care that they point to the same bytes of source text.
293 pub fn source_equal(&self, other
: &Span
) -> bool
{
294 let span
= self.data();
295 let other
= other
.data();
296 span
.lo
== other
.lo
&& span
.hi
== other
.hi
299 /// Returns `Some(span)`, where the start is trimmed by the end of `other`
300 pub fn trim_start(self, other
: Span
) -> Option
<Span
> {
301 let span
= self.data();
302 let other
= other
.data();
303 if span
.hi
> other
.hi
{
304 Some(span
.with_lo(cmp
::max(span
.lo
, other
.hi
)))
310 /// Return the source span - this is either the supplied span, or the span for
311 /// the macro callsite that expanded to it.
312 pub fn source_callsite(self) -> Span
{
313 self.ctxt().outer().expn_info().map(|info
| info
.call_site
.source_callsite()).unwrap_or(self)
316 /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
318 pub fn parent(self) -> Option
<Span
> {
319 self.ctxt().outer().expn_info().map(|i
| i
.call_site
)
322 /// Edition of the crate from which this span came.
323 pub fn edition(self) -> edition
::Edition
{
324 self.ctxt().outer().expn_info().map_or_else(|| hygiene
::default_edition(),
325 |einfo
| einfo
.edition
)
329 pub fn rust_2015(&self) -> bool
{
330 self.edition() == edition
::Edition
::Edition2015
334 pub fn rust_2018(&self) -> bool
{
335 self.edition() >= edition
::Edition
::Edition2018
338 /// Return the source callee.
340 /// Returns `None` if the supplied span has no expansion trace,
341 /// else returns the `ExpnInfo` for the macro definition
342 /// corresponding to the source callsite.
343 pub fn source_callee(self) -> Option
<ExpnInfo
> {
344 fn source_callee(info
: ExpnInfo
) -> ExpnInfo
{
345 match info
.call_site
.ctxt().outer().expn_info() {
346 Some(info
) => source_callee(info
),
350 self.ctxt().outer().expn_info().map(source_callee
)
353 /// Check if a span is "internal" to a macro in which #[unstable]
354 /// items can be used (that is, a macro marked with
355 /// `#[allow_internal_unstable]`).
356 pub fn allows_unstable(&self) -> bool
{
357 match self.ctxt().outer().expn_info() {
358 Some(info
) => info
.allow_internal_unstable
,
363 /// Check if this span arises from a compiler desugaring of kind `kind`.
364 pub fn is_compiler_desugaring(&self, kind
: CompilerDesugaringKind
) -> bool
{
365 match self.ctxt().outer().expn_info() {
366 Some(info
) => match info
.format
{
367 ExpnFormat
::CompilerDesugaring(k
) => k
== kind
,
374 /// Return the compiler desugaring that created this span, or None
375 /// if this span is not from a desugaring.
376 pub fn compiler_desugaring_kind(&self) -> Option
<CompilerDesugaringKind
> {
377 match self.ctxt().outer().expn_info() {
378 Some(info
) => match info
.format
{
379 ExpnFormat
::CompilerDesugaring(k
) => Some(k
),
386 /// Check if a span is "internal" to a macro in which `unsafe`
387 /// can be used without triggering the `unsafe_code` lint
388 // (that is, a macro marked with `#[allow_internal_unsafe]`).
389 pub fn allows_unsafe(&self) -> bool
{
390 match self.ctxt().outer().expn_info() {
391 Some(info
) => info
.allow_internal_unsafe
,
396 pub fn macro_backtrace(mut self) -> Vec
<MacroBacktrace
> {
397 let mut prev_span
= DUMMY_SP
;
398 let mut result
= vec
![];
399 while let Some(info
) = self.ctxt().outer().expn_info() {
400 // Don't print recursive invocations
401 if !info
.call_site
.source_equal(&prev_span
) {
402 let (pre
, post
) = match info
.format
{
403 ExpnFormat
::MacroAttribute(..) => ("#[", "]"),
404 ExpnFormat
::MacroBang(..) => ("", "!"),
405 ExpnFormat
::CompilerDesugaring(..) => ("desugaring of `", "`"),
407 result
.push(MacroBacktrace
{
408 call_site
: info
.call_site
,
409 macro_decl_name
: format
!("{}{}{}", pre
, info
.format
.name(), post
),
410 def_site_span
: info
.def_site
,
415 self = info
.call_site
;
420 /// Return a `Span` that would enclose both `self` and `end`.
421 pub fn to(self, end
: Span
) -> Span
{
422 let span_data
= self.data();
423 let end_data
= end
.data();
424 // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
425 // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
426 // have an incomplete span than a completely nonsensical one.
427 if span_data
.ctxt
!= end_data
.ctxt
{
428 if span_data
.ctxt
== SyntaxContext
::empty() {
430 } else if end_data
.ctxt
== SyntaxContext
::empty() {
433 // both span fall within a macro
434 // FIXME(estebank) check if it is the *same* macro
437 cmp
::min(span_data
.lo
, end_data
.lo
),
438 cmp
::max(span_data
.hi
, end_data
.hi
),
439 if span_data
.ctxt
== SyntaxContext
::empty() { end_data.ctxt }
else { span_data.ctxt }
,
443 /// Return a `Span` between the end of `self` to the beginning of `end`.
444 pub fn between(self, end
: Span
) -> Span
{
445 let span
= self.data();
446 let end
= end
.data();
450 if end
.ctxt
== SyntaxContext
::empty() { end.ctxt }
else { span.ctxt }
,
454 /// Return a `Span` between the beginning of `self` to the beginning of `end`.
455 pub fn until(self, end
: Span
) -> Span
{
456 let span
= self.data();
457 let end
= end
.data();
461 if end
.ctxt
== SyntaxContext
::empty() { end.ctxt }
else { span.ctxt }
,
465 pub fn from_inner_byte_pos(self, start
: usize, end
: usize) -> Span
{
466 let span
= self.data();
467 Span
::new(span
.lo
+ BytePos
::from_usize(start
),
468 span
.lo
+ BytePos
::from_usize(end
),
473 pub fn apply_mark(self, mark
: Mark
) -> Span
{
474 let span
= self.data();
475 span
.with_ctxt(span
.ctxt
.apply_mark(mark
))
479 pub fn remove_mark(&mut self) -> Mark
{
480 let mut span
= self.data();
481 let mark
= span
.ctxt
.remove_mark();
482 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
);
487 pub fn adjust(&mut self, expansion
: Mark
) -> Option
<Mark
> {
488 let mut span
= self.data();
489 let mark
= span
.ctxt
.adjust(expansion
);
490 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
);
495 pub fn glob_adjust(&mut self, expansion
: Mark
, glob_ctxt
: SyntaxContext
)
496 -> Option
<Option
<Mark
>> {
497 let mut span
= self.data();
498 let mark
= span
.ctxt
.glob_adjust(expansion
, glob_ctxt
);
499 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
);
504 pub fn reverse_glob_adjust(&mut self, expansion
: Mark
, glob_ctxt
: SyntaxContext
)
505 -> Option
<Option
<Mark
>> {
506 let mut span
= self.data();
507 let mark
= span
.ctxt
.reverse_glob_adjust(expansion
, glob_ctxt
);
508 *self = Span
::new(span
.lo
, span
.hi
, span
.ctxt
);
513 pub fn modern(self) -> Span
{
514 let span
= self.data();
515 span
.with_ctxt(span
.ctxt
.modern())
519 pub fn modern_and_legacy(self) -> Span
{
520 let span
= self.data();
521 span
.with_ctxt(span
.ctxt
.modern_and_legacy())
525 #[derive(Clone, Debug)]
526 pub struct SpanLabel
{
527 /// The span we are going to include in the final snippet.
530 /// Is this a primary span? This is the "locus" of the message,
531 /// and is indicated with a `^^^^` underline, versus `----`.
532 pub is_primary
: bool
,
534 /// What label should we attach to this span (if any)?
535 pub label
: Option
<String
>,
538 impl Default
for Span
{
539 fn default() -> Self {
544 impl serialize
::UseSpecializedEncodable
for Span
{
545 fn default_encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
546 let span
= self.data();
547 s
.emit_struct("Span", 2, |s
| {
548 s
.emit_struct_field("lo", 0, |s
| {
552 s
.emit_struct_field("hi", 1, |s
| {
559 impl serialize
::UseSpecializedDecodable
for Span
{
560 fn default_decode
<D
: Decoder
>(d
: &mut D
) -> Result
<Span
, D
::Error
> {
561 d
.read_struct("Span", 2, |d
| {
562 let lo
= d
.read_struct_field("lo", 0, Decodable
::decode
)?
;
563 let hi
= d
.read_struct_field("hi", 1, Decodable
::decode
)?
;
564 Ok(Span
::new(lo
, hi
, NO_EXPANSION
))
569 fn default_span_debug(span
: Span
, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
570 f
.debug_struct("Span")
571 .field("lo", &span
.lo())
572 .field("hi", &span
.hi())
573 .field("ctxt", &span
.ctxt())
577 impl fmt
::Debug
for Span
{
578 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
579 SPAN_DEBUG
.with(|span_debug
| span_debug
.get()(*self, f
))
583 impl fmt
::Debug
for SpanData
{
584 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
585 SPAN_DEBUG
.with(|span_debug
| span_debug
.get()(Span
::new(self.lo
, self.hi
, self.ctxt
), f
))
591 pub fn new() -> MultiSpan
{
593 primary_spans
: vec
![],
598 pub fn from_span(primary_span
: Span
) -> MultiSpan
{
600 primary_spans
: vec
![primary_span
],
605 pub fn from_spans(vec
: Vec
<Span
>) -> MultiSpan
{
612 pub fn push_span_label(&mut self, span
: Span
, label
: String
) {
613 self.span_labels
.push((span
, label
));
616 /// Selects the first primary span (if any)
617 pub fn primary_span(&self) -> Option
<Span
> {
618 self.primary_spans
.first().cloned()
621 /// Returns all primary spans.
622 pub fn primary_spans(&self) -> &[Span
] {
626 /// Returns `true` if this contains only a dummy primary span with any hygienic context.
627 pub fn is_dummy(&self) -> bool
{
628 let mut is_dummy
= true;
629 for span
in &self.primary_spans
{
630 if !span
.is_dummy() {
637 /// Replaces all occurrences of one Span with another. Used to move Spans in areas that don't
638 /// display well (like std macros). Returns true if replacements occurred.
639 pub fn replace(&mut self, before
: Span
, after
: Span
) -> bool
{
640 let mut replacements_occurred
= false;
641 for primary_span
in &mut self.primary_spans
{
642 if *primary_span
== before
{
643 *primary_span
= after
;
644 replacements_occurred
= true;
647 for span_label
in &mut self.span_labels
{
648 if span_label
.0 == before
{
649 span_label
.0 = after
;
650 replacements_occurred
= true;
653 replacements_occurred
656 /// Returns the strings to highlight. We always ensure that there
657 /// is an entry for each of the primary spans -- for each primary
658 /// span P, if there is at least one label with span P, we return
659 /// those labels (marked as primary). But otherwise we return
660 /// `SpanLabel` instances with empty labels.
661 pub fn span_labels(&self) -> Vec
<SpanLabel
> {
662 let is_primary
= |span
| self.primary_spans
.contains(&span
);
664 let mut span_labels
= self.span_labels
.iter().map(|&(span
, ref label
)|
667 is_primary
: is_primary(span
),
668 label
: Some(label
.clone())
670 ).collect
::<Vec
<_
>>();
672 for &span
in &self.primary_spans
{
673 if !span_labels
.iter().any(|sl
| sl
.span
== span
) {
674 span_labels
.push(SpanLabel
{
686 impl From
<Span
> for MultiSpan
{
687 fn from(span
: Span
) -> MultiSpan
{
688 MultiSpan
::from_span(span
)
692 impl From
<Vec
<Span
>> for MultiSpan
{
693 fn from(spans
: Vec
<Span
>) -> MultiSpan
{
694 MultiSpan
::from_spans(spans
)
698 pub const NO_EXPANSION
: SyntaxContext
= SyntaxContext
::empty();
700 /// Identifies an offset of a multi-byte character in a SourceFile
701 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
702 pub struct MultiByteChar
{
703 /// The absolute offset of the character in the SourceMap
705 /// The number of bytes, >=2
709 /// Identifies an offset of a non-narrow character in a SourceFile
710 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
711 pub enum NonNarrowChar
{
712 /// Represents a zero-width character
714 /// Represents a wide (fullwidth) character
716 /// Represents a tab character, represented visually with a width of 4 characters
721 fn new(pos
: BytePos
, width
: usize) -> Self {
723 0 => NonNarrowChar
::ZeroWidth(pos
),
724 2 => NonNarrowChar
::Wide(pos
),
725 4 => NonNarrowChar
::Tab(pos
),
726 _
=> panic
!("width {} given for non-narrow character", width
),
730 /// Returns the absolute offset of the character in the SourceMap
731 pub fn pos(&self) -> BytePos
{
733 NonNarrowChar
::ZeroWidth(p
) |
734 NonNarrowChar
::Wide(p
) |
735 NonNarrowChar
::Tab(p
) => p
,
739 /// Returns the width of the character, 0 (zero-width) or 2 (wide)
740 pub fn width(&self) -> usize {
742 NonNarrowChar
::ZeroWidth(_
) => 0,
743 NonNarrowChar
::Wide(_
) => 2,
744 NonNarrowChar
::Tab(_
) => 4,
749 impl Add
<BytePos
> for NonNarrowChar
{
752 fn add(self, rhs
: BytePos
) -> Self {
754 NonNarrowChar
::ZeroWidth(pos
) => NonNarrowChar
::ZeroWidth(pos
+ rhs
),
755 NonNarrowChar
::Wide(pos
) => NonNarrowChar
::Wide(pos
+ rhs
),
756 NonNarrowChar
::Tab(pos
) => NonNarrowChar
::Tab(pos
+ rhs
),
761 impl Sub
<BytePos
> for NonNarrowChar
{
764 fn sub(self, rhs
: BytePos
) -> Self {
766 NonNarrowChar
::ZeroWidth(pos
) => NonNarrowChar
::ZeroWidth(pos
- rhs
),
767 NonNarrowChar
::Wide(pos
) => NonNarrowChar
::Wide(pos
- rhs
),
768 NonNarrowChar
::Tab(pos
) => NonNarrowChar
::Tab(pos
- rhs
),
773 /// The state of the lazy external source loading mechanism of a SourceFile.
774 #[derive(PartialEq, Eq, Clone)]
775 pub enum ExternalSource
{
776 /// The external source has been loaded already.
778 /// No attempt has been made to load the external source.
780 /// A failed attempt has been made to load the external source.
782 /// No external source has to be loaded, since the SourceFile represents a local crate.
786 impl ExternalSource
{
787 pub fn is_absent(&self) -> bool
{
789 ExternalSource
::Present(_
) => false,
794 pub fn get_source(&self) -> Option
<&str> {
796 ExternalSource
::Present(ref src
) => Some(src
),
802 /// A single source in the SourceMap.
804 pub struct SourceFile
{
805 /// The name of the file that the source came from, source that doesn't
806 /// originate from files has names between angle brackets by convention,
809 /// True if the `name` field above has been modified by --remap-path-prefix
810 pub name_was_remapped
: bool
,
811 /// The unmapped path of the file that the source came from.
812 /// Set to `None` if the SourceFile was imported from an external crate.
813 pub unmapped_path
: Option
<FileName
>,
814 /// Indicates which crate this SourceFile was imported from.
815 pub crate_of_origin
: u32,
816 /// The complete source code
817 pub src
: Option
<Lrc
<String
>>,
818 /// The source code's hash
820 /// The external source code (used for external crates, which will have a `None`
821 /// value as `self.src`.
822 pub external_src
: Lock
<ExternalSource
>,
823 /// The start position of this source in the SourceMap
824 pub start_pos
: BytePos
,
825 /// The end position of this source in the SourceMap
826 pub end_pos
: BytePos
,
827 /// Locations of lines beginnings in the source code
828 pub lines
: Vec
<BytePos
>,
829 /// Locations of multi-byte characters in the source code
830 pub multibyte_chars
: Vec
<MultiByteChar
>,
831 /// Width of characters that are not narrow in the source code
832 pub non_narrow_chars
: Vec
<NonNarrowChar
>,
833 /// A hash of the filename, used for speeding up the incr. comp. hashing.
837 impl Encodable
for SourceFile
{
838 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
839 s
.emit_struct("SourceFile", 8, |s
| {
840 s
.emit_struct_field("name", 0, |s
| self.name
.encode(s
))?
;
841 s
.emit_struct_field("name_was_remapped", 1, |s
| self.name_was_remapped
.encode(s
))?
;
842 s
.emit_struct_field("src_hash", 2, |s
| self.src_hash
.encode(s
))?
;
843 s
.emit_struct_field("start_pos", 4, |s
| self.start_pos
.encode(s
))?
;
844 s
.emit_struct_field("end_pos", 5, |s
| self.end_pos
.encode(s
))?
;
845 s
.emit_struct_field("lines", 6, |s
| {
846 let lines
= &self.lines
[..];
848 s
.emit_u32(lines
.len() as u32)?
;
850 if !lines
.is_empty() {
851 // In order to preserve some space, we exploit the fact that
852 // the lines list is sorted and individual lines are
853 // probably not that long. Because of that we can store lines
854 // as a difference list, using as little space as possible
855 // for the differences.
856 let max_line_length
= if lines
.len() == 1 {
860 .map(|w
| w
[1] - w
[0])
861 .map(|bp
| bp
.to_usize())
866 let bytes_per_diff
: u8 = match max_line_length
{
868 0x100 ..= 0xFFFF => 2,
872 // Encode the number of bytes used per diff.
873 bytes_per_diff
.encode(s
)?
;
875 // Encode the first element.
878 let diff_iter
= (&lines
[..]).windows(2)
879 .map(|w
| (w
[1] - w
[0]));
881 match bytes_per_diff
{
882 1 => for diff
in diff_iter { (diff.0 as u8).encode(s)? }
,
883 2 => for diff
in diff_iter { (diff.0 as u16).encode(s)? }
,
884 4 => for diff
in diff_iter { diff.0.encode(s)? }
,
891 s
.emit_struct_field("multibyte_chars", 7, |s
| {
892 self.multibyte_chars
.encode(s
)
894 s
.emit_struct_field("non_narrow_chars", 8, |s
| {
895 self.non_narrow_chars
.encode(s
)
897 s
.emit_struct_field("name_hash", 9, |s
| {
898 self.name_hash
.encode(s
)
904 impl Decodable
for SourceFile
{
905 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<SourceFile
, D
::Error
> {
907 d
.read_struct("SourceFile", 8, |d
| {
908 let name
: FileName
= d
.read_struct_field("name", 0, |d
| Decodable
::decode(d
))?
;
909 let name_was_remapped
: bool
=
910 d
.read_struct_field("name_was_remapped", 1, |d
| Decodable
::decode(d
))?
;
912 d
.read_struct_field("src_hash", 2, |d
| Decodable
::decode(d
))?
;
913 let start_pos
: BytePos
=
914 d
.read_struct_field("start_pos", 4, |d
| Decodable
::decode(d
))?
;
915 let end_pos
: BytePos
= d
.read_struct_field("end_pos", 5, |d
| Decodable
::decode(d
))?
;
916 let lines
: Vec
<BytePos
> = d
.read_struct_field("lines", 6, |d
| {
917 let num_lines
: u32 = Decodable
::decode(d
)?
;
918 let mut lines
= Vec
::with_capacity(num_lines
as usize);
921 // Read the number of bytes used per diff.
922 let bytes_per_diff
: u8 = Decodable
::decode(d
)?
;
924 // Read the first element.
925 let mut line_start
: BytePos
= Decodable
::decode(d
)?
;
926 lines
.push(line_start
);
928 for _
in 1..num_lines
{
929 let diff
= match bytes_per_diff
{
930 1 => d
.read_u8()?
as u32,
931 2 => d
.read_u16()?
as u32,
936 line_start
= line_start
+ BytePos(diff
);
938 lines
.push(line_start
);
944 let multibyte_chars
: Vec
<MultiByteChar
> =
945 d
.read_struct_field("multibyte_chars", 7, |d
| Decodable
::decode(d
))?
;
946 let non_narrow_chars
: Vec
<NonNarrowChar
> =
947 d
.read_struct_field("non_narrow_chars", 8, |d
| Decodable
::decode(d
))?
;
948 let name_hash
: u128
=
949 d
.read_struct_field("name_hash", 9, |d
| Decodable
::decode(d
))?
;
954 // `crate_of_origin` has to be set by the importer.
955 // This value matches up with rustc::hir::def_id::INVALID_CRATE.
956 // That constant is not available here unfortunately :(
957 crate_of_origin
: ::std
::u32::MAX
- 1,
962 external_src
: Lock
::new(ExternalSource
::AbsentOk
),
972 impl fmt
::Debug
for SourceFile
{
973 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
974 write
!(fmt
, "SourceFile({})", self.name
)
979 pub fn new(name
: FileName
,
980 name_was_remapped
: bool
,
981 unmapped_path
: FileName
,
983 start_pos
: BytePos
) -> SourceFile
{
984 remove_bom(&mut src
);
987 let mut hasher
: StableHasher
<u128
> = StableHasher
::new();
988 hasher
.write(src
.as_bytes());
992 let mut hasher
: StableHasher
<u128
> = StableHasher
::new();
993 name
.hash(&mut hasher
);
996 let end_pos
= start_pos
.to_usize() + src
.len();
998 let (lines
, multibyte_chars
, non_narrow_chars
) =
999 analyze_source_file
::analyze_source_file(&src
[..], start_pos
);
1004 unmapped_path
: Some(unmapped_path
),
1006 src
: Some(Lrc
::new(src
)),
1008 external_src
: Lock
::new(ExternalSource
::Unneeded
),
1010 end_pos
: Pos
::from_usize(end_pos
),
1018 /// Return the BytePos of the beginning of the current line.
1019 pub fn line_begin_pos(&self, pos
: BytePos
) -> BytePos
{
1020 let line_index
= self.lookup_line(pos
).unwrap();
1021 self.lines
[line_index
]
1024 /// Add externally loaded source.
1025 /// If the hash of the input doesn't match or no input is supplied via None,
1026 /// it is interpreted as an error and the corresponding enum variant is set.
1027 /// The return value signifies whether some kind of source is present.
1028 pub fn add_external_src
<F
>(&self, get_src
: F
) -> bool
1029 where F
: FnOnce() -> Option
<String
>
1031 if *self.external_src
.borrow() == ExternalSource
::AbsentOk
{
1032 let src
= get_src();
1033 let mut external_src
= self.external_src
.borrow_mut();
1034 // Check that no-one else have provided the source while we were getting it
1035 if *external_src
== ExternalSource
::AbsentOk
{
1036 if let Some(src
) = src
{
1037 let mut hasher
: StableHasher
<u128
> = StableHasher
::new();
1038 hasher
.write(src
.as_bytes());
1040 if hasher
.finish() == self.src_hash
{
1041 *external_src
= ExternalSource
::Present(src
);
1045 *external_src
= ExternalSource
::AbsentErr
;
1050 self.src
.is_some() || external_src
.get_source().is_some()
1053 self.src
.is_some() || self.external_src
.borrow().get_source().is_some()
1057 /// Get a line from the list of pre-computed line-beginnings.
1058 /// The line number here is 0-based.
1059 pub fn get_line(&self, line_number
: usize) -> Option
<Cow
<str>> {
1060 fn get_until_newline(src
: &str, begin
: usize) -> &str {
1061 // We can't use `lines.get(line_number+1)` because we might
1062 // be parsing when we call this function and thus the current
1063 // line is the last one we have line info for.
1064 let slice
= &src
[begin
..];
1065 match slice
.find('
\n'
) {
1066 Some(e
) => &slice
[..e
],
1072 let line
= if let Some(line
) = self.lines
.get(line_number
) {
1077 let begin
: BytePos
= *line
- self.start_pos
;
1081 if let Some(ref src
) = self.src
{
1082 Some(Cow
::from(get_until_newline(src
, begin
)))
1083 } else if let Some(src
) = self.external_src
.borrow().get_source() {
1084 Some(Cow
::Owned(String
::from(get_until_newline(src
, begin
))))
1090 pub fn is_real_file(&self) -> bool
{
1094 pub fn is_imported(&self) -> bool
{
1098 pub fn byte_length(&self) -> u32 {
1099 self.end_pos
.0 - self.start_pos
.0
1101 pub fn count_lines(&self) -> usize {
1105 /// Find the line containing the given position. The return value is the
1106 /// index into the `lines` array of this SourceFile, not the 1-based line
1107 /// number. If the source_file is empty or the position is located before the
1108 /// first line, None is returned.
1109 pub fn lookup_line(&self, pos
: BytePos
) -> Option
<usize> {
1110 if self.lines
.len() == 0 {
1114 let line_index
= lookup_line(&self.lines
[..], pos
);
1115 assert
!(line_index
< self.lines
.len() as isize);
1116 if line_index
>= 0 {
1117 Some(line_index
as usize)
1123 pub fn line_bounds(&self, line_index
: usize) -> (BytePos
, BytePos
) {
1124 if self.start_pos
== self.end_pos
{
1125 return (self.start_pos
, self.end_pos
);
1128 assert
!(line_index
< self.lines
.len());
1129 if line_index
== (self.lines
.len() - 1) {
1130 (self.lines
[line_index
], self.end_pos
)
1132 (self.lines
[line_index
], self.lines
[line_index
+ 1])
1137 pub fn contains(&self, byte_pos
: BytePos
) -> bool
{
1138 byte_pos
>= self.start_pos
&& byte_pos
<= self.end_pos
1142 /// Remove utf-8 BOM if any.
1143 fn remove_bom(src
: &mut String
) {
1144 if src
.starts_with("\u{feff}") {
1149 // _____________________________________________________________________________
1150 // Pos, BytePos, CharPos
1154 fn from_usize(n
: usize) -> Self;
1155 fn to_usize(&self) -> usize;
1156 fn from_u32(n
: u32) -> Self;
1157 fn to_u32(&self) -> u32;
1160 /// A byte offset. Keep this small (currently 32-bits), as AST contains
1162 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1163 pub struct BytePos(pub u32);
1165 /// A character offset. Because of multibyte utf8 characters, a byte offset
1166 /// is not equivalent to a character offset. The SourceMap will convert BytePos
1167 /// values to CharPos values as necessary.
1168 #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1169 pub struct CharPos(pub usize);
1171 // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
1172 // have been unsuccessful
1174 impl Pos
for BytePos
{
1176 fn from_usize(n
: usize) -> BytePos { BytePos(n as u32) }
1179 fn to_usize(&self) -> usize { self.0 as usize }
1182 fn from_u32(n
: u32) -> BytePos { BytePos(n) }
1185 fn to_u32(&self) -> u32 { self.0 }
1188 impl Add
for BytePos
{
1189 type Output
= BytePos
;
1192 fn add(self, rhs
: BytePos
) -> BytePos
{
1193 BytePos((self.to_usize() + rhs
.to_usize()) as u32)
1197 impl Sub
for BytePos
{
1198 type Output
= BytePos
;
1201 fn sub(self, rhs
: BytePos
) -> BytePos
{
1202 BytePos((self.to_usize() - rhs
.to_usize()) as u32)
1206 impl Encodable
for BytePos
{
1207 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
1212 impl Decodable
for BytePos
{
1213 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<BytePos
, D
::Error
> {
1214 Ok(BytePos(d
.read_u32()?
))
1218 impl Pos
for CharPos
{
1220 fn from_usize(n
: usize) -> CharPos { CharPos(n) }
1223 fn to_usize(&self) -> usize { self.0 }
1226 fn from_u32(n
: u32) -> CharPos { CharPos(n as usize) }
1229 fn to_u32(&self) -> u32 { self.0 as u32}
1232 impl Add
for CharPos
{
1233 type Output
= CharPos
;
1236 fn add(self, rhs
: CharPos
) -> CharPos
{
1237 CharPos(self.to_usize() + rhs
.to_usize())
1241 impl Sub
for CharPos
{
1242 type Output
= CharPos
;
1245 fn sub(self, rhs
: CharPos
) -> CharPos
{
1246 CharPos(self.to_usize() - rhs
.to_usize())
1250 // _____________________________________________________________________________
1251 // Loc, LocWithOpt, SourceFileAndLine, SourceFileAndBytePos
1254 /// A source code location used for error reporting
1255 #[derive(Debug, Clone)]
1257 /// Information about the original source
1258 pub file
: Lrc
<SourceFile
>,
1259 /// The (1-based) line number
1261 /// The (0-based) column offset
1263 /// The (0-based) column offset when displayed
1264 pub col_display
: usize,
1267 /// A source code location used as the result of lookup_char_pos_adj
1268 // Actually, *none* of the clients use the filename *or* file field;
1269 // perhaps they should just be removed.
1271 pub struct LocWithOpt
{
1272 pub filename
: FileName
,
1275 pub file
: Option
<Lrc
<SourceFile
>>,
1278 // used to be structural records. Better names, anyone?
1280 pub struct SourceFileAndLine { pub sf: Lrc<SourceFile>, pub line: usize }
1282 pub struct SourceFileAndBytePos { pub sf: Lrc<SourceFile>, pub pos: BytePos }
1284 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1285 pub struct LineInfo
{
1286 /// Index of line, starting from 0.
1287 pub line_index
: usize,
1289 /// Column in line where span begins, starting from 0.
1290 pub start_col
: CharPos
,
1292 /// Column in line where span ends, starting from 0, exclusive.
1293 pub end_col
: CharPos
,
1296 pub struct FileLines
{
1297 pub file
: Lrc
<SourceFile
>,
1298 pub lines
: Vec
<LineInfo
>
1301 thread_local
!(pub static SPAN_DEBUG
: Cell
<fn(Span
, &mut fmt
::Formatter
) -> fmt
::Result
> =
1302 Cell
::new(default_span_debug
));
1305 pub struct MacroBacktrace
{
1306 /// span where macro was applied to generate this code
1307 pub call_site
: Span
,
1309 /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
1310 pub macro_decl_name
: String
,
1312 /// span where macro was defined (if known)
1313 pub def_site_span
: Option
<Span
>,
1316 // _____________________________________________________________________________
1317 // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
1320 pub type FileLinesResult
= Result
<FileLines
, SpanLinesError
>;
1322 #[derive(Clone, PartialEq, Eq, Debug)]
1323 pub enum SpanLinesError
{
1324 IllFormedSpan(Span
),
1325 DistinctSources(DistinctSources
),
1328 #[derive(Clone, PartialEq, Eq, Debug)]
1329 pub enum SpanSnippetError
{
1330 IllFormedSpan(Span
),
1331 DistinctSources(DistinctSources
),
1332 MalformedForSourcemap(MalformedSourceMapPositions
),
1333 SourceNotAvailable { filename: FileName }
1336 #[derive(Clone, PartialEq, Eq, Debug)]
1337 pub struct DistinctSources
{
1338 pub begin
: (FileName
, BytePos
),
1339 pub end
: (FileName
, BytePos
)
1342 #[derive(Clone, PartialEq, Eq, Debug)]
1343 pub struct MalformedSourceMapPositions
{
1345 pub source_len
: usize,
1346 pub begin_pos
: BytePos
,
1347 pub end_pos
: BytePos
1350 // Given a slice of line start positions and a position, returns the index of
1351 // the line the position is on. Returns -1 if the position is located before
1353 fn lookup_line(lines
: &[BytePos
], pos
: BytePos
) -> isize {
1354 match lines
.binary_search(&pos
) {
1355 Ok(line
) => line
as isize,
1356 Err(line
) => line
as isize - 1
1362 use super::{lookup_line, BytePos}
;
1365 fn test_lookup_line() {
1367 let lines
= &[BytePos(3), BytePos(17), BytePos(28)];
1369 assert_eq
!(lookup_line(lines
, BytePos(0)), -1);
1370 assert_eq
!(lookup_line(lines
, BytePos(3)), 0);
1371 assert_eq
!(lookup_line(lines
, BytePos(4)), 0);
1373 assert_eq
!(lookup_line(lines
, BytePos(16)), 0);
1374 assert_eq
!(lookup_line(lines
, BytePos(17)), 1);
1375 assert_eq
!(lookup_line(lines
, BytePos(18)), 1);
1377 assert_eq
!(lookup_line(lines
, BytePos(28)), 2);
1378 assert_eq
!(lookup_line(lines
, BytePos(29)), 2);