Add HasSession
trait
This commit is contained in:
parent
5ccf5432ab
commit
3779062955
@ -6,7 +6,8 @@
|
||||
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::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 @@ fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
|
||||
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 @@ fn check_source_text(self, cx: &impl LintContext, pred: impl for<'a> FnOnce(&'a
|
||||
/// 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 @@ fn with_source_text_and_range<T>(
|
||||
/// 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 @@ pub fn as_str(&self) -> Option<&str> {
|
||||
}
|
||||
|
||||
/// 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"##
|
||||
|
Loading…
Reference in New Issue
Block a user