22
33use std:: ops:: ControlFlow ;
44
5- use base_db:: FileId ;
65use hir_def:: {
76 attr:: AttrsWithOwner ,
87 item_scope:: ItemInNs ,
@@ -11,12 +10,8 @@ use hir_def::{
1110 resolver:: { HasResolver , Resolver , TypeNs } ,
1211 AssocItemId , AttrDefId , ModuleDefId ,
1312} ;
14- use hir_expand:: {
15- name:: Name ,
16- span_map:: { RealSpanMap , SpanMapRef } ,
17- } ;
13+ use hir_expand:: { mod_path:: PathKind , name:: Name } ;
1814use hir_ty:: { db:: HirDatabase , method_resolution} ;
19- use syntax:: { ast, AstNode } ;
2015
2116use crate :: {
2217 Adt , AsAssocItem , AssocItem , BuiltinType , Const , ConstParam , DocLinkDef , Enum , ExternCrateDecl ,
@@ -129,7 +124,7 @@ fn resolve_doc_path_on_(
129124 AttrDefId :: GenericParamId ( _) => return None ,
130125 } ;
131126
132- let mut modpath = modpath_from_str ( db , link) ?;
127+ let mut modpath = modpath_from_str ( link) ?;
133128
134129 let resolved = resolver. resolve_module_path_in_items ( db. upcast ( ) , & modpath) ;
135130 if resolved. is_none ( ) {
@@ -305,34 +300,37 @@ fn as_module_def_if_namespace_matches(
305300 ( ns. unwrap_or ( expected_ns) == expected_ns) . then ( || DocLinkDef :: ModuleDef ( def) )
306301}
307302
308- fn modpath_from_str ( db : & dyn HirDatabase , link : & str ) -> Option < ModPath > {
303+ fn modpath_from_str ( link : & str ) -> Option < ModPath > {
309304 // FIXME: this is not how we should get a mod path here.
310305 let try_get_modpath = |link : & str | {
311- let ast_path = ast:: SourceFile :: parse ( & format ! ( "type T = {link};" ) )
312- . syntax_node ( )
313- . descendants ( )
314- . find_map ( ast:: Path :: cast) ?;
315- if ast_path. syntax ( ) . text ( ) != link {
316- return None ;
317- }
318- ModPath :: from_src (
319- db. upcast ( ) ,
320- ast_path,
321- SpanMapRef :: RealSpanMap ( & RealSpanMap :: absolute ( FileId :: BOGUS ) ) ,
322- )
306+ let mut parts = link. split ( "::" ) ;
307+ let mut first_segment = None ;
308+ let kind = match parts. next ( ) ? {
309+ "" => PathKind :: Abs ,
310+ "crate" => PathKind :: Crate ,
311+ "self" => PathKind :: Super ( 0 ) ,
312+ "super" => {
313+ let mut deg = 1 ;
314+ while let Some ( segment) = parts. next ( ) {
315+ if segment == "super" {
316+ deg += 1 ;
317+ } else {
318+ first_segment = Some ( segment) ;
319+ break ;
320+ }
321+ }
322+ PathKind :: Super ( deg)
323+ }
324+ segment => {
325+ first_segment = Some ( segment) ;
326+ PathKind :: Plain
327+ }
328+ } ;
329+ let parts = first_segment. into_iter ( ) . chain ( parts) . map ( |segment| match segment. parse ( ) {
330+ Ok ( idx) => Name :: new_tuple_field ( idx) ,
331+ Err ( _) => Name :: new_text_dont_use ( segment. into ( ) ) ,
332+ } ) ;
333+ Some ( ModPath :: from_segments ( kind, parts) )
323334 } ;
324-
325- let full = try_get_modpath ( link) ;
326- if full. is_some ( ) {
327- return full;
328- }
329-
330- // Tuple field names cannot be a part of `ModPath` usually, but rustdoc can
331- // resolve doc paths like `TupleStruct::0`.
332- // FIXME: Find a better way to handle these.
333- let ( base, maybe_tuple_field) = link. rsplit_once ( "::" ) ?;
334- let tuple_field = Name :: new_tuple_field ( maybe_tuple_field. parse ( ) . ok ( ) ?) ;
335- let mut modpath = try_get_modpath ( base) ?;
336- modpath. push_segment ( tuple_field) ;
337- Some ( modpath)
335+ try_get_modpath ( link)
338336}
0 commit comments