|
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,51 +49,76 @@ 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) = |
52 |
| - super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) |
53 |
| - { |
54 |
| - let warning_message = if buffer.has_errors { |
| 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 mark_with_text = code_block.syntax.is_none() && code_block.is_fenced; |
| 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, |
| 70 | + &dox, |
| 71 | + &code_block.range, |
| 72 | + &item.attrs, |
| 73 | + ) { |
| 74 | + Some(sp) => (sp, true), |
| 75 | + None => (super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), 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 { |
55 | 83 | "could not parse code block as Rust code"
|
56 | 84 | } else {
|
57 | 85 | "Rust code block is empty"
|
58 | 86 | };
|
59 | 87 |
|
60 |
| - let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); |
61 |
| - |
62 |
| - if code_block.syntax.is_none() && code_block.is_fenced { |
63 |
| - let sp = sp.from_inner(InnerSpan::new(0, 3)); |
| 88 | + let mut diag = lint.build(msg); |
| 89 | + if mark_with_text { |
64 | 90 | diag.span_suggestion(
|
65 |
| - sp, |
| 91 | + sp.from_inner(InnerSpan::new(0, 3)), |
66 | 92 | "mark blocks that do not contain Rust code as text",
|
67 | 93 | String::from("```text"),
|
68 | 94 | Applicability::MachineApplicable,
|
69 | 95 | );
|
70 | 96 | }
|
71 |
| - |
72 | 97 | diag
|
73 | 98 | } else {
|
74 |
| - // We couldn't calculate the span of the markdown block that had the error, so our |
75 |
| - // diagnostics are going to be a bit lacking. |
76 |
| - let mut diag = self.cx.sess().struct_span_warn( |
77 |
| - super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), |
78 |
| - "doc comment contains an invalid Rust code block", |
79 |
| - ); |
80 |
| - |
81 |
| - if code_block.syntax.is_none() && code_block.is_fenced { |
| 99 | + let mut diag = lint.build("doc comment contains an invalid Rust code block"); |
| 100 | + if mark_with_text { |
82 | 101 | diag.help("mark blocks that do not contain Rust code as text: ```text");
|
83 | 102 | }
|
84 | 103 |
|
85 | 104 | diag
|
86 | 105 | };
|
87 |
| - |
88 | 106 | // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
|
89 | 107 | for message in buffer.messages.iter() {
|
90 | 108 | diag.note(&message);
|
91 | 109 | }
|
92 |
| - |
93 | 110 | diag.emit();
|
94 |
| - } |
| 111 | + }; |
| 112 | + |
| 113 | + // Finally build and emit the completed diagnostic. |
| 114 | + // All points of divergence have been handled earlier so this can be |
| 115 | + // done the same way whether the span is precise or not. |
| 116 | + self.cx.tcx.struct_span_lint_hir( |
| 117 | + lint::builtin::INVALID_RUST_CODEBLOCK, |
| 118 | + hir_id, |
| 119 | + sp, |
| 120 | + diag_builder, |
| 121 | + ); |
95 | 122 | }
|
96 | 123 | }
|
97 | 124 |
|
|
0 commit comments