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;
5+ use rustc_session:: lint;
46use rustc_session:: parse:: ParseSess ;
57use rustc_span:: source_map:: { FilePathMapping , SourceMap } ;
68use rustc_span:: { FileName , InnerSpan } ;
@@ -47,50 +49,65 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
4749 . unwrap_or ( false ) ;
4850 let buffer = buffer. borrow ( ) ;
4951
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 )
52+ if !( buffer. has_errors || is_empty) {
53+ // No errors in a non-empty program.
54+ return ;
55+ }
56+
57+ let local_id = match item. def_id . as_local ( ) {
58+ Some ( id) => id,
59+ // We don't need to check the syntax for other crates so returning
60+ // without doing anything should not be a problem.
61+ None => return ,
62+ } ;
63+
64+ let hir_id = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( local_id) ;
65+ let suggest_using_text = code_block. syntax . is_none ( ) && code_block. is_fenced ;
66+ let is_ignore = code_block. is_ignore ;
67+
68+ // The span and whether it is precise or not.
69+ let ( sp, precise_span) = match super :: source_span_for_markdown_range (
70+ self . cx . tcx ,
71+ & dox,
72+ & code_block. range ,
73+ & item. attrs ,
74+ ) {
75+ Some ( sp) => ( sp, true ) ,
76+ None => ( super :: span_of_attrs ( & item. attrs ) . unwrap_or ( item. source . span ( ) ) , false ) ,
77+ } ;
78+
79+ // lambda that will use the lint to start a new diagnostic and add
80+ // a suggestion to it when needed.
81+ let diag_builder = |lint : LintDiagnosticBuilder < ' _ > | {
82+ let mut diag = if precise_span {
83+ let msg = if buffer. has_errors {
84+ "could not parse code block as Rust code"
5985 } else {
60- ( "Rust code block is empty" , false )
86+ "Rust code block is empty"
6187 } ;
6288
63- let mut diag = self . cx . sess ( ) . struct_span_warn ( sp, warning_message) ;
89+ let mut diag = lint. build ( msg) ;
90+
91+ if suggest_using_text {
92+ let extended_msg = if is_ignore {
93+ "`ignore` code blocks require valid Rust code for syntax highlighting. \
94+ Mark blocks that do not contain Rust code as text"
95+ } else {
96+ "mark blocks that do not contain Rust code as text"
97+ } ;
6498
65- if code_block. syntax . is_none ( ) && code_block. is_fenced {
66- let sp = sp. from_inner ( InnerSpan :: new ( 0 , 3 ) ) ;
6799 diag. span_suggestion (
68- sp,
69- "mark blocks that do not contain Rust code as text" ,
100+ sp. from_inner ( InnerSpan :: new ( 0 , 3 ) ) ,
101+ extended_msg ,
70102 String :: from ( "```text" ) ,
71103 Applicability :: MachineApplicable ,
72104 ) ;
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- ) ;
82105 }
83106
84107 diag
85108 } 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- super :: span_of_attrs ( & item. attrs ) . unwrap_or ( item. source . span ( ) ) ,
90- "doc comment contains an invalid Rust code block" ,
91- ) ;
92-
93- if code_block. syntax . is_none ( ) && code_block. is_fenced {
109+ let mut diag = lint. build ( "doc comment contains an invalid Rust code block" ) ;
110+ if suggest_using_text {
94111 diag. help ( "mark blocks that do not contain Rust code as text: ```text" ) ;
95112 }
96113
@@ -103,7 +120,17 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
103120 }
104121
105122 diag. emit ( ) ;
106- }
123+ } ;
124+
125+ // Finally build and emit the completed diagnostic.
126+ // All points of divergence have been handled earlier so this can be
127+ // done the same way whether the span is precise or not.
128+ self . cx . tcx . struct_span_lint_hir (
129+ lint:: builtin:: INVALID_RUST_CODEBLOCK ,
130+ hir_id,
131+ sp,
132+ diag_builder,
133+ ) ;
107134 }
108135}
109136
0 commit comments