@@ -16,7 +16,7 @@ use hir_def::{
16
16
type_ref:: { Mutability , TypeRef } ,
17
17
AdtId , AssocContainerId , ConstId , DefWithBodyId , EnumId , FunctionId , GenericDefId , HasModule ,
18
18
ImplId , LocalEnumVariantId , LocalFieldId , LocalModuleId , Lookup , ModuleId , StaticId , StructId ,
19
- TraitId , TypeAliasId , TypeParamId , UnionId ,
19
+ TraitId , TypeAliasId , TypeParamId , UnionId , VariantId ,
20
20
} ;
21
21
use hir_expand:: {
22
22
diagnostics:: DiagnosticSink ,
@@ -35,12 +35,14 @@ use ra_syntax::{
35
35
ast:: { self , AttrsOwner , NameOwner } ,
36
36
AstNode ,
37
37
} ;
38
+ use ra_tt:: { Ident , Leaf , Literal , TokenTree } ;
38
39
use rustc_hash:: FxHashSet ;
39
40
use stdx:: impl_from;
40
41
41
42
use crate :: {
42
43
db:: { DefDatabase , HirDatabase } ,
43
44
has_source:: HasSource ,
45
+ link_rewrite:: Resolvable ,
44
46
HirDisplay , InFile , Name ,
45
47
} ;
46
48
@@ -120,6 +122,33 @@ impl Crate {
120
122
pub fn all ( db : & dyn HirDatabase ) -> Vec < Crate > {
121
123
db. crate_graph ( ) . iter ( ) . map ( |id| Crate { id } ) . collect ( )
122
124
}
125
+
126
+ /// Try to get the root URL of the documentation of a crate.
127
+ pub fn get_doc_url ( self : & Crate , db : & dyn HirDatabase ) -> Option < String > {
128
+ // Look for #![doc(html_root_url = "...")]
129
+ let attrs = db. attrs ( AttrDef :: from ( self . root_module ( db) ?) . into ( ) ) ;
130
+ let doc_attr_q = attrs. by_key ( "doc" ) ;
131
+
132
+ let doc_url = if doc_attr_q. exists ( ) {
133
+ doc_attr_q. tt_values ( ) . map ( |tt| {
134
+ let name = tt. token_trees . iter ( )
135
+ . skip_while ( |tt| !matches ! ( tt, TokenTree :: Leaf ( Leaf :: Ident ( Ident { text: ref ident, ..} ) ) if ident == "html_root_url" ) )
136
+ . skip ( 2 )
137
+ . next ( ) ;
138
+
139
+ match name {
140
+ Some ( TokenTree :: Leaf ( Leaf :: Literal ( Literal { ref text, ..} ) ) ) => Some ( text) ,
141
+ _ => None
142
+ }
143
+ } ) . flat_map ( |t| t) . next ( ) . map ( |s| s. to_string ( ) )
144
+ } else {
145
+ None
146
+ } ;
147
+
148
+ doc_url
149
+ . map ( |s| s. trim_matches ( '"' ) . trim_end_matches ( "/" ) . to_owned ( ) + "/" )
150
+ . map ( |s| s. to_string ( ) )
151
+ }
123
152
}
124
153
125
154
#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
@@ -1709,3 +1738,76 @@ pub trait HasVisibility {
1709
1738
vis. is_visible_from ( db. upcast ( ) , module. id )
1710
1739
}
1711
1740
}
1741
+
1742
+ impl Resolvable for ModuleDef {
1743
+ fn resolver < D : DefDatabase + HirDatabase > ( & self , db : & D ) -> Option < Resolver > {
1744
+ Some ( match self {
1745
+ ModuleDef :: Module ( m) => ModuleId :: from ( m. clone ( ) ) . resolver ( db) ,
1746
+ ModuleDef :: Function ( f) => FunctionId :: from ( f. clone ( ) ) . resolver ( db) ,
1747
+ ModuleDef :: Adt ( adt) => AdtId :: from ( adt. clone ( ) ) . resolver ( db) ,
1748
+ ModuleDef :: EnumVariant ( ev) => {
1749
+ GenericDefId :: from ( GenericDef :: from ( ev. clone ( ) ) ) . resolver ( db)
1750
+ }
1751
+ ModuleDef :: Const ( c) => GenericDefId :: from ( GenericDef :: from ( c. clone ( ) ) ) . resolver ( db) ,
1752
+ ModuleDef :: Static ( s) => StaticId :: from ( s. clone ( ) ) . resolver ( db) ,
1753
+ ModuleDef :: Trait ( t) => TraitId :: from ( t. clone ( ) ) . resolver ( db) ,
1754
+ ModuleDef :: TypeAlias ( t) => ModuleId :: from ( t. module ( db) ) . resolver ( db) ,
1755
+ // FIXME: This should be a resolver relative to `std/core`
1756
+ ModuleDef :: BuiltinType ( _t) => None ?,
1757
+ } )
1758
+ }
1759
+
1760
+ fn try_into_module_def ( self ) -> Option < ModuleDef > {
1761
+ Some ( self )
1762
+ }
1763
+ }
1764
+
1765
+ impl Resolvable for TypeParam {
1766
+ fn resolver < D : DefDatabase + HirDatabase > ( & self , db : & D ) -> Option < Resolver > {
1767
+ Some ( Into :: < ModuleId > :: into ( self . module ( db) ) . resolver ( db) )
1768
+ }
1769
+
1770
+ fn try_into_module_def ( self ) -> Option < ModuleDef > {
1771
+ None
1772
+ }
1773
+ }
1774
+
1775
+ impl Resolvable for MacroDef {
1776
+ fn resolver < D : DefDatabase + HirDatabase > ( & self , db : & D ) -> Option < Resolver > {
1777
+ Some ( Into :: < ModuleId > :: into ( self . module ( db) ?) . resolver ( db) )
1778
+ }
1779
+
1780
+ fn try_into_module_def ( self ) -> Option < ModuleDef > {
1781
+ None
1782
+ }
1783
+ }
1784
+
1785
+ impl Resolvable for Field {
1786
+ fn resolver < D : DefDatabase + HirDatabase > ( & self , db : & D ) -> Option < Resolver > {
1787
+ Some ( Into :: < VariantId > :: into ( Into :: < VariantDef > :: into ( self . parent_def ( db) ) ) . resolver ( db) )
1788
+ }
1789
+
1790
+ fn try_into_module_def ( self ) -> Option < ModuleDef > {
1791
+ None
1792
+ }
1793
+ }
1794
+
1795
+ impl Resolvable for ImplDef {
1796
+ fn resolver < D : DefDatabase + HirDatabase > ( & self , db : & D ) -> Option < Resolver > {
1797
+ Some ( Into :: < ModuleId > :: into ( self . module ( db) ) . resolver ( db) )
1798
+ }
1799
+
1800
+ fn try_into_module_def ( self ) -> Option < ModuleDef > {
1801
+ None
1802
+ }
1803
+ }
1804
+
1805
+ impl Resolvable for Local {
1806
+ fn resolver < D : DefDatabase + HirDatabase > ( & self , db : & D ) -> Option < Resolver > {
1807
+ Some ( Into :: < ModuleId > :: into ( self . module ( db) ) . resolver ( db) )
1808
+ }
1809
+
1810
+ fn try_into_module_def ( self ) -> Option < ModuleDef > {
1811
+ None
1812
+ }
1813
+ }
0 commit comments