From 9afab36ca9aac3ac8a685ead1982b8ad6e782f70 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 9 Aug 2024 09:01:41 -0400 Subject: [PATCH] Rename `get_source_text` to `get_source_range`. Add new `get_source_text` which returns a displayable string-like type. --- clippy_lints/src/matches/single_match.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 4 +- clippy_utils/src/source.rs | 77 ++++++++++++++++-------- 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 24dea03601c..b6930f7b9d1 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -22,7 +22,7 @@ /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - if let Some(ff) = span.get_source_text(cx) + if let Some(ff) = span.get_source_range(cx) && let Some(text) = ff.as_str() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e907e4058e5..760d5bc95f7 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -687,7 +687,7 @@ fn block(&self, block: &Block<'_>) -> Option> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_text(&self.tcx) + && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index f325e4eaf15..b0a668329e9 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1191,9 +1191,9 @@ fn eq_span_tokens( pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range, right: Range, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = left.get_source_text(cx) + if let Some(lsrc) = left.get_source_range(cx) && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = right.get_source_text(cx) + && let Some(rsrc) = right.get_source_range(cx) && let Some(rsrc) = rsrc.as_str() { let pred = |t: &(_, _)| pred(t.0); diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 96dd3c55d37..1be1a9b28b9 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -16,7 +16,7 @@ }; use std::borrow::Cow; use std::fmt; -use std::ops::Range; +use std::ops::{Deref, Range}; pub trait HasSession { fn sess(&self) -> &Session; @@ -94,10 +94,16 @@ fn with_ctxt(self, ctxt: SyntaxContext) -> Span { } pub trait SpanRangeExt: SpanRange { + /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, + /// or the source text is not accessible. + fn get_source_text(self, cx: &impl HasSession) -> Option { + get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) + } + /// Gets the source file, and range in the file, of the given span. Returns `None` if the span /// extends through multiple files, or is malformed. - fn get_source_text(self, cx: &impl HasSession) -> Option { - get_source_text(cx.sess().source_map(), self.into_range()) + fn get_source_range(self, cx: &impl HasSession) -> Option { + get_source_range(cx.sess().source_map(), self.into_range()) } /// Calls the given function with the source text referenced and returns the value. Returns @@ -144,21 +150,49 @@ fn with_leading_whitespace(self, cx: &impl HasSession) -> Range { fn trim_start(self, cx: &impl HasSession) -> Range { trim_start(cx.sess().source_map(), self.into_range()) } - - /// Writes the referenced source text to the given writer. Will return `Err` if the source text - /// could not be retrieved. - fn write_source_text_to(self, cx: &impl HasSession, dst: &mut impl fmt::Write) -> fmt::Result { - write_source_text_to(cx.sess().source_map(), self.into_range(), dst) - } - - /// Extracts the referenced source text as an owned string. - fn source_text_to_string(self, cx: &impl HasSession) -> Option { - self.with_source_text(cx, ToOwned::to_owned) - } } impl SpanRangeExt for T {} -fn get_source_text(sm: &SourceMap, sp: Range) -> Option { +/// Handle to a range of text in a source file. +pub struct SourceText(SourceFileRange); +impl SourceText { + /// Takes ownership of the source file handle if the source text is accessible. + pub fn new(text: SourceFileRange) -> Option { + if text.as_str().is_some() { + Some(Self(text)) + } else { + None + } + } + + /// Gets the source text. + pub fn as_str(&self) -> &str { + self.0.as_str().unwrap() + } + + /// Converts this into an owned string. + pub fn to_owned(&self) -> String { + self.as_str().to_owned() + } +} +impl Deref for SourceText { + type Target = str; + fn deref(&self) -> &Self::Target { + self.as_str() + } +} +impl AsRef for SourceText { + fn as_ref(&self) -> &str { + self.as_str() + } +} +impl fmt::Display for SourceText { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} + +fn get_source_range(sm: &SourceMap, sp: Range) -> Option { let start = sm.lookup_byte_offset(sp.start); let end = sm.lookup_byte_offset(sp.end); if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { @@ -169,7 +203,7 @@ fn get_source_text(sm: &SourceMap, sp: Range) -> Option(sm: &SourceMap, sp: Range, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - if let Some(src) = get_source_text(sm, sp) + if let Some(src) = get_source_range(sm, sp) && let Some(src) = src.as_str() { Some(f(src)) @@ -183,7 +217,7 @@ fn with_source_text_and_range( sp: Range, f: impl for<'a> FnOnce(&'a str, Range) -> T, ) -> Option { - if let Some(src) = get_source_text(sm, sp) + if let Some(src) = get_source_range(sm, sp) && let Some(text) = &src.sf.src { Some(f(text, src.range)) @@ -198,7 +232,7 @@ fn map_range( sp: Range, f: impl for<'a> FnOnce(&'a str, Range) -> Option>, ) -> Option> { - if let Some(src) = get_source_text(sm, sp.clone()) + if let Some(src) = get_source_range(sm, sp.clone()) && let Some(text) = &src.sf.src && let Some(range) = f(text, src.range.clone()) { @@ -232,13 +266,6 @@ fn trim_start(sm: &SourceMap, sp: Range) -> Range { .unwrap_or(sp) } -fn write_source_text_to(sm: &SourceMap, sp: Range, dst: &mut impl fmt::Write) -> fmt::Result { - match with_source_text(sm, sp, |src| dst.write_str(src)) { - Some(x) => x, - None => Err(fmt::Error), - } -} - pub struct SourceFileRange { pub sf: Lrc, pub range: Range,