diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2025-09-10 15:44:42 +0200 |
|---|---|---|
| committer | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2025-09-10 18:44:20 +0200 |
| commit | 5a36fe23879ee8dde1326bcf08f0016af6ccd896 (patch) | |
| tree | f4290d660916ab1db3c340f11fac13affea86f18 /src | |
| parent | be8de5d6a0fc5cb2924e174a809a0aff303f281a (diff) | |
| download | rust-5a36fe23879ee8dde1326bcf08f0016af6ccd896.tar.gz rust-5a36fe23879ee8dde1326bcf08f0016af6ccd896.zip | |
Improve suggestion in case a bare URL is surrounded by brackets
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustdoc/passes/lint/bare_urls.rs | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index f70bdf4e4fe..ffa160beae3 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -17,7 +17,10 @@ use crate::core::DocContext; use crate::html::markdown::main_body_opts; pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) { - let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| { + let report_diag = |cx: &DocContext<'_>, + msg: &'static str, + range: Range<usize>, + without_brackets: Option<&str>| { let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings) .map(|(sp, _)| sp); let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx)); @@ -27,14 +30,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & // The fallback of using the attribute span is suitable for // highlighting where the error is, but not for placing the < and > if let Some(sp) = maybe_sp { - lint.multipart_suggestion( - "use an automatic link instead", - vec![ - (sp.shrink_to_lo(), "<".to_string()), - (sp.shrink_to_hi(), ">".to_string()), - ], - Applicability::MachineApplicable, - ); + if let Some(without_brackets) = without_brackets { + lint.multipart_suggestion( + "use an automatic link instead", + vec![(sp, format!("<{without_brackets}>"))], + Applicability::MachineApplicable, + ); + } else { + lint.multipart_suggestion( + "use an automatic link instead", + vec![ + (sp.shrink_to_lo(), "<".to_string()), + (sp.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } } }); }; @@ -43,7 +54,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & while let Some((event, range)) = p.next() { match event { - Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag), + Event::Text(s) => find_raw_urls(cx, dox, &s, range, &report_diag), // We don't want to check the text inside code blocks or links. Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => { for (event, _) in p.by_ref() { @@ -67,25 +78,41 @@ static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| { r"https?://", // url scheme r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains r"[a-zA-Z]{2,63}", // root domain - r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments + r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)", // optional query or url fragments )) .expect("failed to build regex") }); fn find_raw_urls( cx: &DocContext<'_>, + whole_text: &str, text: &str, range: Range<usize>, - f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>), + f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>, Option<&str>), ) { trace!("looking for raw urls in {text}"); // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). for match_ in URL_REGEX.find_iter(text) { let url_range = match_.range(); + let mut without_brackets = None; + let mut extra_range = 0; + // If the whole text is contained inside `[]`, then we need to replace the brackets and + // not just add `<>`. + if whole_text[..range.start + url_range.start].ends_with('[') + && range.start + url_range.end <= whole_text.len() + && whole_text[range.start + url_range.end..].starts_with(']') + { + extra_range = 1; + without_brackets = Some(match_.as_str()); + } f( cx, "this URL is not a hyperlink", - Range { start: range.start + url_range.start, end: range.start + url_range.end }, + Range { + start: range.start + url_range.start - extra_range, + end: range.start + url_range.end + extra_range, + }, + without_brackets, ); } } |
