Change:
Consider this code: In the generated docs, the link on the page appears as , with the correct link, but without the parentheses.
Sorry, I stole this from you :smile:
That's okay! Thanks for fixing this :)

Discussion:
} // Parse and strip the disambiguator from the link, if present. <del> let (path_str, disambiguator) = match Disambiguator::from_str(&link) { Ok(Some((d, path))) => (path.trim(), Some(d)), Ok(None) => (link.trim(), None), </del> <ins> let (disambiguator, path_str, link_text) = match Disambiguator::from_str(&link) { Ok(Some((d, path, link_text))) => (Some(d), path.trim(), link_text.trim()), Ok(None) => (None, link.trim(), link.trim()), </ins> Err((err_msg, relative_range)) => { // Only report error if we would not have ignored this link. See issue #83859. if !should_ignore_link_with_disambiguators(link) {

return None; } <del> // We stripped `()` and `!` when parsing the disambiguator. // Add them back to be displayed, but not prefix disambiguators. let link_text = disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned()); </del> // Strip generics from the path. let path_str = if path_str.contains(['<', '>'].as_slice()) { match strip_generics_from_path(&path_str) {

path_str, disambiguator, extra_fragment: extra_fragment.map(String::from), <del> link_text, </del> <ins> link_text: link_text.to_owned(), </ins> })) }

} impl Disambiguator { <del> /// The text that should be displayed when the path is rendered as HTML. /// /// NOTE: `path` is not the original link given by the user, but a name suitable for passing to `resolve`. fn display_for(&self, path: &str) -> String { match self { // FIXME: this will have different output if the user had `m!()` originally. Self::Kind(DefKind::Macro(MacroKind::Bang)) => format!("{}!", path), Self::Kind(DefKind::Fn) => format!("{}()", path), _ => path.to_owned(), } } /// Given a link, parse and return `(disambiguator, path_str)`. </del> <ins> /// Given a link, parse and return `(disambiguator, path_str, link_text)`. </ins> /// /// This returns `Ok(Some(...))` if a disambiguator was found, /// `Ok(None)` if no disambiguator was found, or `Err(...)` /// if there was a problem with the disambiguator. <del> fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> { </del> <ins> fn from_str(link: &str) -> Result<Option<(Self, &str, &str)>, (String, Range<usize>)> { </ins> use Disambiguator::{Kind, Namespace as NS, Primitive}; if let Some(idx) = link.find('@') {

"prim" | "primitive" => Primitive, _ => return Err((format!("unknown disambiguator `{}`", prefix), 0..idx)), }; <del> Ok(Some((d, &rest[1..]))) </del> <ins> Ok(Some((d, &rest[1..], &rest[1..]))) </ins> } else { let suffixes = [ ("!()", DefKind::Macro(MacroKind::Bang)), <ins> ("!{}", DefKind::Macro(MacroKind::Bang)), ("![]", DefKind::Macro(MacroKind::Bang)), </ins> ("()", DefKind::Fn), ("!", DefKind::Macro(MacroKind::Bang)), ]; for (suffix, kind) in suffixes { <del> if let Some(link) = link.strip_suffix(suffix) { </del> <ins> if let Some(path_str) = link.strip_suffix(suffix) { </ins> // Avoid turning `!` or `()` into an empty string <del> if !link.is_empty() { return Ok(Some((Kind(kind), link))); </del> <ins> if !path_str.is_empty() { return Ok(Some((Kind(kind), path_str, link))); </ins> } } }

<ins> #![crate_name = "foo"] #![deny(rustdoc::broken_intra_doc_links)] //! [foo!()] // @has foo/index.html '//a[@href="macro.foo.html"]' 'foo!()' //! [foo!{}] // @has - '//a[@href="macro.foo.html"]' 'foo!{}' //! [foo![]](foo![]) // @has - '//a[@href="macro.foo.html"]' 'foo![]' //! [foo1](foo!()) // @has - '//a[@href="macro.foo.html"]' 'foo1' //! [foo2](foo!{}) // @has - '//a[@href="macro.foo.html"]' 'foo2' //! [foo3](foo![]) // @has - '//a[@href="macro.foo.html"]' 'foo3' #[macro_export] macro_rules! foo { () => {}; } </ins>