@@ -38,7 +38,7 @@ use std::sync::{Arc, Weak};
3838use  pulldown_cmark:: { 
3939    BrokenLink ,  CodeBlockKind ,  CowStr ,  Event ,  LinkType ,  Options ,  Parser ,  Tag ,  TagEnd ,  html, 
4040} ; 
41- use  rustc_data_structures:: fx:: FxHashMap ; 
41+ use  rustc_data_structures:: fx:: { FxHashMap ,   FxIndexMap } ; 
4242use  rustc_errors:: { Diag ,  DiagMessage } ; 
4343use  rustc_hir:: def_id:: LocalDefId ; 
4444use  rustc_middle:: ty:: TyCtxt ; 
@@ -1763,6 +1763,46 @@ pub(crate) fn markdown_links<'md, R>(
17631763        } 
17641764    } ; 
17651765
1766+     let  span_for_refdef = |link :  & CowStr < ' _ > ,  span :  Range < usize > | { 
1767+         // We want to underline the link's definition, but `span` will point at the entire refdef. 
1768+         // Skip the label, then try to find the entire URL. 
1769+         let  mut  square_brace_count = 0 ; 
1770+         let  mut  iter = md. as_bytes ( ) [ span. start ..span. end ] . iter ( ) . copied ( ) . enumerate ( ) ; 
1771+         for  ( _i,  c)  in  & mut  iter { 
1772+             match  c { 
1773+                 b':'  if  square_brace_count == 0  => break , 
1774+                 b'['  => square_brace_count += 1 , 
1775+                 b']'  => square_brace_count -= 1 , 
1776+                 _ => { } 
1777+             } 
1778+         } 
1779+         while  let  Some ( ( i,  c) )  = iter. next ( )  { 
1780+             if  c == b'<'  { 
1781+                 while  let  Some ( ( j,  c) )  = iter. next ( )  { 
1782+                     match  c { 
1783+                         b'\\'  => { 
1784+                             let  _ = iter. next ( ) ; 
1785+                         } 
1786+                         b'>'  => { 
1787+                             return  MarkdownLinkRange :: Destination ( 
1788+                                 i + 1  + span. start ..j + span. start , 
1789+                             ) ; 
1790+                         } 
1791+                         _ => { } 
1792+                     } 
1793+                 } 
1794+             }  else  if  !c. is_ascii_whitespace ( )  { 
1795+                 while  let  Some ( ( j,  c) )  = iter. next ( )  { 
1796+                     if  c. is_ascii_whitespace ( )  { 
1797+                         return  MarkdownLinkRange :: Destination ( i + span. start ..j + span. start ) ; 
1798+                     } 
1799+                 } 
1800+                 return  MarkdownLinkRange :: Destination ( i + span. start ..span. end ) ; 
1801+             } 
1802+         } 
1803+         span_for_link ( link,  span) 
1804+     } ; 
1805+ 
17661806    let  span_for_offset_backward = |span :  Range < usize > ,  open :  u8 ,  close :  u8 | { 
17671807        let  mut  open_brace = !0 ; 
17681808        let  mut  close_brace = !0 ; 
@@ -1844,9 +1884,16 @@ pub(crate) fn markdown_links<'md, R>(
18441884    . into_offset_iter ( ) ; 
18451885    let  mut  links = Vec :: new ( ) ; 
18461886
1887+     let  mut  refdefs = FxIndexMap :: default ( ) ; 
1888+     for  ( label,  refdef)  in  event_iter. reference_definitions ( ) . iter ( )  { 
1889+         refdefs. insert ( label. to_string ( ) ,  ( false ,  refdef. dest . to_string ( ) ,  refdef. span . clone ( ) ) ) ; 
1890+     } 
1891+ 
18471892    for  ( event,  span)  in  event_iter { 
18481893        match  event { 
1849-             Event :: Start ( Tag :: Link  {  link_type,  dest_url,  .. } )  if  may_be_doc_link ( link_type)  => { 
1894+             Event :: Start ( Tag :: Link  {  link_type,  dest_url,  id,  .. } ) 
1895+                 if  may_be_doc_link ( link_type)  =>
1896+             { 
18501897                let  range = match  link_type { 
18511898                    // Link is pulled from the link itself. 
18521899                    LinkType :: ReferenceUnknown  | LinkType :: ShortcutUnknown  => { 
@@ -1856,7 +1903,12 @@ pub(crate) fn markdown_links<'md, R>(
18561903                    LinkType :: Inline  => span_for_offset_backward ( span,  b'(' ,  b')' ) , 
18571904                    // Link is pulled from elsewhere in the document. 
18581905                    LinkType :: Reference  | LinkType :: Collapsed  | LinkType :: Shortcut  => { 
1859-                         span_for_link ( & dest_url,  span) 
1906+                         if  let  Some ( ( is_used,  dest_url,  span) )  = refdefs. get_mut ( & id[ ..] )  { 
1907+                             * is_used = true ; 
1908+                             span_for_refdef ( & CowStr :: from ( & dest_url[ ..] ) ,  span. clone ( ) ) 
1909+                         }  else  { 
1910+                             span_for_link ( & dest_url,  span) 
1911+                         } 
18601912                    } 
18611913                    LinkType :: Autolink  | LinkType :: Email  => unreachable ! ( ) , 
18621914                } ; 
@@ -1873,6 +1925,18 @@ pub(crate) fn markdown_links<'md, R>(
18731925        } 
18741926    } 
18751927
1928+     for  ( _label,  ( is_used,  dest_url,  span) )  in  refdefs. into_iter ( )  { 
1929+         if  !is_used
1930+             && let  Some ( link)  = preprocess_link ( MarkdownLink  { 
1931+                 kind :  LinkType :: Reference , 
1932+                 range :  span_for_refdef ( & CowStr :: from ( & dest_url[ ..] ) ,  span) , 
1933+                 link :  dest_url, 
1934+             } ) 
1935+         { 
1936+             links. push ( link) ; 
1937+         } 
1938+     } 
1939+ 
18761940    links
18771941} 
18781942
0 commit comments