@@ -24,7 +24,8 @@ use std::ops::Range;
24
24
25
25
use core:: DocContext ;
26
26
use fold:: DocFolder ;
27
- use html:: markdown:: markdown_links;
27
+ use html:: markdown:: { find_testable_code, markdown_links, ErrorCodes , LangString } ;
28
+
28
29
use passes:: Pass ;
29
30
30
31
pub const COLLECT_INTRA_DOC_LINKS : Pass =
@@ -56,13 +57,15 @@ enum PathKind {
56
57
struct LinkCollector < ' a , ' tcx : ' a , ' rcx : ' a , ' cstore : ' rcx > {
57
58
cx : & ' a DocContext < ' a , ' tcx , ' rcx , ' cstore > ,
58
59
mod_ids : Vec < NodeId > ,
60
+ is_nightly_build : bool ,
59
61
}
60
62
61
63
impl < ' a , ' tcx , ' rcx , ' cstore > LinkCollector < ' a , ' tcx , ' rcx , ' cstore > {
62
64
fn new ( cx : & ' a DocContext < ' a , ' tcx , ' rcx , ' cstore > ) -> Self {
63
65
LinkCollector {
64
66
cx,
65
67
mod_ids : Vec :: new ( ) ,
68
+ is_nightly_build : UnstableFeatures :: from_environment ( ) . is_nightly_build ( ) ,
66
69
}
67
70
}
68
71
@@ -211,6 +214,43 @@ impl<'a, 'tcx, 'rcx, 'cstore> LinkCollector<'a, 'tcx, 'rcx, 'cstore> {
211
214
}
212
215
}
213
216
217
+ fn look_for_tests < ' a , ' tcx : ' a , ' rcx : ' a , ' cstore : ' rcx > (
218
+ cx : & ' a DocContext < ' a , ' tcx , ' rcx , ' cstore > ,
219
+ dox : & str ,
220
+ item : & Item ,
221
+ ) {
222
+ if ( item. is_mod ( ) && cx. tcx . hir . as_local_node_id ( item. def_id ) . is_none ( ) ) ||
223
+ cx. as_local_node_id ( item. def_id ) . is_none ( ) {
224
+ // If non-local, no need to check anything.
225
+ return ;
226
+ }
227
+
228
+ struct Tests {
229
+ found_tests : usize ,
230
+ }
231
+
232
+ impl :: test:: Tester for Tests {
233
+ fn add_test ( & mut self , _: String , _: LangString , _: usize ) {
234
+ self . found_tests += 1 ;
235
+ }
236
+ }
237
+
238
+ let mut tests = Tests {
239
+ found_tests : 0 ,
240
+ } ;
241
+
242
+ if find_testable_code ( & dox, & mut tests, ErrorCodes :: No ) . is_ok ( ) {
243
+ if tests. found_tests == 0 {
244
+ let mut diag = cx. tcx . struct_span_lint_node (
245
+ lint:: builtin:: MISSING_DOC_CODE_EXAMPLES ,
246
+ NodeId :: new ( 0 ) ,
247
+ span_of_attrs ( & item. attrs ) ,
248
+ "Missing code example in this documentation" ) ;
249
+ diag. emit ( ) ;
250
+ }
251
+ }
252
+ }
253
+
214
254
impl < ' a , ' tcx , ' rcx , ' cstore > DocFolder for LinkCollector < ' a , ' tcx , ' rcx , ' cstore > {
215
255
fn fold_item ( & mut self , mut item : Item ) -> Option < Item > {
216
256
let item_node_id = if item. is_mod ( ) {
@@ -273,6 +313,12 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for LinkCollector<'a, 'tcx, 'rcx, 'cstor
273
313
let cx = self . cx ;
274
314
let dox = item. attrs . collapsed_doc_value ( ) . unwrap_or_else ( String :: new) ;
275
315
316
+ look_for_tests ( & cx, & dox, & item) ;
317
+
318
+ if !self . is_nightly_build {
319
+ return None ;
320
+ }
321
+
276
322
for ( ori_link, link_range) in markdown_links ( & dox) {
277
323
// bail early for real links
278
324
if ori_link. contains ( '/' ) {
0 commit comments