about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2024-07-31 17:46:35 -0400
committerJason Newcomb <jsnewcomb@pm.me>2024-08-08 10:31:45 -0400
commit3779062955fe792c3969abc1c8d4aa13525a1f17 (patch)
tree4b8e80381507b6abed6942b5d36c5c0d58c12c5a
parent5ccf5432ab9848f390941a6cd29b6468ea842c3e (diff)
downloadrust-3779062955fe792c3969abc1c8d4aa13525a1f17.tar.gz
rust-3779062955fe792c3969abc1c8d4aa13525a1f17.zip
Add `HasSession` trait
-rw-r--r--clippy_utils/src/source.rs129
1 files changed, 75 insertions, 54 deletions
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index 496c8f5b553..96dd3c55d37 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -6,7 +6,8 @@ use rustc_ast::{LitKind, StrStyle};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::{EarlyContext, LateContext};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::{original_sp, SourceMap};
 use rustc_span::{
@@ -17,6 +18,30 @@ use std::borrow::Cow;
 use std::fmt;
 use std::ops::Range;
 
+pub trait HasSession {
+    fn sess(&self) -> &Session;
+}
+impl HasSession for Session {
+    fn sess(&self) -> &Session {
+        self
+    }
+}
+impl HasSession for TyCtxt<'_> {
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+}
+impl HasSession for EarlyContext<'_> {
+    fn sess(&self) -> &Session {
+        ::rustc_lint::LintContext::sess(self)
+    }
+}
+impl HasSession for LateContext<'_> {
+    fn sess(&self) -> &Session {
+        self.tcx.sess()
+    }
+}
+
 /// Conversion of a value into the range portion of a `Span`.
 pub trait SpanRange: Sized {
     fn into_range(self) -> Range<BytePos>;
@@ -71,19 +96,19 @@ impl IntoSpan for Range<BytePos> {
 pub trait SpanRangeExt: SpanRange {
     /// 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 LintContext) -> Option<SourceFileRange> {
+    fn get_source_text(self, cx: &impl HasSession) -> Option<SourceFileRange> {
         get_source_text(cx.sess().source_map(), self.into_range())
     }
 
     /// Calls the given function with the source text referenced and returns the value. Returns
     /// `None` if the source text cannot be retrieved.
-    fn with_source_text<T>(self, cx: &impl LintContext, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> {
+    fn with_source_text<T>(self, cx: &impl HasSession, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> {
         with_source_text(cx.sess().source_map(), self.into_range(), f)
     }
 
     /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the
     /// source text cannot be retrieved.
-    fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool {
+    fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool {
         self.with_source_text(cx, pred).unwrap_or(false)
     }
 
@@ -91,7 +116,7 @@ pub trait SpanRangeExt: SpanRange {
     /// and returns the value. Returns `None` if the source text cannot be retrieved.
     fn with_source_text_and_range<T>(
         self,
-        cx: &impl LintContext,
+        cx: &impl HasSession,
         f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T,
     ) -> Option<T> {
         with_source_text_and_range(cx.sess().source_map(), self.into_range(), f)
@@ -104,30 +129,30 @@ pub trait SpanRangeExt: SpanRange {
     /// The new range must reside within the same source file.
     fn map_range(
         self,
-        cx: &impl LintContext,
+        cx: &impl HasSession,
         f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
     ) -> Option<Range<BytePos>> {
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
     /// Extends the range to include all preceding whitespace characters.
-    fn with_leading_whitespace(self, cx: &impl LintContext) -> Range<BytePos> {
+    fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> {
         with_leading_whitespace(cx.sess().source_map(), self.into_range())
     }
 
     /// Trims the leading whitespace from the range.
-    fn trim_start(self, cx: &impl LintContext) -> Range<BytePos> {
+    fn trim_start(self, cx: &impl HasSession) -> Range<BytePos> {
         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 LintContext, dst: &mut impl fmt::Write) -> fmt::Result {
+    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 LintContext) -> Option<String> {
+    fn source_text_to_string(self, cx: &impl HasSession) -> Option<String> {
         self.with_source_text(cx, ToOwned::to_owned)
     }
 }
@@ -227,15 +252,15 @@ impl SourceFileRange {
 }
 
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
-pub fn expr_block<T: LintContext>(
-    cx: &T,
+pub fn expr_block(
+    sess: &impl HasSession,
     expr: &Expr<'_>,
     outer: SyntaxContext,
     default: &str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
 ) -> String {
-    let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app);
+    let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app);
     if !from_macro
         && let ExprKind::Block(block, _) = expr.kind
         && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
@@ -260,13 +285,13 @@ pub fn expr_block<T: LintContext>(
 ///     let x = ();
 /// //  ^^^^^^^^^^
 /// ```
-pub fn first_line_of_span<T: LintContext>(cx: &T, span: Span) -> Span {
-    first_char_in_first_line(cx, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
+pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span {
+    first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
 }
 
-fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePos> {
-    let line_span = line_span(cx, span);
-    snippet_opt(cx, line_span).and_then(|snip| {
+fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option<BytePos> {
+    let line_span = line_span(sess, span);
+    snippet_opt(sess, line_span).and_then(|snip| {
         snip.find(|c: char| !c.is_whitespace())
             .map(|pos| line_span.lo() + BytePos::from_usize(pos))
     })
@@ -281,9 +306,9 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
 ///        let x = ();
 /// // ^^^^^^^^^^^^^^
 /// ```
-fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
+fn line_span(sess: &impl HasSession, span: Span) -> Span {
     let span = original_sp(span, DUMMY_SP);
-    let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
+    let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap();
     let line_start = sf.lines()[line];
     let line_start = sf.absolute_position(line_start);
     span.with_lo(line_start)
@@ -297,13 +322,13 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 ///     let x = ();
 /// //          ^^ -- will return 4
 /// ```
-pub fn indent_of<T: LintContext>(cx: &T, span: Span) -> Option<usize> {
-    snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
+pub fn indent_of(sess: &impl HasSession, span: Span) -> Option<usize> {
+    snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
 }
 
 /// Gets a snippet of the indentation of the line of a span
-pub fn snippet_indent<T: LintContext>(cx: &T, span: Span) -> Option<String> {
-    snippet_opt(cx, line_span(cx, span)).map(|mut s| {
+pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
+    snippet_opt(sess, line_span(sess, span)).map(|mut s| {
         let len = s.len() - s.trim_start().len();
         s.truncate(len);
         s
@@ -315,8 +340,8 @@ pub fn snippet_indent<T: LintContext>(cx: &T, span: Span) -> Option<String> {
 // sources that the user has no control over.
 // For some reason these attributes don't have any expansion info on them, so
 // we have to check it this way until there is a better way.
-pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
-    if let Some(snippet) = snippet_opt(cx, span) {
+pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool {
+    if let Some(snippet) = snippet_opt(sess, span) {
         if snippet.is_empty() {
             return false;
         }
@@ -407,8 +432,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>,
 /// snippet(cx, span1, "..") // -> "value"
 /// snippet(cx, span2, "..") // -> "Vec::new()"
 /// ```
-pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
-    snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
+pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> {
+    snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from)
 }
 
 /// Same as [`snippet`], but it adapts the applicability level by following rules:
@@ -417,13 +442,13 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<
 /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 /// - If the default value is used and the applicability level is `MachineApplicable`, change it to
 ///   `HasPlaceholders`
-pub fn snippet_with_applicability<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_with_applicability<'a>(
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     applicability: &mut Applicability,
 ) -> Cow<'a, str> {
-    snippet_with_applicability_sess(cx.sess(), span, default, applicability)
+    snippet_with_applicability_sess(sess.sess(), span, default, applicability)
 }
 
 fn snippet_with_applicability_sess<'a>(
@@ -435,7 +460,7 @@ fn snippet_with_applicability_sess<'a>(
     if *applicability != Applicability::Unspecified && span.from_expansion() {
         *applicability = Applicability::MaybeIncorrect;
     }
-    snippet_opt_sess(sess, span).map_or_else(
+    snippet_opt(sess, span).map_or_else(
         || {
             if *applicability == Applicability::MachineApplicable {
                 *applicability = Applicability::HasPlaceholders;
@@ -447,12 +472,8 @@ fn snippet_with_applicability_sess<'a>(
 }
 
 /// Converts a span to a code snippet. Returns `None` if not available.
-pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
-    snippet_opt_sess(cx.sess(), span)
-}
-
-fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
-    sess.source_map().span_to_snippet(span).ok()
+pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> {
+    sess.sess().source_map().span_to_snippet(span).ok()
 }
 
 /// Converts a span (from a block) to a code snippet if available, otherwise use default.
@@ -489,41 +510,41 @@ fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
 ///     } // aligned with `if`
 /// ```
 /// Note that the first line of the snippet always has 0 indentation.
-pub fn snippet_block<'a, T: LintContext>(
-    cx: &T,
+pub fn snippet_block<'a>(
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
 ) -> Cow<'a, str> {
-    let snip = snippet(cx, span, default);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let snip = snippet(sess, span, default);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     reindent_multiline(snip, true, indent)
 }
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
 /// `snippet_with_applicability`.
 pub fn snippet_block_with_applicability<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
     applicability: &mut Applicability,
 ) -> Cow<'a, str> {
-    let snip = snippet_with_applicability(cx, span, default, applicability);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let snip = snippet_with_applicability(sess, span, default, applicability);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     reindent_multiline(snip, true, indent)
 }
 
 pub fn snippet_block_with_context<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
 ) -> (Cow<'a, str>, bool) {
-    let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app);
-    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app);
+    let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
     (reindent_multiline(snip, true, indent), from_macro)
 }
 
@@ -537,13 +558,13 @@ pub fn snippet_block_with_context<'a>(
 ///
 /// This will also return whether or not the snippet is a macro call.
 pub fn snippet_with_context<'a>(
-    cx: &impl LintContext,
+    sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
     default: &'a str,
     applicability: &mut Applicability,
 ) -> (Cow<'a, str>, bool) {
-    snippet_with_context_sess(cx.sess(), span, outer, default, applicability)
+    snippet_with_context_sess(sess.sess(), span, outer, default, applicability)
 }
 
 fn snippet_with_context_sess<'a>(
@@ -661,15 +682,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
 /// writeln!(o, "")   ->   writeln!(o, "")
 ///             ^^                   ^^^^
 /// ```
-pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
-    let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
+pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span {
+    let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true);
     extended.with_lo(extended.lo() - BytePos(1))
 }
 
 /// Converts `expr` to a `char` literal if it's a `str` literal containing a single
 /// character (or a single byte with `ascii_only`)
 pub fn str_literal_to_char_literal(
-    cx: &LateContext<'_>,
+    sess: &impl HasSession,
     expr: &Expr<'_>,
     applicability: &mut Applicability,
     ascii_only: bool,
@@ -684,7 +705,7 @@ pub fn str_literal_to_char_literal(
         }
         && len == 1
     {
-        let snip = snippet_with_applicability(cx, expr.span, string, applicability);
+        let snip = snippet_with_applicability(sess, expr.span, string, applicability);
         let ch = if let StrStyle::Raw(nhash) = style {
             let nhash = nhash as usize;
             // for raw string: r##"a"##