1
1
use rustc_data_structures:: sync:: { Lock , Lrc } ;
2
2
use rustc_errors:: { emitter:: Emitter , Applicability , Diagnostic , Handler } ;
3
+ use rustc_middle:: lint:: LintDiagnosticBuilder ;
3
4
use rustc_parse:: parse_stream_from_source_str;
5
+ use rustc_session:: lint;
4
6
use rustc_session:: parse:: ParseSess ;
5
7
use rustc_span:: source_map:: { FilePathMapping , SourceMap } ;
6
8
use rustc_span:: { FileName , InnerSpan } ;
@@ -47,50 +49,65 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
47
49
. unwrap_or ( false ) ;
48
50
let buffer = buffer. borrow ( ) ;
49
51
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"
59
85
} else {
60
- ( "Rust code block is empty" , false )
86
+ "Rust code block is empty"
61
87
} ;
62
88
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
+ } ;
64
98
65
- if code_block. syntax . is_none ( ) && code_block. is_fenced {
66
- let sp = sp. from_inner ( InnerSpan :: new ( 0 , 3 ) ) ;
67
99
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 ,
70
102
String :: from ( "```text" ) ,
71
103
Applicability :: MachineApplicable ,
72
104
) ;
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
- ) ;
82
105
}
83
106
84
107
diag
85
108
} 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 {
94
111
diag. help ( "mark blocks that do not contain Rust code as text: ```text" ) ;
95
112
}
96
113
@@ -103,7 +120,17 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
103
120
}
104
121
105
122
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
+ ) ;
107
134
}
108
135
}
109
136
0 commit comments