1
- use hir:: ModuleDef ;
1
+ use hir:: { HasVisibility , ModuleDef , Visibility } ;
2
2
use ide_db:: assists:: { AssistId , AssistKind } ;
3
3
use stdx:: to_lower_snake_case;
4
4
use syntax:: {
5
- ast:: { self , edit:: IndentLevel , HasDocComments , HasName , HasVisibility } ,
5
+ ast:: { self , edit:: IndentLevel , HasDocComments , HasName } ,
6
6
AstNode ,
7
7
} ;
8
8
@@ -43,7 +43,7 @@ pub(crate) fn generate_documentation_template(
43
43
let name = ctx. find_node_at_offset :: < ast:: Name > ( ) ?;
44
44
let ast_func = name. syntax ( ) . parent ( ) . and_then ( ast:: Fn :: cast) ?;
45
45
if is_in_trait_impl ( & ast_func)
46
- || !is_public ( & ast_func)
46
+ || !is_public ( & ast_func, ctx ) ?
47
47
|| ast_func. doc_comments ( ) . next ( ) . is_some ( )
48
48
{
49
49
return None ;
@@ -187,7 +187,7 @@ struct ExHelper {
187
187
self_name : Option < String > ,
188
188
}
189
189
190
- /// Build the start of the example and transmit the useful intermediary results.
190
+ /// Builds the start of the example and transmit the useful intermediary results.
191
191
/// `None` if the function has a `self` parameter but is not in an `impl`.
192
192
fn gen_ex_start_helper ( ast_func : & ast:: Fn , ctx : & AssistContext ) -> Option < ( Vec < String > , ExHelper ) > {
193
193
let mut lines = Vec :: new ( ) ;
@@ -209,31 +209,41 @@ fn gen_ex_start_helper(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<(Vec<S
209
209
Some ( ( lines, ex_helper) )
210
210
}
211
211
212
- /// Check if the function and all its parent modules are exactly `pub`
213
- fn is_public ( ast_func : & ast:: Fn ) -> bool {
214
- has_pub ( ast_func)
215
- && ast_func
216
- . syntax ( )
217
- . ancestors ( )
218
- . filter_map ( ast:: Module :: cast)
219
- . all ( |module| has_pub ( & module) )
212
+ /// Checks if the function is public / exported
213
+ fn is_public ( ast_func : & ast:: Fn , ctx : & AssistContext ) -> Option < bool > {
214
+ let hir_func = ctx. sema . to_def ( ast_func) ?;
215
+ Some (
216
+ hir_func. visibility ( ctx. db ( ) ) == Visibility :: Public
217
+ && all_parent_mods_public ( & hir_func, ctx) ,
218
+ )
220
219
}
221
220
222
- /// Get the name of the current crate
221
+ /// Checks that all parent modules of the function are public / exported
222
+ fn all_parent_mods_public ( hir_func : & hir:: Function , ctx : & AssistContext ) -> bool {
223
+ let mut module = hir_func. module ( ctx. db ( ) ) ;
224
+ loop {
225
+ if let Some ( parent) = module. parent ( ctx. db ( ) ) {
226
+ match ModuleDef :: from ( module) . visibility ( ctx. db ( ) ) {
227
+ Visibility :: Public => module = parent,
228
+ _ => break false ,
229
+ }
230
+ } else {
231
+ break true ;
232
+ }
233
+ }
234
+ }
235
+
236
+ /// Returns the name of the current crate
223
237
fn crate_name ( ast_func : & ast:: Fn , ctx : & AssistContext ) -> Option < String > {
224
238
let krate = ctx. sema . scope ( & ast_func. syntax ( ) ) . module ( ) ?. krate ( ) ;
225
239
Some ( krate. display_name ( ctx. db ( ) ) ?. to_string ( ) )
226
240
}
227
241
228
- /// Check if visibility is exactly `pub` (not `pub(crate)` for instance)
229
- fn has_pub < T : HasVisibility > ( item : & T ) -> bool {
230
- item. visibility ( ) . map ( |v| v. path ( ) . is_none ( ) ) . unwrap_or ( false )
231
- }
232
-
233
242
/// `None` if function without a body; some bool to guess if function can panic
234
243
fn can_panic ( ast_func : & ast:: Fn ) -> Option < bool > {
235
244
let body = ast_func. body ( ) ?. to_string ( ) ;
236
245
let can_panic = body. contains ( "panic!(" )
246
+ // FIXME it would be better to not match `debug_assert*!` macro invocations
237
247
|| body. contains ( "assert!(" )
238
248
|| body. contains ( ".unwrap()" )
239
249
|| body. contains ( ".expect(" ) ;
@@ -387,8 +397,8 @@ fn build_path(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<String> {
387
397
let leaf = self_partial_type ( ast_func)
388
398
. or_else ( || ast_func. name ( ) . map ( |n| n. to_string ( ) ) )
389
399
. unwrap_or_else ( || "*" . into ( ) ) ;
390
- let func_module_def : ModuleDef = ctx. sema . to_def ( ast_func) ?. module ( ctx. db ( ) ) . into ( ) ;
391
- match func_module_def . canonical_path ( ctx. db ( ) ) {
400
+ let module_def : ModuleDef = ctx. sema . to_def ( ast_func) ?. module ( ctx. db ( ) ) . into ( ) ;
401
+ match module_def . canonical_path ( ctx. db ( ) ) {
392
402
Some ( path) => Some ( format ! ( "{}::{}::{}" , crate_name, path, leaf) ) ,
393
403
None => Some ( format ! ( "{}::{}" , crate_name, leaf) ) ,
394
404
}
0 commit comments