@@ -3,6 +3,7 @@ use clippy_config::Conf;
3
3
use clippy_utils:: attrs:: is_doc_hidden;
4
4
use clippy_utils:: diagnostics:: { span_lint, span_lint_and_help} ;
5
5
use clippy_utils:: macros:: { is_panic, root_macro_call_first_node} ;
6
+ use clippy_utils:: source:: snippet;
6
7
use clippy_utils:: ty:: is_type_diagnostic_item;
7
8
use clippy_utils:: visitors:: Visitable ;
8
9
use clippy_utils:: { is_entrypoint_fn, is_trait_impl_item, method_chain_args} ;
@@ -27,9 +28,11 @@ use rustc_resolve::rustdoc::{
27
28
use rustc_session:: impl_lint_pass;
28
29
use rustc_span:: edition:: Edition ;
29
30
use rustc_span:: { sym, Span } ;
31
+ use std:: borrow:: Cow ;
30
32
use std:: ops:: Range ;
31
33
use url:: Url ;
32
34
35
+ mod doc_comment_double_space_linebreak;
33
36
mod link_with_quotes;
34
37
mod markdown;
35
38
mod missing_headers;
@@ -422,6 +425,39 @@ declare_clippy_lint! {
422
425
"require every line of a paragraph to be indented and marked"
423
426
}
424
427
428
+ declare_clippy_lint ! {
429
+ /// ### What it does
430
+ /// Detects doc comment linebreaks that use double spaces to separate lines, instead of back-slash (\).
431
+ ///
432
+ /// ### Why is this bad?
433
+ /// Double spaces, when used as doc comment linebreaks, can be difficult to see, and may
434
+ /// accidentally be removed during automatic fofmatting or manual refactoring. The use of a back-slash (\)
435
+ /// is clearer in this regard.
436
+ ///
437
+ /// ### Example
438
+ /// The two dots in this example represent a double space.
439
+ /// ```no_run
440
+ /// /// This command takes two numbers as inputs and..
441
+ /// /// adds them together, and then returns the result.
442
+ /// fn add(l: i32, r: i32) -> i32 {
443
+ /// l + r
444
+ /// }
445
+ /// ``````
446
+ ///
447
+ /// Use instead:
448
+ /// ```no_run
449
+ /// /// This command takes two numbers as inputs and \
450
+ /// /// adds them together, and then returns the result.
451
+ /// fn add(l: i32, r: i32) -> i32 {
452
+ /// l + r
453
+ /// }
454
+ /// ```
455
+ #[ clippy:: version = "1.80.0" ]
456
+ pub DOC_COMMENT_DOUBLE_SPACE_LINEBREAK ,
457
+ restriction,
458
+ "double-space used for doc comment linebreak instead of `\\ `"
459
+ }
460
+
425
461
pub struct Documentation {
426
462
valid_idents : & ' static FxHashSet < String > ,
427
463
check_private_items : bool ,
@@ -448,6 +484,7 @@ impl_lint_pass!(Documentation => [
448
484
SUSPICIOUS_DOC_COMMENTS ,
449
485
EMPTY_DOCS ,
450
486
DOC_LAZY_CONTINUATION ,
487
+ DOC_COMMENT_DOUBLE_SPACE_LINEBREAK
451
488
] ) ;
452
489
453
490
impl < ' tcx > LateLintPass < ' tcx > for Documentation {
@@ -569,6 +606,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
569
606
return None ;
570
607
}
571
608
609
+ //doc_comment_double_space_linebreak::check(cx, attrs);
572
610
suspicious_doc_comments:: check ( cx, attrs) ;
573
611
574
612
let ( fragments, _) = attrs_to_doc_fragments (
@@ -653,6 +691,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
653
691
let mut paragraph_range = 0 ..0 ;
654
692
let mut code_level = 0 ;
655
693
let mut blockquote_level = 0 ;
694
+ let mut prev_text: Option < ( Span , CowStr < ' _ > ) > = None ;
695
+ let mut collected_breaks: Vec < ( Span , ( Span , CowStr < ' _ > ) , Cow < ' _ , str > ) > = Vec :: new ( ) ;
656
696
657
697
let mut containers = Vec :: new ( ) ;
658
698
@@ -767,8 +807,20 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
767
807
span,
768
808
) ;
769
809
}
810
+
811
+ if let Some ( span) = fragments. span ( cx, range. clone ( ) )
812
+ && let Some ( ref p) = prev_text
813
+ && let snippet = snippet ( cx, span, ".." )
814
+ && !snippet. trim ( ) . starts_with ( "\\ " )
815
+ && event == HardBreak {
816
+ collected_breaks. push ( ( span, p. clone ( ) , snippet) ) ;
817
+ prev_text = None ;
818
+ }
770
819
} ,
771
820
Text ( text) => {
821
+ if let Some ( span) = fragments. span ( cx, range. clone ( ) ) {
822
+ prev_text = Some ( ( span, text. clone ( ) ) ) ;
823
+ }
772
824
paragraph_range. end = range. end ;
773
825
let range_ = range. clone ( ) ;
774
826
ticks_unbalanced |= text. contains ( '`' )
@@ -816,6 +868,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
816
868
FootnoteReference ( _) => { }
817
869
}
818
870
}
871
+
872
+ doc_comment_double_space_linebreak:: check ( cx, collected_breaks) ;
873
+
819
874
headers
820
875
}
821
876
0 commit comments