::with_trailing_whitespace(self.into_file_range(scx), scx)
+ }
+
+ // Extends the range to include the immediately preceding pattern. Returns `None` if the pattern
+ // does not immediately precede the range, or if the range cannot index the file's text.
+ #[inline]
+ #[must_use]
+ fn with_leading_match(self, scx: &SpanEditCx<'_>, pat: P) -> Option
+ where
+ P: Pattern,
+ for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
{
- Some(f(src))
- } else {
- None
+ ::with_leading_match(self.into_file_range(scx), scx, pat)
+ }
+
+ // Extends the range to include the immediately proceeding pattern. Returns `None` if the pattern
+ // does not immediately proceed the range, or if the range cannot index the file's text.
+ #[inline]
+ #[must_use]
+ fn with_trailing_match(self, scx: &SpanEditCx<'_>, pat: impl Pattern) -> Option {
+ ::with_trailing_match(self.into_file_range(scx), scx, pat)
}
}
+impl FileRangeExt for FileRange {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn get_range_between(self, scx: &SpanEditCx<'_>, sp: impl SpanLike) -> Option {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn f(self_: FileRange, scx: &SpanEditCx<'_>, sp: SpanData) -> Option {
+ debug_assert_eq!(scx.ctxt, sp.ctxt);
+ let file = scx.file();
+ let other = RelativeBytePos(sp.lo.0.wrapping_sub(file.start_pos.0))
+ ..RelativeBytePos(sp.hi.0.wrapping_sub(file.start_pos.0));
+ scx.dbg_check_range(None, other.clone());
+ if self_.end.0 <= other.start.0 {
+ Some(self_.end..other.start)
+ } else if self_.start.0 >= other.end.0 {
+ Some(other.end..self_.start)
+ } else {
+ None
+ }
+ }
+ f(self, scx, sp.data())
+ }
-fn with_source_text_and_range(
- sm: &SourceMap,
- sp: Range,
- f: impl for<'a> FnOnce(&'a str, Range) -> T,
-) -> Option {
- if let Some(src) = get_source_range(sm, sp)
- && let Some(text) = &src.sf.src
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn extend_start_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option {
+ debug_assert_eq!(scx.ctxt, pos.ctxt);
+ let file = scx.file();
+ let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0));
+ scx.dbg_check_range(None, pos..pos);
+ (pos <= self.start).then_some(pos..self.end)
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn extend_end_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option {
+ debug_assert_eq!(scx.ctxt, pos.ctxt);
+ let file = scx.file();
+ let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0));
+ scx.dbg_check_range(None, pos..pos);
+ (pos >= self.end).then_some(self.start..pos)
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn shrink_start_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option {
+ debug_assert_eq!(scx.ctxt, pos.ctxt);
+ let file = scx.file();
+ let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0));
+ scx.dbg_check_range(None, pos..pos);
+ (self.start <= pos && pos <= self.end).then_some(pos..self.end)
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn shrink_end_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option {
+ debug_assert_eq!(scx.ctxt, pos.ctxt);
+ let file = scx.file();
+ let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0));
+ scx.dbg_check_range(None, pos..pos);
+ (self.start <= pos && pos <= self.end).then_some(self.start..pos)
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ #[allow(clippy::manual_map, reason = "track_caller doesn't work through `map`")]
+ fn map_range_text<'cx, T: IntoSubRanges>(
+ self,
+ scx: &'cx SpanEditCx<'_>,
+ f: impl FnOnce(&'cx str) -> Option,
+ ) -> Option {
+ let file = scx.text.as_str();
+ match file.get(self.start.to_usize()..self.end.to_usize()).and_then(f) {
+ Some(s) => Some(s.into_sub_ranges(file)),
+ None => None,
+ }
+ }
+
+ fn with_leading_whitespace(self, scx: &SpanEditCx<'_>) -> Option {
+ let file = scx.file();
+ let text = scx.file_text();
+ let lines: &[RelativeBytePos] = file.lines();
+ let text_before = text.get(..self.start.to_usize())?.trim_end();
+
+ // Start with the line after the extended range starts.
+ // Note `lines` either starts with zero or is empty.
+ let post_search_line = lines.partition_point(|&pos| pos.to_usize() <= text_before.len());
+ // If this is `None` we're still on the final line.
+ if let Some(&search_line_end) = lines.get(post_search_line)
+ // Did we extend over a line boundary?
+ && search_line_end <= self.start
+ // `lines.get` shouldn't ever fail, but `0` always works as a start position.
+ && let search_start = lines.get(post_search_line - 1).map_or(0, |&x| x.to_usize())
+ && ends_with_line_comment_or_broken(&text_before[search_start..])
+ // We extended into a comment line, check if there's any non-whitespace that would be moved into it.
+ && let next_line = lines.partition_point(|&pos| pos < self.end)
+ && let next_start = lines.get(next_line).map_or(file.source_len, |&x| x)
+ && !text.get(self.end.to_usize()..next_start.to_usize())?.trim_start().is_empty()
+ {
+ // A non-whitespace character would be moved into a comment. Do not change the range.
+ Some(self)
+ } else {
+ Some(RelativeBytePos::from_usize(text_before.len())..self.end)
+ }
+ }
+
+ fn with_trailing_whitespace(self, scx: &SpanEditCx<'_>) -> Option {
+ scx.get_text(self.end..)
+ .map(|s| self.start..RelativeBytePos::from_usize(scx.text.len() - s.trim_start().len()))
+ }
+
+ fn with_leading_match(self, scx: &SpanEditCx<'_>, pat: P) -> Option
+ where
+ P: Pattern,
+ for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
{
- Some(f(text, src.range))
- } else {
- None
+ scx.get_text(..self.start)
+ .and_then(|s| s.strip_suffix(pat))
+ .map(|s| RelativeBytePos::from_usize(s.len())..self.end)
+ }
+
+ fn with_trailing_match(self, scx: &SpanEditCx<'_>, pat: impl Pattern) -> Option {
+ scx.get_text(self.end..)
+ .and_then(|s| s.strip_prefix(pat))
+ .map(|s| self.start..RelativeBytePos::from_usize(scx.text.len() - s.len()))
}
}
+impl FileRangeExt for RangeFull {}
+impl FileRangeExt for RangeTo {}
+impl FileRangeExt for RangeFrom {}
-#[expect(clippy::cast_possible_truncation)]
-fn map_range(
- sm: &SourceMap,
- sp: Range,
- f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>,
-) -> Option> {
- if let Some(src) = get_source_range(sm, sp.clone())
- && let Some(text) = &src.sf.src
- && let Some(range) = f(&src.sf, text, src.range.clone())
+pub trait StrExt {
+ /// Gets the substring which ranges from the start of the first match of the pattern to the end
+ /// of the second match. Returns `None` if the pattern doesn't occur twice.
+ fn find_bounded_inclusive(&self, pat: impl Pattern) -> Option<&Self>;
+
+ /// Gets the non-overlapping prefix and suffix. Returns `None` if the string doesn't start with
+ /// the prefix or end with the suffix.
+ ///
+ /// The prefix will be taken first, with the suffix taken from the remainder of the string.
+ fn get_prefix_suffix(&self, prefix: impl Pattern, suffix: P) -> Option<[&Self; 2]>
+ where
+ P: Pattern,
+ for<'a> P::Searcher<'a>: ReverseSearcher<'a>;
+
+ /// Splits a string into a prefix and everything proceeding it. Returns `None` if the string
+ /// doesn't start with the prefix.
+ fn split_prefix(&self, pat: impl Pattern) -> Option<[&Self; 2]>;
+
+ /// Splits a string into a suffix and everything preceding it. Returns `None` if the string
+ /// doesn't end with the suffix.
+ fn split_suffix
(&self, pat: P) -> Option<[&Self; 2]>
+ where
+ P: Pattern,
+ for<'a> P::Searcher<'a>: ReverseSearcher<'a>;
+
+ /// Splits a string into a prefix and everything proceeding it. Returns `None` if the string
+ /// doesn't start with the prefix.
+ fn split_multipart_prefix(&self, pats: impl IntoIterator) -> Option<[&Self; 2]>;
+}
+impl StrExt for str {
+ fn find_bounded_inclusive(&self, pat: impl Pattern) -> Option<&Self> {
+ let mut iter = self.match_indices(pat);
+ if let Some((first_pos, _)) = iter.next()
+ && let Some((second_pos, second)) = iter.next()
+ {
+ Some(&self[first_pos..second_pos + second.len()])
+ } else {
+ None
+ }
+ }
+
+ fn get_prefix_suffix(&self, prefix: impl Pattern, suffix: P) -> Option<[&Self; 2]>
+ where
+ P: Pattern,
+ for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
{
- debug_assert!(
- range.start <= text.len() && range.end <= text.len(),
- "Range `{range:?}` is outside the source file (file `{}`, length `{}`)",
- src.sf.name.display(FileNameDisplayPreference::Local),
- text.len(),
- );
- debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds");
- let dstart = (range.start as u32).wrapping_sub(src.range.start as u32);
- let dend = (range.end as u32).wrapping_sub(src.range.start as u32);
- Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend)))
- } else {
- None
+ if let Some([pre, s]) = self.split_prefix(prefix)
+ && let Some([_, suf]) = s.split_suffix(suffix)
+ {
+ Some([pre, suf])
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn split_prefix(&self, pat: impl Pattern) -> Option<[&Self; 2]> {
+ self.strip_prefix(pat)
+ .map(|rest| [&self[..self.len() - rest.len()], rest])
+ }
+
+ #[inline]
+ fn split_suffix
(&self, pat: P) -> Option<[&Self; 2]>
+ where
+ P: Pattern,
+ for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
+ {
+ self.strip_suffix(pat).map(|rest| [rest, &self[rest.len()..]])
+ }
+
+ /// Splits a string into a prefix and everything proceeding it. Returns `None` if the string
+ /// doesn't start with the prefix.
+ fn split_multipart_prefix(&self, pats: impl IntoIterator) -> Option<[&Self; 2]> {
+ let mut s = self;
+ for pat in pats {
+ s = s.strip_prefix(pat)?;
+ }
+ Some([&self[..self.len() - s.len()], s])
}
}
+/// Checks if the last token of the string is either a line comment or an incomplete token.
fn ends_with_line_comment_or_broken(text: &str) -> bool {
let Some(last) = tokenize(text, FrontmatterAllowed::No).last() else {
return false;
@@ -303,65 +1427,16 @@ fn ends_with_line_comment_or_broken(text: &str) -> bool {
}
}
-fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range) -> Option {
- debug_assert!(lines.is_empty() || lines[0].to_u32() == 0);
-
- let start = src.get(..range.start)?.trim_end();
- let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len());
- if let Some(line_end) = lines.get(next_line)
- && line_end.to_usize() <= range.start
- && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize())
- && ends_with_line_comment_or_broken(&start[prev_start..])
- && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end)
- && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize())
- && tokenize(src.get(range.end..next_start)?, FrontmatterAllowed::No)
- .any(|t| !matches!(t.kind, TokenKind::Whitespace))
- {
- Some(range.start)
- } else {
- Some(start.len())
- }
-}
-
-fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range {
- map_range(sm, sp.clone(), |sf, src, range| {
- Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end)
- })
- .unwrap_or(sp)
-}
-
-fn trim_start(sm: &SourceMap, sp: Range) -> Range {
- map_range(sm, sp.clone(), |_, src, range| {
- let src = src.get(range.clone())?;
- Some(range.start + (src.len() - src.trim_start().len())..range.end)
- })
- .unwrap_or(sp)
-}
-
-pub struct SourceFileRange {
- pub sf: Arc,
- pub range: Range,
-}
-impl SourceFileRange {
- /// Attempts to get the text from the source file. This can fail if the source text isn't
- /// loaded.
- pub fn as_str(&self) -> Option<&str> {
- (self.sf.src.as_ref().map(|src| src.as_str()))
- .or_else(|| self.sf.external_src.get()?.get_source())
- .and_then(|x| x.get(self.range.clone()))
- }
-}
-
/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block` with no label.
-pub fn expr_block(
- sess: &impl HasSession,
+pub fn expr_block<'sm>(
+ sm: impl HasSourceMap<'sm>,
expr: &Expr<'_>,
outer: SyntaxContext,
default: &str,
indent_relative_to: Option,
app: &mut Applicability,
) -> String {
- let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app);
+ let (code, from_macro) = snippet_block_with_context(sm, expr.span, outer, default, indent_relative_to, app);
if !from_macro
&& let ExprKind::Block(block, None) = expr.kind
&& block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
@@ -386,13 +1461,13 @@ pub fn expr_block(
/// let x = ();
/// // ^^^^^^^^^^
/// ```
-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))
+pub fn first_line_of_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span {
+ first_char_in_first_line(sm, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos))
}
-fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option {
- let line_span = line_span(sess, span);
- snippet_opt(sess, line_span).and_then(|snip| {
+fn first_char_in_first_line<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option {
+ let line_span = line_span(sm, span);
+ snippet_opt(sm, line_span).and_then(|snip| {
snip.find(|c: char| !c.is_whitespace())
.map(|pos| line_span.lo() + BytePos::from_usize(pos))
})
@@ -407,9 +1482,9 @@ fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option Span {
+fn line_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span {
let span = original_sp(span, DUMMY_SP);
- let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap();
+ let SourceFileAndLine { sf, line } = sm.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)
@@ -423,13 +1498,13 @@ fn line_span(sess: &impl HasSession, span: Span) -> Span {
/// let x = ();
/// // ^^ -- will return 4
/// ```
-pub fn indent_of(sess: &impl HasSession, span: Span) -> Option {
- snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
+pub fn indent_of<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option {
+ snippet_opt(sm, line_span(sm, 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(sess: &impl HasSession, span: Span) -> Option {
- snippet_opt(sess, line_span(sess, span)).map(|mut s| {
+pub fn snippet_indent<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option {
+ snippet_opt(sm, line_span(sm, span)).map(|mut s| {
let len = s.len() - s.trim_start().len();
s.truncate(len);
s
@@ -441,8 +1516,8 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option {
// 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(sess: &impl HasSession, span: Span) -> bool {
- if let Some(snippet) = snippet_opt(sess, span)
+pub fn is_present_in_source<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool {
+ if let Some(snippet) = snippet_opt(sm, span)
&& snippet.is_empty()
{
return false;
@@ -532,8 +1607,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option,
/// snippet(cx, span1, "..") // -> "value"
/// snippet(cx, span2, "..") // -> "Vec::new()"
/// ```
-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)
+pub fn snippet<'a, 'sm>(sm: impl HasSourceMap<'sm>, span: Span, default: &'a str) -> Cow<'a, str> {
+ snippet_opt(sm, span).map_or_else(|| Cow::Borrowed(default), From::from)
}
/// Same as [`snippet`], but it adapts the applicability level by following rules:
@@ -542,17 +1617,17 @@ pub fn snippet<'a>(sess: &impl HasSession, 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>(
- sess: &impl HasSession,
+pub fn snippet_with_applicability<'a, 'sm>(
+ sm: impl HasSourceMap<'sm>,
span: Span,
default: &'a str,
applicability: &mut Applicability,
) -> Cow<'a, str> {
- snippet_with_applicability_sess(sess.sess(), span, default, applicability)
+ snippet_with_applicability_sm(sm.source_map(), span, default, applicability)
}
-fn snippet_with_applicability_sess<'a>(
- sess: &Session,
+fn snippet_with_applicability_sm<'a>(
+ sm: &SourceMap,
span: Span,
default: &'a str,
applicability: &mut Applicability,
@@ -560,7 +1635,7 @@ fn snippet_with_applicability_sess<'a>(
if *applicability != Applicability::Unspecified && span.from_expansion() {
*applicability = Applicability::MaybeIncorrect;
}
- snippet_opt(sess, span).map_or_else(
+ snippet_opt(sm, span).map_or_else(
|| {
if *applicability == Applicability::MachineApplicable {
*applicability = Applicability::HasPlaceholders;
@@ -572,8 +1647,8 @@ fn snippet_with_applicability_sess<'a>(
}
/// Converts a span to a code snippet. Returns `None` if not available.
-pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option {
- sess.sess().source_map().span_to_snippet(span).ok()
+pub fn snippet_opt<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option {
+ sm.source_map().span_to_snippet(span).ok()
}
/// Converts a span (from a block) to a code snippet if available, otherwise use default.
@@ -610,36 +1685,41 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option {
/// } // aligned with `if`
/// ```
/// Note that the first line of the snippet always has 0 indentation.
-pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option) -> String {
- let snip = snippet(sess, span, default);
- let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
+pub fn snippet_block<'sm>(
+ sm: impl HasSourceMap<'sm>,
+ span: Span,
+ default: &str,
+ indent_relative_to: Option,
+) -> String {
+ let snip = snippet(sm, span, default);
+ let indent = indent_relative_to.and_then(|s| indent_of(sm, 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(
- sess: &impl HasSession,
+pub fn snippet_block_with_applicability<'sm>(
+ sm: impl HasSourceMap<'sm>,
span: Span,
default: &str,
indent_relative_to: Option,
applicability: &mut Applicability,
) -> String {
- let snip = snippet_with_applicability(sess, span, default, applicability);
- let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
+ let snip = snippet_with_applicability(sm, span, default, applicability);
+ let indent = indent_relative_to.and_then(|s| indent_of(sm, s));
reindent_multiline(&snip, true, indent)
}
-pub fn snippet_block_with_context(
- sess: &impl HasSession,
+pub fn snippet_block_with_context<'sm>(
+ sm: impl HasSourceMap<'sm>,
span: Span,
outer: SyntaxContext,
default: &str,
indent_relative_to: Option,
app: &mut Applicability,
) -> (String, bool) {
- let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app);
- let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
+ let (snip, from_macro) = snippet_with_context(sm, span, outer, default, app);
+ let indent = indent_relative_to.and_then(|s| indent_of(sm, s));
(reindent_multiline(&snip, true, indent), from_macro)
}
@@ -653,18 +1733,18 @@ pub fn snippet_block_with_context(
/// correctly get a snippet of `vec![]`.
///
/// This will also return whether or not the snippet is a macro call.
-pub fn snippet_with_context<'a>(
- sess: &impl HasSession,
+pub fn snippet_with_context<'a, 'sm>(
+ sm: impl HasSourceMap<'sm>,
span: Span,
outer: SyntaxContext,
default: &'a str,
applicability: &mut Applicability,
) -> (Cow<'a, str>, bool) {
- snippet_with_context_sess(sess.sess(), span, outer, default, applicability)
+ snippet_with_context_sm(sm.source_map(), span, outer, default, applicability)
}
-fn snippet_with_context_sess<'a>(
- sess: &Session,
+fn snippet_with_context_sm<'a>(
+ sm: &SourceMap,
span: Span,
outer: SyntaxContext,
default: &'a str,
@@ -672,10 +1752,7 @@ fn snippet_with_context_sess<'a>(
) -> (Cow<'a, str>, bool) {
// If it is just range desugaring, use the desugaring span since it may include parenthesis.
if span.desugaring_kind() == Some(DesugaringKind::RangeExpr) && span.parent_callsite().unwrap().ctxt() == outer {
- return (
- snippet_with_applicability_sess(sess, span, default, applicability),
- false,
- );
+ return (snippet_with_applicability_sm(sm, span, default, applicability), false);
}
let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else(
@@ -691,7 +1768,7 @@ fn snippet_with_context_sess<'a>(
);
(
- snippet_with_applicability_sess(sess, span, default, applicability),
+ snippet_with_applicability_sm(sm, span, default, applicability),
is_macro_call,
)
}
@@ -754,15 +1831,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
/// writeln!(o, "") -> writeln!(o, "")
/// ^^ ^^^^
/// ```
-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);
+pub fn expand_past_previous_comma<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span {
+ let extended = sm.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(
- sess: &impl HasSession,
+pub fn str_literal_to_char_literal<'sm>(
+ sm: impl HasSourceMap<'sm>,
expr: &Expr<'_>,
applicability: &mut Applicability,
ascii_only: bool,
@@ -777,7 +1854,7 @@ pub fn str_literal_to_char_literal(
}
&& len == 1
{
- let snip = snippet_with_applicability(sess, expr.span, string, applicability);
+ let snip = snippet_with_applicability(sm, expr.span, string, applicability);
let ch = if let StrStyle::Raw(nhash) = style {
let nhash = nhash as usize;
// for raw string: r##"a"##
diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs
deleted file mode 100644
index 009815633d75..000000000000
--- a/tests/ui/formatting.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-#![allow(clippy::if_same_then_else)]
-#![allow(clippy::deref_addrof)]
-#![allow(clippy::nonminimal_bool)]
-
-fn foo() -> bool {
- true
-}
-
-#[rustfmt::skip]
-fn main() {
- // weird op_eq formatting:
- let mut a = 42;
- a =- 35;
- //~^ suspicious_assignment_formatting
-
-
- a =* &191;
- //~^ suspicious_assignment_formatting
-
-
-
- let mut b = true;
- b =! false;
- //~^ suspicious_assignment_formatting
-
-
-
- // those are ok:
- a = -35;
- a = *&191;
- b = !false;
-
- // possible missing comma in an array
- let _ = &[
- -1, -2, -3 // <= no comma here
- //~^ possible_missing_comma
-
-
- -4, -5, -6
- ];
- let _ = &[
- -1, -2, -3 // <= no comma here
- //~^ possible_missing_comma
-
-
- *4, -5, -6
- ];
-
- // those are ok:
- let _ = &[
- -1, -2, -3,
- -4, -5, -6
- ];
- let _ = &[
- -1, -2, -3,
- -4, -5, -6,
- ];
- let _ = &[
- 1 + 2, 3 +
- 4, 5 + 6,
- ];
-
- // don't lint for bin op without unary equiv
- // issue 3244
- vec![
- 1
- / 2,
- ];
- // issue 3396
- vec![
- true
- | false,
- ];
-
- // don't lint if the indentation suggests not to
- let _ = &[
- 1 + 2, 3
- - 4, 5
- ];
- // lint if it doesn't
- let _ = &[
- -1
- //~^ possible_missing_comma
-
-
- -4,
- ];
-}
diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr
deleted file mode 100644
index d9dc2a55f5b6..000000000000
--- a/tests/ui/formatting.stderr
+++ /dev/null
@@ -1,53 +0,0 @@
-error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
- --> tests/ui/formatting.rs:13:6
- |
-LL | a =- 35;
- | ^^^^
- |
- = note: to remove this lint, use either `-=` or `= -`
- = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::suspicious_assignment_formatting)]`
-
-error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
- --> tests/ui/formatting.rs:17:6
- |
-LL | a =* &191;
- | ^^^^
- |
- = note: to remove this lint, use either `*=` or `= *`
-
-error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
- --> tests/ui/formatting.rs:23:6
- |
-LL | b =! false;
- | ^^^^
- |
- = note: to remove this lint, use either `!=` or `= !`
-
-error: possibly missing a comma here
- --> tests/ui/formatting.rs:35:19
- |
-LL | -1, -2, -3 // <= no comma here
- | ^
- |
- = note: to remove this lint, add a comma or write the expr in a single line
- = note: `#[deny(clippy::possible_missing_comma)]` on by default
-
-error: possibly missing a comma here
- --> tests/ui/formatting.rs:42:19
- |
-LL | -1, -2, -3 // <= no comma here
- | ^
- |
- = note: to remove this lint, add a comma or write the expr in a single line
-
-error: possibly missing a comma here
- --> tests/ui/formatting.rs:82:11
- |
-LL | -1
- | ^
- |
- = note: to remove this lint, add a comma or write the expr in a single line
-
-error: aborting due to 6 previous errors
-
diff --git a/tests/ui/formatting/possible_missing_comma.1.fixed b/tests/ui/formatting/possible_missing_comma.1.fixed
new file mode 100644
index 000000000000..286fa748b1cd
--- /dev/null
+++ b/tests/ui/formatting/possible_missing_comma.1.fixed
@@ -0,0 +1,74 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::possible_missing_comma)]
+
+use proc_macros::{external, inline_macros, with_span};
+
+#[rustfmt::skip]
+#[inline_macros]
+fn main() {
+ {
+ let x = 20;
+ let y = &32;
+
+ let _ = [1, 2, *y]; //~ possible_missing_comma
+ let _ = [1, 2, -x]; //~ possible_missing_comma
+ let _ = [1, x - 2, -x]; //~ possible_missing_comma
+ let _ = [1, 2, -x - 2]; //~ possible_missing_comma
+ let _ = [1, 2 * x * 2, -x]; //~ possible_missing_comma
+
+ let _ = [
+ 1,
+ x,
+ -2 * x * 2, //~ possible_missing_comma
+ -x, //~ possible_missing_comma
+ ];
+
+ let _ = (1, &x); //~ possible_missing_comma
+ let _ = (1, x, -1); //~ possible_missing_comma
+
+ let _ = (1-x);
+ let _ = (1- x);
+ let _ = (1 -/* comment */x);
+ let _ = (1, 2*y - 5);
+ let _ = (1, 2 /x);
+ let _ = (1, 2 tests/ui/formatting/possible_missing_comma.rs:13:23
+ |
+LL | let _ = [1, 2 *y];
+ | ^
+ |
+note: the lint level is defined here
+ --> tests/ui/formatting/possible_missing_comma.rs:2:9
+ |
+LL | #![deny(clippy::possible_missing_comma)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a comma before
+ |
+LL | let _ = [1, 2, *y];
+ | +
+help: add a space after
+ |
+LL | let _ = [1, 2 * y];
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:14:23
+ |
+LL | let _ = [1, 2 -x];
+ | ^
+ |
+help: add a comma before
+ |
+LL | let _ = [1, 2, -x];
+ | +
+help: add a space after
+ |
+LL | let _ = [1, 2 - x];
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:15:27
+ |
+LL | let _ = [1, x - 2 -x];
+ | ^
+ |
+help: add a comma before
+ |
+LL | let _ = [1, x - 2, -x];
+ | +
+help: add a space after
+ |
+LL | let _ = [1, x - 2 - x];
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:16:23
+ |
+LL | let _ = [1, 2 -x - 2];
+ | ^
+ |
+help: add a comma before
+ |
+LL | let _ = [1, 2, -x - 2];
+ | +
+help: add a space after
+ |
+LL | let _ = [1, 2 - x - 2];
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:17:31
+ |
+LL | let _ = [1, 2 * x * 2 -x];
+ | ^
+ |
+help: add a comma before
+ |
+LL | let _ = [1, 2 * x * 2, -x];
+ | +
+help: add a space after
+ |
+LL | let _ = [1, 2 * x * 2 - x];
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:23:13
+ |
+LL | -x,
+ | ^
+ |
+help: add a comma before
+ |
+LL | -2 * x * 2,
+ | +
+help: add a space after
+ |
+LL | - x,
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:22:13
+ |
+LL | -2 * x * 2
+ | ^
+ |
+help: add a comma before
+ |
+LL | x,
+ | +
+help: add a space after
+ |
+LL | - 2 * x * 2
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:26:20
+ |
+LL | let _ = (1 &x);
+ | ^
+ |
+help: add a comma before
+ |
+LL | let _ = (1, &x);
+ | +
+help: add a space after
+ |
+LL | let _ = (1 & x);
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:27:23
+ |
+LL | let _ = (1, x -1);
+ | ^
+ |
+help: add a comma before
+ |
+LL | let _ = (1, x, -1);
+ | +
+help: add a space after
+ |
+LL | let _ = (1, x - 1);
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:51:20
+ |
+LL | let _ = (y &&x);
+ | ^^
+ |
+help: add a comma before
+ |
+LL | let _ = (y, &&x);
+ | +
+help: add a space after
+ |
+LL | let _ = (y && x);
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:69:20
+ |
+LL | let _ = (x -1);
+ | ^
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a comma before
+ |
+LL | let _ = (x, -1);
+ | +
+help: add a space after
+ |
+LL | let _ = (x - 1);
+ | +
+
+error: the is formatted like a unary operator, but it's parsed as a binary operator
+ --> tests/ui/formatting/possible_missing_comma.rs:70:20
+ |
+LL | let _ = (x -$(@tt 1));
+ | ^
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a comma before
+ |
+LL | let _ = (x, -$(@tt 1));
+ | +
+help: add a space after
+ |
+LL | let _ = (x - $(@tt 1));
+ | +
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/formatting/possible_missing_else.1.fixed b/tests/ui/formatting/possible_missing_else.1.fixed
new file mode 100644
index 000000000000..0584fe01b566
--- /dev/null
+++ b/tests/ui/formatting/possible_missing_else.1.fixed
@@ -0,0 +1,69 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::possible_missing_else)]
+#![allow(
+ clippy::if_same_then_else,
+ clippy::let_unit_value,
+ clippy::needless_ifs,
+ clippy::needless_else
+)]
+
+use proc_macros::{external, with_span};
+
+fn foo() -> bool {
+ true
+}
+
+#[rustfmt::skip]
+fn main() {
+ //~vv possible_missing_else
+ if foo() {
+ } else {
+ }
+
+ //~vv possible_missing_else
+ if foo() {
+ } else if foo() {
+ }
+
+ let _ = {
+ let _ = 0;
+
+ //~vv possible_missing_else
+ if foo() {
+ } else if foo() {
+ }
+ else {
+ }
+ };
+
+ let _ = {
+ //~vv possible_missing_else
+ if foo() {
+ } else if foo() {
+ }
+ else {
+ }
+
+ let _ = 0;
+ };
+
+ // those are ok:
+ if foo() {
+ }
+ {
+ }
+
+ if foo() {
+ } else {
+ }
+
+ if foo() {
+ }
+ else {
+ }
+
+ if foo() {
+ }
+ if foo() {
+ }
+}
diff --git a/tests/ui/formatting/possible_missing_else.2.fixed b/tests/ui/formatting/possible_missing_else.2.fixed
new file mode 100644
index 000000000000..816f7ad357a3
--- /dev/null
+++ b/tests/ui/formatting/possible_missing_else.2.fixed
@@ -0,0 +1,73 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::possible_missing_else)]
+#![allow(
+ clippy::if_same_then_else,
+ clippy::let_unit_value,
+ clippy::needless_ifs,
+ clippy::needless_else
+)]
+
+use proc_macros::{external, with_span};
+
+fn foo() -> bool {
+ true
+}
+
+#[rustfmt::skip]
+fn main() {
+ //~vv possible_missing_else
+ if foo() {
+ }
+ {
+ }
+
+ //~vv possible_missing_else
+ if foo() {
+ }
+ if foo() {
+ }
+
+ let _ = {
+ let _ = 0;
+
+ //~vv possible_missing_else
+ if foo() {
+ }
+ if foo() {
+ }
+ else {
+ }
+ };
+
+ let _ = {
+ //~vv possible_missing_else
+ if foo() {
+ }
+ if foo() {
+ }
+ else {
+ }
+
+ let _ = 0;
+ };
+
+ // those are ok:
+ if foo() {
+ }
+ {
+ }
+
+ if foo() {
+ } else {
+ }
+
+ if foo() {
+ }
+ else {
+ }
+
+ if foo() {
+ }
+ if foo() {
+ }
+}
diff --git a/tests/ui/formatting/possible_missing_else.rs b/tests/ui/formatting/possible_missing_else.rs
new file mode 100644
index 000000000000..f6d3d86b30a1
--- /dev/null
+++ b/tests/ui/formatting/possible_missing_else.rs
@@ -0,0 +1,69 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::possible_missing_else)]
+#![allow(
+ clippy::if_same_then_else,
+ clippy::let_unit_value,
+ clippy::needless_ifs,
+ clippy::needless_else
+)]
+
+use proc_macros::{external, with_span};
+
+fn foo() -> bool {
+ true
+}
+
+#[rustfmt::skip]
+fn main() {
+ //~vv possible_missing_else
+ if foo() {
+ } {
+ }
+
+ //~vv possible_missing_else
+ if foo() {
+ } if foo() {
+ }
+
+ let _ = {
+ let _ = 0;
+
+ //~vv possible_missing_else
+ if foo() {
+ } if foo() {
+ }
+ else {
+ }
+ };
+
+ let _ = {
+ //~vv possible_missing_else
+ if foo() {
+ } if foo() {
+ }
+ else {
+ }
+
+ let _ = 0;
+ };
+
+ // those are ok:
+ if foo() {
+ }
+ {
+ }
+
+ if foo() {
+ } else {
+ }
+
+ if foo() {
+ }
+ else {
+ }
+
+ if foo() {
+ }
+ if foo() {
+ }
+}
diff --git a/tests/ui/formatting/possible_missing_else.stderr b/tests/ui/formatting/possible_missing_else.stderr
new file mode 100644
index 000000000000..9e41ce1e4505
--- /dev/null
+++ b/tests/ui/formatting/possible_missing_else.stderr
@@ -0,0 +1,71 @@
+error: this is formatted as though there should be an `else`
+ --> tests/ui/formatting/possible_missing_else.rs:20:6
+ |
+LL | } {
+ | ^
+ |
+note: the lint level is defined here
+ --> tests/ui/formatting/possible_missing_else.rs:2:9
+ |
+LL | #![deny(clippy::possible_missing_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add an `else`
+ |
+LL | } else {
+ | ++++
+help: add a line break
+ |
+LL ~ }
+LL ~ {
+ |
+
+error: this is formatted as though there should be an `else`
+ --> tests/ui/formatting/possible_missing_else.rs:25:6
+ |
+LL | } if foo() {
+ | ^
+ |
+help: add an `else`
+ |
+LL | } else if foo() {
+ | ++++
+help: add a line break
+ |
+LL ~ }
+LL ~ if foo() {
+ |
+
+error: this is formatted as though there should be an `else`
+ --> tests/ui/formatting/possible_missing_else.rs:33:10
+ |
+LL | } if foo() {
+ | ^
+ |
+help: add an `else`
+ |
+LL | } else if foo() {
+ | ++++
+help: add a line break
+ |
+LL ~ }
+LL ~ if foo() {
+ |
+
+error: this is formatted as though there should be an `else`
+ --> tests/ui/formatting/possible_missing_else.rs:42:10
+ |
+LL | } if foo() {
+ | ^
+ |
+help: add an `else`
+ |
+LL | } else if foo() {
+ | ++++
+help: add a line break
+ |
+LL ~ }
+LL ~ if foo() {
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/formatting/suspicious_assignment_formatting.1.fixed b/tests/ui/formatting/suspicious_assignment_formatting.1.fixed
new file mode 100644
index 000000000000..dd9eff1443a9
--- /dev/null
+++ b/tests/ui/formatting/suspicious_assignment_formatting.1.fixed
@@ -0,0 +1,71 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::suspicious_assignment_formatting)]
+#![allow(clippy::no_effect)]
+
+use proc_macros::{external, inline_macros, with_span};
+
+#[rustfmt::skip]
+#[inline_macros]
+fn main() {
+ {
+ let mut x = 42;
+ let y = &45;
+
+ x -= 35; //~ suspicious_assignment_formatting
+ x *= y; //~ suspicious_assignment_formatting
+
+ x=-32;
+ x =-32;
+ x =(-32);
+ x =-/* comment */32;
+ }
+
+ {
+ let mut x = false;
+ let y = false;
+ x != y; //~ suspicious_assignment_formatting
+ }
+
+ with_span! {
+ span
+ let mut x = 42;
+ x =- 35;
+ }
+
+ external! {
+ let mut x = 42;
+ x =- 35;
+ }
+
+ inline! {
+ let mut x = 42;
+ x -= 35; //~ suspicious_assignment_formatting
+ }
+
+ {
+ let mut x = 42;
+ inline! {
+ $x -= $35; //~ suspicious_assignment_formatting
+ }
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ x $($t)* 35;
+ }
+ }
+ m!(=-);
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ x $($t)*;
+ }
+ }
+ m!(=- 35);
+ }
+}
diff --git a/tests/ui/formatting/suspicious_assignment_formatting.2.fixed b/tests/ui/formatting/suspicious_assignment_formatting.2.fixed
new file mode 100644
index 000000000000..050c4e3694f1
--- /dev/null
+++ b/tests/ui/formatting/suspicious_assignment_formatting.2.fixed
@@ -0,0 +1,71 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::suspicious_assignment_formatting)]
+#![allow(clippy::no_effect)]
+
+use proc_macros::{external, inline_macros, with_span};
+
+#[rustfmt::skip]
+#[inline_macros]
+fn main() {
+ {
+ let mut x = 42;
+ let y = &45;
+
+ x = -35; //~ suspicious_assignment_formatting
+ x = *y; //~ suspicious_assignment_formatting
+
+ x=-32;
+ x =-32;
+ x =(-32);
+ x =-/* comment */32;
+ }
+
+ {
+ let mut x = false;
+ let y = false;
+ x = !y; //~ suspicious_assignment_formatting
+ }
+
+ with_span! {
+ span
+ let mut x = 42;
+ x =- 35;
+ }
+
+ external! {
+ let mut x = 42;
+ x =- 35;
+ }
+
+ inline! {
+ let mut x = 42;
+ x = -35; //~ suspicious_assignment_formatting
+ }
+
+ {
+ let mut x = 42;
+ inline! {
+ $x = -$35; //~ suspicious_assignment_formatting
+ }
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ x $($t)* 35;
+ }
+ }
+ m!(=-);
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ x $($t)*;
+ }
+ }
+ m!(=- 35);
+ }
+}
diff --git a/tests/ui/formatting/suspicious_assignment_formatting.rs b/tests/ui/formatting/suspicious_assignment_formatting.rs
new file mode 100644
index 000000000000..b726903911e4
--- /dev/null
+++ b/tests/ui/formatting/suspicious_assignment_formatting.rs
@@ -0,0 +1,71 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::suspicious_assignment_formatting)]
+#![allow(clippy::no_effect)]
+
+use proc_macros::{external, inline_macros, with_span};
+
+#[rustfmt::skip]
+#[inline_macros]
+fn main() {
+ {
+ let mut x = 42;
+ let y = &45;
+
+ x =- 35; //~ suspicious_assignment_formatting
+ x =* y; //~ suspicious_assignment_formatting
+
+ x=-32;
+ x =-32;
+ x =(-32);
+ x =-/* comment */32;
+ }
+
+ {
+ let mut x = false;
+ let y = false;
+ x =! y; //~ suspicious_assignment_formatting
+ }
+
+ with_span! {
+ span
+ let mut x = 42;
+ x =- 35;
+ }
+
+ external! {
+ let mut x = 42;
+ x =- 35;
+ }
+
+ inline! {
+ let mut x = 42;
+ x =- 35; //~ suspicious_assignment_formatting
+ }
+
+ {
+ let mut x = 42;
+ inline! {
+ $x =- $35; //~ suspicious_assignment_formatting
+ }
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ x $($t)* 35;
+ }
+ }
+ m!(=-);
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ x $($t)*;
+ }
+ }
+ m!(=- 35);
+ }
+}
diff --git a/tests/ui/formatting/suspicious_assignment_formatting.stderr b/tests/ui/formatting/suspicious_assignment_formatting.stderr
new file mode 100644
index 000000000000..f96785e41c26
--- /dev/null
+++ b/tests/ui/formatting/suspicious_assignment_formatting.stderr
@@ -0,0 +1,89 @@
+error: this looks similar to a compound assignment operator
+ --> tests/ui/formatting/suspicious_assignment_formatting.rs:14:11
+ |
+LL | x =- 35;
+ | ^^
+ |
+note: the lint level is defined here
+ --> tests/ui/formatting/suspicious_assignment_formatting.rs:2:9
+ |
+LL | #![deny(clippy::suspicious_assignment_formatting)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: reverse the characters
+ |
+LL - x =- 35;
+LL + x -= 35;
+ |
+help: separate the characters
+ |
+LL | x = -35;
+ | ~~~
+
+error: this looks similar to a compound assignment operator
+ --> tests/ui/formatting/suspicious_assignment_formatting.rs:15:11
+ |
+LL | x =* y;
+ | ^^
+ |
+help: reverse the characters
+ |
+LL - x =* y;
+LL + x *= y;
+ |
+help: separate the characters
+ |
+LL | x = *y;
+ | ~~~
+
+error: this looks similar to a compound assignment operator
+ --> tests/ui/formatting/suspicious_assignment_formatting.rs:26:11
+ |
+LL | x =! y;
+ | ^^
+ |
+help: reverse the characters
+ |
+LL - x =! y;
+LL + x != y;
+ |
+help: separate the characters
+ |
+LL | x = !y;
+ | ~~~
+
+error: this looks similar to a compound assignment operator
+ --> tests/ui/formatting/suspicious_assignment_formatting.rs:42:11
+ |
+LL | x =- 35;
+ | ^^
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: reverse the characters
+ |
+LL - x =- 35;
+LL + x -= 35;
+ |
+help: separate the characters
+ |
+LL | x = -35;
+ | ~~~
+
+error: this looks similar to a compound assignment operator
+ --> tests/ui/formatting/suspicious_assignment_formatting.rs:48:16
+ |
+LL | $x =- $35;
+ | ^^
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: reverse the characters
+ |
+LL - $x =- $35;
+LL + $x -= $35;
+ |
+help: separate the characters
+ |
+LL | $x = -$35;
+ | ~~~
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/formatting/suspicious_else_formatting.rs
similarity index 52%
rename from tests/ui/suspicious_else_formatting.rs
rename to tests/ui/formatting/suspicious_else_formatting.rs
index 8574cf1c20a1..d66ad07bb1f3 100644
--- a/tests/ui/suspicious_else_formatting.rs
+++ b/tests/ui/formatting/suspicious_else_formatting.rs
@@ -1,6 +1,5 @@
-//@aux-build:proc_macro_suspicious_else_formatting.rs
-
-#![warn(clippy::suspicious_else_formatting, clippy::possible_missing_else)]
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::suspicious_else_formatting)]
#![allow(
clippy::if_same_then_else,
clippy::let_unit_value,
@@ -8,8 +7,7 @@
clippy::needless_else
)]
-extern crate proc_macro_suspicious_else_formatting;
-use proc_macro_suspicious_else_formatting::DeriveBadSpan;
+use proc_macros::{external, with_span};
fn foo() -> bool {
true
@@ -17,44 +15,11 @@ fn foo() -> bool {
#[rustfmt::skip]
fn main() {
- // weird `else` formatting:
- if foo() {
- } {
- //~^ possible_missing_else
- }
-
- if foo() {
- } if foo() {
- //~^ possible_missing_else
- }
-
- let _ = { // if as the last expression
- let _ = 0;
-
- if foo() {
- } if foo() {
- //~^ possible_missing_else
- }
- else {
- }
- };
-
- let _ = { // if in the middle of a block
- if foo() {
- } if foo() {
- //~^ possible_missing_else
- }
- else {
- }
-
- let _ = 0;
- };
-
+ //~vv suspicious_else_formatting
if foo() {
} else
{
}
- //~^^^ suspicious_else_formatting
// This is fine, though weird. Allman style braces on the else.
if foo() {
@@ -63,25 +28,20 @@ fn main() {
{
}
+ //~vv suspicious_else_formatting
if foo() {
} else
- if foo() { // the span of the above error should continue here
+ if foo() {
}
- //~^^^ suspicious_else_formatting
+ //~vv suspicious_else_formatting
if foo() {
}
else
- if foo() { // the span of the above error should continue here
- }
- //~^^^^ suspicious_else_formatting
-
- // those are ok:
if foo() {
}
- {
- }
+ // those are ok:
if foo() {
} else {
}
@@ -91,20 +51,16 @@ fn main() {
else {
}
- if foo() {
- }
- if foo() {
- }
-
- // Almost Allman style braces. Lint these.
+ //~vv suspicious_else_formatting
if foo() {
}
else
{
+
}
- //~^^^^^ suspicious_else_formatting
+ //~vv suspicious_else_formatting
if foo() {
}
else
@@ -112,7 +68,6 @@ fn main() {
{
}
- //~^^^^^^ suspicious_else_formatting
// #3864 - Allman style braces
if foo()
@@ -156,8 +111,56 @@ fn main() {
println!("false");
}
-}
+ with_span! {
+ span
+ if true {
+ let _ = 0;
+ } else
+
+ {
+ let _ = 1;
+ }
+ }
+
+
+ external! {
+ if true {
+ let _ = 0;
+ } else
+
+ {
+ let _ = 1;
+ }
+ }
+
+ //~vvv suspicious_else_formatting
+ if true {
+ let _ = 0;
+ } /* comment */ else
+
+ {
+ let _ = 1;
+ }
-// #7650 - Don't lint. Proc-macro using bad spans for `if` expressions.
-#[derive(DeriveBadSpan)]
-struct _Foo(u32, u32);
+ //~vvv suspicious_else_formatting
+ if true {
+ let _ = 0;
+ }
+ // comment
+ else
+
+
+ {
+ let _ = 1;
+ }
+
+
+ //~vvv suspicious_else_formatting
+ if true {
+ let _ = 0;
+ } /*
+ * some comment */ else
+ {
+ let _ = 1;
+ }
+}
diff --git a/tests/ui/formatting/suspicious_else_formatting.stderr b/tests/ui/formatting/suspicious_else_formatting.stderr
new file mode 100644
index 000000000000..f30ceb19eccb
--- /dev/null
+++ b/tests/ui/formatting/suspicious_else_formatting.stderr
@@ -0,0 +1,97 @@
+error: this is an `else {..}` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:20:6
+ |
+LL | } else
+ | ______^
+LL | | {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+note: the lint level is defined here
+ --> tests/ui/formatting/suspicious_else_formatting.rs:2:9
+ |
+LL | #![deny(clippy::suspicious_else_formatting)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this is an `else if` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:33:6
+ |
+LL | } else
+ | ______^
+LL | | if foo() {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
+
+error: this is an `else if` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:39:6
+ |
+LL | }
+ | ______^
+LL | | else
+LL | | if foo() {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
+
+error: this is an `else {..}` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:56:6
+ |
+LL | }
+ | ______^
+LL | |
+LL | | else
+LL | | {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else {..}` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:65:6
+ |
+LL | }
+ | ______^
+LL | | else
+LL | |
+LL | | {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else {..}` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:139:6
+ |
+LL | } /* comment */ else
+ | ______^
+LL | |
+LL | | {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else {..}` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:148:6
+ |
+LL | }
+ | ______^
+LL | | // comment
+LL | | else
+... |
+LL | | {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else {..}` but the formatting might hide it
+ --> tests/ui/formatting/suspicious_else_formatting.rs:161:6
+ |
+LL | } /*
+ | ______^
+LL | | * some comment */ else
+LL | | {
+ | |____^
+ |
+ = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/formatting/suspicious_unary_op_formatting.fixed b/tests/ui/formatting/suspicious_unary_op_formatting.fixed
new file mode 100644
index 000000000000..24d3818507ca
--- /dev/null
+++ b/tests/ui/formatting/suspicious_unary_op_formatting.fixed
@@ -0,0 +1,64 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::suspicious_unary_op_formatting)]
+
+use proc_macros::{external, inline_macros, with_span};
+
+#[rustfmt::skip]
+#[inline_macros]
+fn main() {
+ {
+ let x = 42;
+ let y = &42;
+
+ let _ = x - -30; //~ suspicious_unary_op_formatting
+ let _ = x * *y; //~ suspicious_unary_op_formatting
+ let _ = x + !30; //~ suspicious_unary_op_formatting
+ let _ = x << *y; //~ suspicious_unary_op_formatting
+ let _ = x == !30; //~ suspicious_unary_op_formatting
+
+ let _ = x+-30;
+ let _ = x +-30;
+ let _ = x +-/* comment */30;
+ }
+
+ with_span! {
+ span
+ let x = 42;
+ let _ = x -- 30;
+ }
+
+ external! {
+ let x = 42;
+ let _ = x -- 30;
+ }
+
+ inline! {
+ let x = 42;
+ let _ = x & -30; //~ suspicious_unary_op_formatting
+ let _ = x | -$30; //~ suspicious_unary_op_formatting
+ }
+
+ inline! {
+ let _ = $x > -$30; //~ suspicious_unary_op_formatting
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ let _ = x $($t)* 35;
+ }
+ }
+ m!(--);
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ let _ = x $($t)*;
+ }
+ }
+ m!(-- 35);
+ }
+}
diff --git a/tests/ui/formatting/suspicious_unary_op_formatting.rs b/tests/ui/formatting/suspicious_unary_op_formatting.rs
new file mode 100644
index 000000000000..6772799f1c3b
--- /dev/null
+++ b/tests/ui/formatting/suspicious_unary_op_formatting.rs
@@ -0,0 +1,64 @@
+//@aux-build:../auxiliary/proc_macros.rs
+#![deny(clippy::suspicious_unary_op_formatting)]
+
+use proc_macros::{external, inline_macros, with_span};
+
+#[rustfmt::skip]
+#[inline_macros]
+fn main() {
+ {
+ let x = 42;
+ let y = &42;
+
+ let _ = x -- 30; //~ suspicious_unary_op_formatting
+ let _ = x ** y; //~ suspicious_unary_op_formatting
+ let _ = x +! 30; //~ suspicious_unary_op_formatting
+ let _ = x <<* y; //~ suspicious_unary_op_formatting
+ let _ = x ==! 30; //~ suspicious_unary_op_formatting
+
+ let _ = x+-30;
+ let _ = x +-30;
+ let _ = x +-/* comment */30;
+ }
+
+ with_span! {
+ span
+ let x = 42;
+ let _ = x -- 30;
+ }
+
+ external! {
+ let x = 42;
+ let _ = x -- 30;
+ }
+
+ inline! {
+ let x = 42;
+ let _ = x &- 30; //~ suspicious_unary_op_formatting
+ let _ = x |- $30; //~ suspicious_unary_op_formatting
+ }
+
+ inline! {
+ let _ = $x >- $30; //~ suspicious_unary_op_formatting
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ let _ = x $($t)* 35;
+ }
+ }
+ m!(--);
+ }
+
+ {
+ macro_rules! m {
+ ($($t:tt)*) => {
+ let mut x = 42;
+ let _ = x $($t)*;
+ }
+ }
+ m!(-- 35);
+ }
+}
diff --git a/tests/ui/formatting/suspicious_unary_op_formatting.stderr b/tests/ui/formatting/suspicious_unary_op_formatting.stderr
new file mode 100644
index 000000000000..4ed0515ca6cd
--- /dev/null
+++ b/tests/ui/formatting/suspicious_unary_op_formatting.stderr
@@ -0,0 +1,78 @@
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:13:19
+ |
+LL | let _ = x -- 30;
+ | ^^-
+ | |
+ | help: add a space between: `- -`
+ |
+note: the lint level is defined here
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:2:9
+ |
+LL | #![deny(clippy::suspicious_unary_op_formatting)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:14:19
+ |
+LL | let _ = x ** y;
+ | ^^-
+ | |
+ | help: add a space between: `* *`
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:15:19
+ |
+LL | let _ = x +! 30;
+ | ^^-
+ | |
+ | help: add a space between: `+ !`
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:16:19
+ |
+LL | let _ = x <<* y;
+ | ^^^-
+ | |
+ | help: add a space between: `<< *`
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:17:19
+ |
+LL | let _ = x ==! 30;
+ | ^^^-
+ | |
+ | help: add a space between: `== !`
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:37:19
+ |
+LL | let _ = x &- 30;
+ | ^^-
+ | |
+ | help: add a space between: `& -`
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:38:19
+ |
+LL | let _ = x |- $30;
+ | ^^-
+ | |
+ | help: add a space between: `| -`
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this formatting makes the binary and unary operators look like a single operator
+ --> tests/ui/formatting/suspicious_unary_op_formatting.rs:42:20
+ |
+LL | let _ = $x >- $30;
+ | ^^-
+ | |
+ | help: add a space between: `> -`
+ |
+ = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/suspicious_else_formatting.stderr b/tests/ui/suspicious_else_formatting.stderr
deleted file mode 100644
index 04555c6edbd3..000000000000
--- a/tests/ui/suspicious_else_formatting.stderr
+++ /dev/null
@@ -1,93 +0,0 @@
-error: this looks like an `else {..}` but the `else` is missing
- --> tests/ui/suspicious_else_formatting.rs:22:6
- |
-LL | } {
- | ^
- |
- = note: to remove this lint, add the missing `else` or add a new line before the next block
- = note: `-D clippy::possible-missing-else` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::possible_missing_else)]`
-
-error: this looks like an `else if` but the `else` is missing
- --> tests/ui/suspicious_else_formatting.rs:27:6
- |
-LL | } if foo() {
- | ^
- |
- = note: to remove this lint, add the missing `else` or add a new line before the second `if`
-
-error: this looks like an `else if` but the `else` is missing
- --> tests/ui/suspicious_else_formatting.rs:35:10
- |
-LL | } if foo() {
- | ^
- |
- = note: to remove this lint, add the missing `else` or add a new line before the second `if`
-
-error: this looks like an `else if` but the `else` is missing
- --> tests/ui/suspicious_else_formatting.rs:44:10
- |
-LL | } if foo() {
- | ^
- |
- = note: to remove this lint, add the missing `else` or add a new line before the second `if`
-
-error: this is an `else {..}` but the formatting might hide it
- --> tests/ui/suspicious_else_formatting.rs:54:6
- |
-LL | } else
- | ______^
-LL | | {
- | |____^
- |
- = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
- = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::suspicious_else_formatting)]`
-
-error: this is an `else if` but the formatting might hide it
- --> tests/ui/suspicious_else_formatting.rs:67:6
- |
-LL | } else
- | ______^
-LL | | if foo() { // the span of the above error should continue here
- | |____^
- |
- = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
-
-error: this is an `else if` but the formatting might hide it
- --> tests/ui/suspicious_else_formatting.rs:73:6
- |
-LL | }
- | ______^
-LL | | else
-LL | | if foo() { // the span of the above error should continue here
- | |____^
- |
- = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
-
-error: this is an `else {..}` but the formatting might hide it
- --> tests/ui/suspicious_else_formatting.rs:101:6
- |
-LL | }
- | ______^
-LL | |
-LL | | else
-LL | | {
- | |____^
- |
- = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
-
-error: this is an `else {..}` but the formatting might hide it
- --> tests/ui/suspicious_else_formatting.rs:109:6
- |
-LL | }
- | ______^
-LL | | else
-LL | |
-LL | | {
- | |____^
- |
- = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
-
-error: aborting due to 9 previous errors
-
diff --git a/tests/ui/suspicious_unary_op_formatting.rs b/tests/ui/suspicious_unary_op_formatting.rs
deleted file mode 100644
index 19f8b231925b..000000000000
--- a/tests/ui/suspicious_unary_op_formatting.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-#![warn(clippy::suspicious_unary_op_formatting)]
-#![allow(clippy::needless_ifs)]
-
-#[rustfmt::skip]
-fn main() {
- // weird binary operator formatting:
- let a = 42;
-
- if a >- 30 {}
- //~^ suspicious_unary_op_formatting
-
- if a >=- 30 {}
- //~^ suspicious_unary_op_formatting
-
-
- let b = true;
- let c = false;
-
- if b &&! c {}
- //~^ suspicious_unary_op_formatting
-
-
- if a >- 30 {}
- //~^ suspicious_unary_op_formatting
-
-
- // those are ok:
- if a >-30 {}
- if a < -30 {}
- if b && !c {}
- if a > - 30 {}
-}
diff --git a/tests/ui/suspicious_unary_op_formatting.stderr b/tests/ui/suspicious_unary_op_formatting.stderr
deleted file mode 100644
index 5fe18aa82435..000000000000
--- a/tests/ui/suspicious_unary_op_formatting.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-error: by not having a space between `>` and `-` it looks like `>-` is a single operator
- --> tests/ui/suspicious_unary_op_formatting.rs:9:9
- |
-LL | if a >- 30 {}
- | ^^^^
- |
- = help: put a space between `>` and `-` and remove the space after `-`
- = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::suspicious_unary_op_formatting)]`
-
-error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator
- --> tests/ui/suspicious_unary_op_formatting.rs:12:9
- |
-LL | if a >=- 30 {}
- | ^^^^^
- |
- = help: put a space between `>=` and `-` and remove the space after `-`
-
-error: by not having a space between `&&` and `!` it looks like `&&!` is a single operator
- --> tests/ui/suspicious_unary_op_formatting.rs:19:9
- |
-LL | if b &&! c {}
- | ^^^^^
- |
- = help: put a space between `&&` and `!` and remove the space after `!`
-
-error: by not having a space between `>` and `-` it looks like `>-` is a single operator
- --> tests/ui/suspicious_unary_op_formatting.rs:23:9
- |
-LL | if a >- 30 {}
- | ^^^^^^
- |
- = help: put a space between `>` and `-` and remove the space after `-`
-
-error: aborting due to 4 previous errors
-