Skip to content

Commit 22c6c53

Browse files
authored
Merge pull request github#12434 from aibaars/diagnostics-links
Ruby: add some links to diagnostic messages
2 parents 29ee1bd + 2d6f3ed commit 22c6c53

File tree

4 files changed

+83
-40
lines changed

4 files changed

+83
-40
lines changed

ruby/extractor/src/diagnostics.rs

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ fn longest_backtick_sequence_length(text: &str) -> usize {
214214
}
215215
result
216216
}
217+
/**
218+
* An argument of a diagnostic message format string. A message argument is either a "code" snippet or a link.
219+
*/
220+
pub enum MessageArg<'a> {
221+
Code(&'a str),
222+
Link(&'a str, &'a str),
223+
}
224+
217225
impl DiagnosticMessage {
218226
pub fn full_error_message(&self) -> String {
219227
match &self.location {
@@ -236,26 +244,39 @@ impl DiagnosticMessage {
236244
self
237245
}
238246

239-
pub fn message(&mut self, text: &str, args: &[&str]) -> &mut Self {
247+
pub fn message(&mut self, text: &str, args: &[MessageArg]) -> &mut Self {
240248
let parts = text.split("{}");
241-
let args = args.iter().chain(std::iter::repeat(&""));
242249
let mut plain = String::with_capacity(2 * text.len());
243250
let mut markdown = String::with_capacity(2 * text.len());
244-
for (p, a) in parts.zip(args) {
251+
for (i, p) in parts.enumerate() {
245252
plain.push_str(p);
246-
plain.push_str(a);
247253
markdown.push_str(p);
248-
if a.len() > 0 {
249-
let count = longest_backtick_sequence_length(a) + 1;
250-
markdown.push_str(&"`".repeat(count));
251-
if count > 1 {
252-
markdown.push_str(" ");
254+
match args.get(i) {
255+
Some(MessageArg::Code(t)) => {
256+
plain.push_str(t);
257+
if t.len() > 0 {
258+
let count = longest_backtick_sequence_length(t) + 1;
259+
markdown.push_str(&"`".repeat(count));
260+
if count > 1 {
261+
markdown.push_str(" ");
262+
}
263+
markdown.push_str(t);
264+
if count > 1 {
265+
markdown.push_str(" ");
266+
}
267+
markdown.push_str(&"`".repeat(count));
268+
}
253269
}
254-
markdown.push_str(a);
255-
if count > 1 {
256-
markdown.push_str(" ");
270+
Some(MessageArg::Link(text, url)) => {
271+
plain.push_str(text);
272+
self.help_link(url);
273+
markdown.push_str("[");
274+
markdown.push_str(text);
275+
markdown.push_str("](");
276+
markdown.push_str(url);
277+
markdown.push_str(")");
257278
}
258-
markdown.push_str(&"`".repeat(count));
279+
None => {}
259280
}
260281
}
261282
self.text(&plain);
@@ -323,14 +344,17 @@ fn test_message() {
323344
let mut m = DiagnosticLoggers::new("foo")
324345
.logger()
325346
.new_entry("id", "name");
326-
m.message("hello: {}", &["hello"]);
347+
m.message("hello: {}", &[MessageArg::Code("hello")]);
327348
assert_eq!("hello: hello", m.plaintext_message);
328349
assert_eq!("hello: `hello`", m.markdown_message);
329350

330351
let mut m = DiagnosticLoggers::new("foo")
331352
.logger()
332353
.new_entry("id", "name");
333-
m.message("hello with backticks: {}", &["oh `hello`!"]);
354+
m.message(
355+
"hello with backticks: {}",
356+
&[MessageArg::Code("oh `hello`!")],
357+
);
334358
assert_eq!("hello with backticks: oh `hello`!", m.plaintext_message);
335359
assert_eq!(
336360
"hello with backticks: `` oh `hello`! ``",

ruby/extractor/src/extractor.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ impl<'a> Visitor<'a> {
277277
fn record_parse_error_for_node(
278278
&mut self,
279279
message: &str,
280-
args: &[&str],
280+
args: &[diagnostics::MessageArg],
281281
node: Node,
282282
status_page: bool,
283283
) {
@@ -306,17 +306,17 @@ impl<'a> Visitor<'a> {
306306
fn enter_node(&mut self, node: Node) -> bool {
307307
if node.is_missing() {
308308
self.record_parse_error_for_node(
309-
"A parse error occurred (expected {} symbol). Check the syntax of the file using the {} command. If the file is invalid, correct the error or exclude the file from analysis.",
310-
&[node.kind(), "ruby -c"],
309+
"A parse error occurred (expected {} symbol). Check the syntax of the file. If the file is invalid, correct the error or {} the file from analysis.",
310+
&[diagnostics::MessageArg::Code(node.kind()), diagnostics::MessageArg::Link("exclude", "https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning")],
311311
node,
312312
true,
313313
);
314314
return false;
315315
}
316316
if node.is_error() {
317317
self.record_parse_error_for_node(
318-
"A parse error occurred. Check the syntax of the file using the {} command. If the file is invalid, correct the error or exclude the file from analysis.",
319-
&["ruby -c"],
318+
"A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or {} the file from analysis.",
319+
&[diagnostics::MessageArg::Link("exclude", "https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning")],
320320
node,
321321
true,
322322
);
@@ -407,7 +407,10 @@ impl<'a> Visitor<'a> {
407407
.new_entry("parse-error", "Parse error")
408408
.severity(diagnostics::Severity::Error)
409409
.location(self.path, start_line, start_column, end_line, end_column)
410-
.message("Unknown table type: {}", &[node.kind()]),
410+
.message(
411+
"Unknown table type: {}",
412+
&[diagnostics::MessageArg::Code(node.kind())],
413+
),
411414
);
412415

413416
valid = false;
@@ -458,10 +461,10 @@ impl<'a> Visitor<'a> {
458461
self.record_parse_error_for_node(
459462
"Type mismatch for field {}::{} with type {} != {}",
460463
&[
461-
node.kind(),
462-
child_node.field_name.unwrap_or("child"),
463-
&format!("{:?}", child_node.type_name),
464-
&format!("{:?}", field.type_info),
464+
diagnostics::MessageArg::Code(node.kind()),
465+
diagnostics::MessageArg::Code(child_node.field_name.unwrap_or("child")),
466+
diagnostics::MessageArg::Code(&format!("{:?}", child_node.type_name)),
467+
diagnostics::MessageArg::Code(&format!("{:?}", field.type_info)),
465468
],
466469
*node,
467470
false,
@@ -471,9 +474,9 @@ impl<'a> Visitor<'a> {
471474
self.record_parse_error_for_node(
472475
"Value for unknown field: {}::{} and type {}",
473476
&[
474-
node.kind(),
475-
&child_node.field_name.unwrap_or("child"),
476-
&format!("{:?}", child_node.type_name),
477+
diagnostics::MessageArg::Code(node.kind()),
478+
diagnostics::MessageArg::Code(&child_node.field_name.unwrap_or("child")),
479+
diagnostics::MessageArg::Code(&format!("{:?}", child_node.type_name)),
477480
],
478481
*node,
479482
false,
@@ -512,7 +515,10 @@ impl<'a> Visitor<'a> {
512515
if !*has_index && index > 0 {
513516
self.record_parse_error_for_node(
514517
"Too many values for field: {}::{}",
515-
&[node.kind(), table_name],
518+
&[
519+
diagnostics::MessageArg::Code(node.kind()),
520+
diagnostics::MessageArg::Code(table_name),
521+
],
516522
*node,
517523
false,
518524
);
@@ -629,8 +635,11 @@ fn location_for(visitor: &mut Visitor, n: Node) -> (usize, usize, usize, usize)
629635
.diagnostics_writer
630636
.new_entry("internal-error", "Internal error")
631637
.message(
632-
"Cannot correct end column value: end_byte index {} is not in range [1,{}]",
633-
&[&index.to_string(), &source.len().to_string()],
638+
"Cannot correct end column value: end_byte index {} is not in range [1,{}].",
639+
&[
640+
diagnostics::MessageArg::Code(&index.to_string()),
641+
diagnostics::MessageArg::Code(&source.len().to_string()),
642+
],
634643
)
635644
.severity(diagnostics::Severity::Error),
636645
);

ruby/extractor/src/main.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ fn main() -> std::io::Result<()> {
7474
main_thread_logger.write(
7575
main_thread_logger
7676
.new_entry("configuration-error", "Configuration error")
77-
.message("{}; defaulting to 1 thread.", &[&e])
77+
.message(
78+
"{}; defaulting to 1 thread.",
79+
&[diagnostics::MessageArg::Code(&e)],
80+
)
7881
.severity(diagnostics::Severity::Warning),
7982
);
8083
1
@@ -95,7 +98,7 @@ fn main() -> std::io::Result<()> {
9598
main_thread_logger.write(
9699
main_thread_logger
97100
.new_entry("configuration-error", "Configuration error")
98-
.message("{}; using gzip.", &[&e])
101+
.message("{}; using gzip.", &[diagnostics::MessageArg::Code(&e)])
99102
.severity(diagnostics::Severity::Warning),
100103
);
101104
trap::Compression::Gzip
@@ -203,11 +206,15 @@ fn main() -> std::io::Result<()> {
203206
)
204207
.file(&path.to_string_lossy())
205208
.message(
206-
"Could not decode the file contents as {}: {}. The contents of the file must match the character encoding specified in the {} directive.",
207-
&[&encoding_name, &msg, "encoding:"],
209+
"Could not decode the file contents as {}: {}. The contents of the file must match the character encoding specified in the {} {}.",
210+
&[
211+
diagnostics::MessageArg::Code(&encoding_name),
212+
diagnostics::MessageArg::Code(&msg),
213+
diagnostics::MessageArg::Code("encoding:"),
214+
diagnostics::MessageArg::Link("directive", "https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
215+
],
208216
)
209217
.status_page()
210-
.help_link("https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
211218
.severity(diagnostics::Severity::Warning),
212219
);
213220
}
@@ -219,11 +226,14 @@ fn main() -> std::io::Result<()> {
219226
.new_entry("unknown-character-encoding", "Unknown character encoding")
220227
.file(&path.to_string_lossy())
221228
.message(
222-
"Unknown character encoding {} in {} directive.",
223-
&[&encoding_name, "#encoding:"],
229+
"Unknown character encoding {} in {} {}.",
230+
&[
231+
diagnostics::MessageArg::Code(&encoding_name),
232+
diagnostics::MessageArg::Code("#encoding:"),
233+
diagnostics::MessageArg::Link("directive", "https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
234+
],
224235
)
225236
.status_page()
226-
.help_link("https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
227237
.severity(diagnostics::Severity::Warning),
228238
);
229239
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
| src/not_ruby.rb:5:25:5:26 | A parse error occurred. Check the syntax of the file using the ruby -c command. If the file is invalid, correct the error or exclude the file from analysis. | Extraction failed in src/not_ruby.rb with error A parse error occurred. Check the syntax of the file using the ruby -c command. If the file is invalid, correct the error or exclude the file from analysis. | 2 |
1+
| src/not_ruby.rb:5:25:5:26 | A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or exclude the file from analysis. | Extraction failed in src/not_ruby.rb with error A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or exclude the file from analysis. | 2 |

0 commit comments

Comments
 (0)