diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_span/src/source_map.rs | 151 |
1 files changed, 45 insertions, 106 deletions
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 28381157d..f9566eeee 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -23,7 +23,6 @@ use std::{convert::TryFrom, unreachable}; use std::fs; use std::io; -use tracing::debug; #[cfg(test)] mod tests; @@ -336,7 +335,7 @@ impl SourceMap { mut file_local_non_narrow_chars: Vec<NonNarrowChar>, mut file_local_normalized_pos: Vec<NormalizedPos>, original_start_pos: BytePos, - original_end_pos: BytePos, + metadata_index: u32, ) -> Lrc<SourceFile> { let start_pos = self .allocate_address_space(source_len) @@ -381,8 +380,7 @@ impl SourceMap { src_hash, external_src: Lock::new(ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, - original_start_pos, - original_end_pos, + metadata_index, }), start_pos, end_pos, @@ -473,7 +471,7 @@ impl SourceMap { let hi = self.lookup_char_pos(sp.hi()); let offset = self.lookup_char_pos(relative_to.lo()); - if lo.file.name != offset.file.name { + if lo.file.name != offset.file.name || !relative_to.contains(sp) { return self.span_to_embeddable_string(sp); } @@ -722,7 +720,7 @@ impl SourceMap { }) } - /// Extends the given `Span` to just after the next occurrence of `c`. + /// Extends the given `Span` to just before the next occurrence of `c`. pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span { if let Ok(next_source) = self.span_to_next_source(sp) { let next_source = next_source.split(c).next().unwrap_or(""); @@ -855,28 +853,56 @@ impl SourceMap { } /// Returns a new span representing the next character after the end-point of this span. + /// Special cases: + /// - if span is a dummy one, returns the same span + /// - if next_point reached the end of source, return span with lo = hi + /// - respect multi-byte characters pub fn next_point(&self, sp: Span) -> Span { if sp.is_dummy() { return sp; } let start_of_next_point = sp.hi().0; - let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true); - // If the width is 1, then the next span should point to the same `lo` and `hi`. However, - // in the case of a multibyte character, where the width != 1, the next span should + let width = self.find_width_of_character_at_span(sp, true); + if width == 0 { + return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None); + } + // If the width is 1, then the next span should only contain the next char besides current ending. + // However, in the case of a multibyte character, where the width != 1, the next span should // span multiple bytes to include the whole character. let end_of_next_point = - start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point); + start_of_next_point.checked_add(width).unwrap_or(start_of_next_point); - let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point)); + let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point)); Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None) } + /// Returns a new span to check next none-whitespace character or some specified expected character + /// If `expect` is none, the first span of non-whitespace character is returned. + /// If `expect` presented, the first span of the character `expect` is returned + /// Otherwise, the span reached to limit is returned. + pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span { + let mut sp = span; + for _ in 0..limit.unwrap_or(100 as usize) { + sp = self.next_point(sp); + if let Ok(ref snippet) = self.span_to_snippet(sp) { + if expect.map_or(false, |es| snippet == es) { + break; + } + if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) { + break; + } + } + } + sp + } + /// Finds the width of the character, either before or after the end of provided span, /// depending on the `forwards` parameter. fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 { let sp = sp.data(); - if sp.lo == sp.hi { + + if sp.lo == sp.hi && !forwards { debug!("find_width_of_character_at_span: early return empty span"); return 1; } @@ -910,9 +936,9 @@ impl SourceMap { let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize(); debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len); // Ensure indexes are also not malformed. - if start_index > end_index || end_index > source_len { + if start_index > end_index || end_index > source_len - 1 { debug!("find_width_of_character_at_span: source indexes are malformed"); - return 1; + return 0; } let src = local_begin.sf.external_src.borrow(); @@ -983,93 +1009,6 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; - if let Ok(snippet) = self.span_to_snippet(prev_span) { - debug!( - "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", - span, prev_span, snippet - ); - - if snippet.is_empty() { - return None; - }; - - let len = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))) - } else { - None - } - } - - /// Takes the span of a type parameter in a function signature and try to generate a span for - /// the function name (with generics) and a new snippet for this span with the pointed type - /// parameter as a new local type parameter. - /// - /// For instance: - /// ```rust,ignore (pseudo-Rust) - /// // Given span - /// fn my_function(param: T) - /// // ^ Original span - /// - /// // Result - /// fn my_function(param: T) - /// // ^^^^^^^^^^^ Generated span with snippet `my_function<T>` - /// ``` - /// - /// Attention: The method used is very fragile since it essentially duplicates the work of the - /// parser. If you need to use this function or something similar, please consider updating the - /// `SourceMap` functions and this function to something more robust. - pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { - // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature. - if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { - if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name. - let mut offset = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - - // Consume the generics part of the function signature. - let mut bracket_counter = 0; - let mut last_char = None; - for c in snippet[offset..].chars() { - match c { - '<' => bracket_counter += 1, - '>' => bracket_counter -= 1, - '(' => { - if bracket_counter == 0 { - break; - } - } - _ => {} - } - offset += c.len_utf8(); - last_char = Some(c); - } - - // Adjust the suggestion span to encompass the function name with its generics. - let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); - - // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature. - let mut new_snippet = if last_char == Some('>') { - format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) - } else { - format!("{}<", &snippet[..offset]) - }; - new_snippet - .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string())); - new_snippet.push('>'); - - return Some((sugg_span, new_snippet)); - } - } - - None - } pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool { source_file.add_external_src(|| { match source_file.name { @@ -1148,13 +1087,13 @@ impl FilePathMapping { return remap_path_prefix(&self.mapping, path); - #[instrument(level = "debug", skip(mapping))] + #[instrument(level = "debug", skip(mapping), ret)] fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) { // NOTE: We are iterating over the mapping entries from last to first // because entries specified later on the command line should // take precedence. for &(ref from, ref to) in mapping.iter().rev() { - debug!("Trying to apply {:?} => {:?}", from, to); + debug!("Trying to apply {from:?} => {to:?}"); if let Ok(rest) = path.strip_prefix(from) { let remapped = if rest.as_os_str().is_empty() { @@ -1168,15 +1107,15 @@ impl FilePathMapping { } else { to.join(rest) }; - debug!("Match - remapped {:?} => {:?}", path, remapped); + debug!("Match - remapped"); return (remapped, true); } else { - debug!("No match - prefix {:?} does not match {:?}", from, path); + debug!("No match - prefix {from:?} does not match"); } } - debug!("Path {:?} was not remapped", path); + debug!("not remapped"); (path, false) } } |