11use rustc_data_structures:: sync:: { Lock , Lrc } ;
22use rustc_errors:: { emitter:: Emitter , Applicability , Diagnostic , Handler } ;
3+ use rustc_middle:: lint:: LintDiagnosticBuilder ;
34use rustc_parse:: parse_stream_from_source_str;
45use rustc_session:: parse:: ParseSess ;
56use rustc_span:: source_map:: { FilePathMapping , SourceMap } ;
@@ -47,50 +48,65 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
4748 . unwrap_or ( false ) ;
4849 let buffer = buffer. borrow ( ) ;
4950
50- if buffer. has_errors || is_empty {
51- let mut diag = if let Some ( sp) = super :: source_span_for_markdown_range (
52- self . cx . tcx ,
53- & dox,
54- & code_block. range ,
55- & item. attrs ,
56- ) {
57- let ( warning_message, suggest_using_text) = if buffer. has_errors {
58- ( "could not parse code block as Rust code" , true )
51+ if !( buffer. has_errors || is_empty) {
52+ // No errors in a non-empty program.
53+ return ;
54+ }
55+
56+ let local_id = match item. def_id . as_local ( ) {
57+ Some ( id) => id,
58+ // We don't need to check the syntax for other crates so returning
59+ // without doing anything should not be a problem.
60+ None => return ,
61+ } ;
62+
63+ let hir_id = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( local_id) ;
64+ let suggest_using_text = code_block. syntax . is_none ( ) && code_block. is_fenced ;
65+ let is_ignore = code_block. is_ignore ;
66+
67+ // The span and whether it is precise or not.
68+ let ( sp, precise_span) = match super :: source_span_for_markdown_range (
69+ self . cx . tcx ,
70+ & dox,
71+ & code_block. range ,
72+ & item. attrs ,
73+ ) {
74+ Some ( sp) => ( sp, true ) ,
75+ None => ( item. attr_span ( self . cx . tcx ) , false ) ,
76+ } ;
77+
78+ // lambda that will use the lint to start a new diagnostic and add
79+ // a suggestion to it when needed.
80+ let diag_builder = |lint : LintDiagnosticBuilder < ' _ > | {
81+ let mut diag = if precise_span {
82+ let msg = if buffer. has_errors {
83+ "could not parse code block as Rust code"
5984 } else {
60- ( "Rust code block is empty" , false )
85+ "Rust code block is empty"
6186 } ;
6287
63- let mut diag = self . cx . sess ( ) . struct_span_warn ( sp, warning_message) ;
88+ let mut diag = lint. build ( msg) ;
89+
90+ if suggest_using_text {
91+ let extended_msg = if is_ignore {
92+ "`ignore` code blocks require valid Rust code for syntax highlighting. \
93+ Mark blocks that do not contain Rust code as text"
94+ } else {
95+ "mark blocks that do not contain Rust code as text"
96+ } ;
6497
65- if code_block. syntax . is_none ( ) && code_block. is_fenced {
66- let sp = sp. from_inner ( InnerSpan :: new ( 0 , 3 ) ) ;
6798 diag. span_suggestion (
68- sp,
69- "mark blocks that do not contain Rust code as text" ,
99+ sp. from_inner ( InnerSpan :: new ( 0 , 3 ) ) ,
100+ extended_msg ,
70101 String :: from ( "```text" ) ,
71102 Applicability :: MachineApplicable ,
72103 ) ;
73- } else if suggest_using_text && code_block. is_ignore {
74- let sp = sp. from_inner ( InnerSpan :: new ( 0 , 3 ) ) ;
75- diag. span_suggestion (
76- sp,
77- "`ignore` code blocks require valid Rust code for syntax highlighting. \
78- Mark blocks that do not contain Rust code as text",
79- String :: from ( "```text," ) ,
80- Applicability :: MachineApplicable ,
81- ) ;
82104 }
83105
84106 diag
85107 } else {
86- // We couldn't calculate the span of the markdown block that had the error, so our
87- // diagnostics are going to be a bit lacking.
88- let mut diag = self . cx . sess ( ) . struct_span_warn (
89- item. attr_span ( self . cx . tcx ) ,
90- "doc comment contains an invalid Rust code block" ,
91- ) ;
92-
93- if code_block. syntax . is_none ( ) && code_block. is_fenced {
108+ let mut diag = lint. build ( "doc comment contains an invalid Rust code block" ) ;
109+ if suggest_using_text {
94110 diag. help ( "mark blocks that do not contain Rust code as text: ```text" ) ;
95111 }
96112
@@ -103,7 +119,17 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
103119 }
104120
105121 diag. emit ( ) ;
106- }
122+ } ;
123+
124+ // Finally build and emit the completed diagnostic.
125+ // All points of divergence have been handled earlier so this can be
126+ // done the same way whether the span is precise or not.
127+ self . cx . tcx . struct_span_lint_hir (
128+ crate :: lint:: INVALID_RUST_CODEBLOCK ,
129+ hir_id,
130+ sp,
131+ diag_builder,
132+ ) ;
107133 }
108134}
109135
0 commit comments