]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/core.rs
New upstream version 1.49.0~beta.4+dfsg1
[rustc.git] / src / librustdoc / core.rs
CommitLineData
ba9703b0 1use rustc_attr as attr;
dfeec247 2use rustc_data_structures::fx::{FxHashMap, FxHashSet};
f9f354fc 3use rustc_data_structures::sync::{self, Lrc};
532ac7d7 4use rustc_driver::abort_on_err;
ba9703b0
XL
5use rustc_errors::emitter::{Emitter, EmitterWriter};
6use rustc_errors::json::JsonEmitter;
60c5eb7d 7use rustc_feature::UnstableFeatures;
3dfed10e 8use rustc_hir::def::{Namespace::TypeNS, Res};
f9f354fc 9use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
dfeec247 10use rustc_hir::HirId;
3dfed10e
XL
11use rustc_hir::{
12 intravisit::{self, NestedVisitorMap, Visitor},
13 Path,
14};
60c5eb7d 15use rustc_interface::interface;
3dfed10e 16use rustc_middle::hir::map::Map;
ba9703b0
XL
17use rustc_middle::middle::cstore::CrateStore;
18use rustc_middle::middle::privacy::AccessLevels;
19use rustc_middle::ty::{Ty, TyCtxt};
85aaf69f 20use rustc_resolve as resolve;
f9f354fc 21use rustc_session::config::{self, CrateType, ErrorOutputType};
dfeec247 22use rustc_session::lint;
ba9703b0 23use rustc_session::DiagnosticOutput;
f9f354fc 24use rustc_session::Session;
dfeec247
XL
25use rustc_span::source_map;
26use rustc_span::symbol::sym;
27use rustc_span::DUMMY_SP;
1a4d82fc 28
0bf4aa26 29use std::cell::RefCell;
9e0c209e 30use std::mem;
532ac7d7 31use std::rc::Rc;
1a4d82fc 32
9fa01778 33use crate::clean;
60c5eb7d
XL
34use crate::clean::{AttributesExt, MAX_DEF_ID};
35use crate::config::{Options as RustdocOptions, RenderOptions};
3dfed10e 36use crate::config::{OutputFormat, RenderInfo};
60c5eb7d 37use crate::passes::{self, Condition::*, ConditionalPass};
1a4d82fc 38
ba9703b0
XL
39pub use rustc_session::config::{CodegenOptions, DebuggingOptions, Input, Options};
40pub use rustc_session::search_paths::SearchPath;
85aaf69f 41
476ff2be 42pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
1a4d82fc 43
532ac7d7 44pub struct DocContext<'tcx> {
dc9dc135 45 pub tcx: TyCtxt<'tcx>,
416331ca 46 pub resolver: Rc<RefCell<interface::BoxedResolver>>,
3dfed10e 47 /// Later on moved into `CACHE_KEY`
a7813a04 48 pub renderinfo: RefCell<RenderInfo>,
3dfed10e 49 /// Later on moved through `clean::Crate` into `CACHE_KEY`
416331ca 50 pub external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
0531ce1d
XL
51 /// Used while populating `external_traits` to ensure we don't process the same trait twice at
52 /// the same time.
416331ca 53 pub active_extern_traits: RefCell<FxHashSet<DefId>>,
9e0c209e
SL
54 // The current set of type and lifetime substitutions,
55 // for expanding type aliases at the HIR level:
48663c56
XL
56 /// Table `DefId` of type parameter -> substituted type
57 pub ty_substs: RefCell<FxHashMap<DefId, clean::Type>>,
58 /// Table `DefId` of lifetime parameter -> substituted lifetime
ea8adc8c 59 pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
48663c56
XL
60 /// Table `DefId` of const parameter -> substituted const
61 pub ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
e1599b0c
XL
62 /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
63 pub impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
0531ce1d
XL
64 pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
65 pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
48663c56
XL
66 /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
67 // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
68 pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
dc9dc135 69 pub auto_traits: Vec<DefId>,
f035d41b
XL
70 /// The options given to rustdoc that could be relevant to a pass.
71 pub render_options: RenderOptions,
3dfed10e
XL
72 /// The traits in scope for a given module.
73 ///
74 /// See `collect_intra_doc_links::traits_implemented_by` for more details.
75 /// `map<module, set<trait>>`
76 pub module_trait_cache: RefCell<FxHashMap<DefId, FxHashSet<DefId>>>,
476ff2be 77}
1a4d82fc 78
532ac7d7 79impl<'tcx> DocContext<'tcx> {
ba9703b0 80 pub fn sess(&self) -> &Session {
476ff2be 81 &self.tcx.sess
1a4d82fc 82 }
9e0c209e 83
532ac7d7 84 pub fn enter_resolver<F, R>(&self, f: F) -> R
60c5eb7d
XL
85 where
86 F: FnOnce(&mut resolve::Resolver<'_>) -> R,
87 {
416331ca 88 self.resolver.borrow_mut().access(f)
532ac7d7
XL
89 }
90
9e0c209e
SL
91 /// Call the closure with the given parameters set as
92 /// the substitutions for a type alias' RHS.
60c5eb7d
XL
93 pub fn enter_alias<F, R>(
94 &self,
95 ty_substs: FxHashMap<DefId, clean::Type>,
96 lt_substs: FxHashMap<DefId, clean::Lifetime>,
97 ct_substs: FxHashMap<DefId, clean::Constant>,
98 f: F,
99 ) -> R
100 where
101 F: FnOnce() -> R,
102 {
9fa01778
XL
103 let (old_tys, old_lts, old_cts) = (
104 mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
105 mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs),
106 mem::replace(&mut *self.ct_substs.borrow_mut(), ct_substs),
107 );
9e0c209e
SL
108 let r = f();
109 *self.ty_substs.borrow_mut() = old_tys;
110 *self.lt_substs.borrow_mut() = old_lts;
9fa01778 111 *self.ct_substs.borrow_mut() = old_cts;
9e0c209e
SL
112 r
113 }
b7449926
XL
114
115 // This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
ba9703b0 116 // refactoring either librustdoc or librustc_middle. In particular, allowing new DefIds to be
b7449926
XL
117 // registered after the AST is constructed would require storing the defid mapping in a
118 // RefCell, decreasing the performance for normal compilation for very little gain.
119 //
48663c56
XL
120 // Instead, we construct 'fake' def ids, which start immediately after the last DefId.
121 // In the Debug impl for clean::Item, we explicitly check for fake
b7449926
XL
122 // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds
123 pub fn next_def_id(&self, crate_num: CrateNum) -> DefId {
124 let start_def_id = {
3dfed10e
XL
125 let num_def_ids = if crate_num == LOCAL_CRATE {
126 self.tcx.hir().definitions().def_path_table().num_def_ids()
b7449926 127 } else {
3dfed10e 128 self.enter_resolver(|r| r.cstore().num_def_ids(crate_num))
b7449926
XL
129 };
130
3dfed10e 131 DefId { krate: crate_num, index: DefIndex::from_usize(num_def_ids) }
b7449926
XL
132 };
133
134 let mut fake_ids = self.fake_def_ids.borrow_mut();
135
dfeec247 136 let def_id = *fake_ids.entry(crate_num).or_insert(start_def_id);
b7449926
XL
137 fake_ids.insert(
138 crate_num,
60c5eb7d 139 DefId { krate: crate_num, index: DefIndex::from(def_id.index.index() + 1) },
b7449926
XL
140 );
141
142 MAX_DEF_ID.with(|m| {
f9f354fc 143 m.borrow_mut().entry(def_id.krate).or_insert(start_def_id);
b7449926
XL
144 });
145
146 self.all_fake_def_ids.borrow_mut().insert(def_id);
147
dfeec247 148 def_id
b7449926
XL
149 }
150
3dfed10e 151 /// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
0bf4aa26 152 /// (This avoids a slice-index-out-of-bounds panic.)
532ac7d7
XL
153 pub fn as_local_hir_id(&self, def_id: DefId) -> Option<HirId> {
154 if self.all_fake_def_ids.borrow().contains(&def_id) {
155 None
156 } else {
3dfed10e 157 def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
532ac7d7
XL
158 }
159 }
1a4d82fc 160
416331ca 161 pub fn stability(&self, id: HirId) -> Option<attr::Stability> {
60c5eb7d
XL
162 self.tcx
163 .hir()
164 .opt_local_def_id(id)
ba9703b0 165 .and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id()))
60c5eb7d 166 .cloned()
416331ca 167 }
1a4d82fc 168
416331ca 169 pub fn deprecation(&self, id: HirId) -> Option<attr::Deprecation> {
ba9703b0
XL
170 self.tcx
171 .hir()
172 .opt_local_def_id(id)
173 .and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id()))
a7813a04
XL
174 }
175}
1a4d82fc 176
94b46f34
XL
177/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
178///
b7449926 179/// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one
94b46f34 180/// will be created for the handler.
60c5eb7d
XL
181pub fn new_handler(
182 error_format: ErrorOutputType,
183 source_map: Option<Lrc<source_map::SourceMap>>,
dfeec247
XL
184 debugging_opts: &DebuggingOptions,
185) -> rustc_errors::Handler {
94b46f34 186 let emitter: Box<dyn Emitter + sync::Send> = match error_format {
48663c56
XL
187 ErrorOutputType::HumanReadable(kind) => {
188 let (short, color_config) = kind.unzip();
189 Box::new(
190 EmitterWriter::stderr(
191 color_config,
74b04a01 192 source_map.map(|sm| sm as _),
48663c56 193 short,
dfeec247
XL
194 debugging_opts.teach,
195 debugging_opts.terminal_width,
e1599b0c 196 false,
60c5eb7d 197 )
ba9703b0 198 .ui_testing(debugging_opts.ui_testing),
48663c56 199 )
60c5eb7d 200 }
48663c56 201 ErrorOutputType::Json { pretty, json_rendered } => {
60c5eb7d 202 let source_map = source_map.unwrap_or_else(|| {
dfeec247 203 Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
60c5eb7d 204 });
94b46f34 205 Box::new(
f035d41b
XL
206 JsonEmitter::stderr(
207 None,
208 source_map,
209 pretty,
210 json_rendered,
211 debugging_opts.terminal_width,
212 false,
213 )
214 .ui_testing(debugging_opts.ui_testing),
94b46f34 215 )
60c5eb7d 216 }
94b46f34
XL
217 };
218
dfeec247 219 rustc_errors::Handler::with_emitter_and_flags(
94b46f34 220 emitter,
dfeec247 221 debugging_opts.diagnostic_handler_flags(true),
94b46f34
XL
222 )
223}
224
f9f354fc
XL
225/// This function is used to setup the lint initialization. By default, in rustdoc, everything
226/// is "allowed". Depending if we run in test mode or not, we want some of them to be at their
227/// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTES" lint is activated in both
228/// modes.
229///
230/// A little detail easy to forget is that there is a way to set the lint level for all lints
231/// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level
232/// inside this function.
233///
234/// It returns a tuple containing:
235/// * Vector of tuples of lints' name and their associated "max" level
236/// * HashMap of lint id with their associated "max" level
1b1a35ee 237pub(crate) fn init_lints<F>(
f035d41b 238 mut allowed_lints: Vec<String>,
f9f354fc
XL
239 lint_opts: Vec<(String, lint::Level)>,
240 filter_call: F,
241) -> (Vec<(String, lint::Level)>, FxHashMap<lint::LintId, lint::Level>)
242where
243 F: Fn(&lint::Lint) -> Option<(String, lint::Level)>,
244{
245 let warnings_lint_name = lint::builtin::WARNINGS.name;
246
f035d41b
XL
247 allowed_lints.push(warnings_lint_name.to_owned());
248 allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
f9f354fc
XL
249
250 let lints = || {
251 lint::builtin::HardwiredLints::get_lints()
252 .into_iter()
253 .chain(rustc_lint::SoftLints::get_lints().into_iter())
254 };
255
256 let lint_opts = lints()
257 .filter_map(|lint| {
f035d41b
XL
258 // Permit feature-gated lints to avoid feature errors when trying to
259 // allow all lints.
1b1a35ee 260 if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) {
f9f354fc
XL
261 None
262 } else {
263 filter_call(lint)
264 }
265 })
266 .chain(lint_opts.into_iter())
267 .collect::<Vec<_>>();
268
269 let lint_caps = lints()
270 .filter_map(|lint| {
f035d41b
XL
271 // We don't want to allow *all* lints so let's ignore
272 // those ones.
273 if allowed_lints.iter().any(|l| lint.name == l) {
f9f354fc
XL
274 None
275 } else {
276 Some((lint::LintId::of(lint), lint::Allow))
277 }
278 })
279 .collect();
280 (lint_opts, lint_caps)
281}
282
3dfed10e
XL
283pub fn run_core(
284 options: RustdocOptions,
285) -> (clean::Crate, RenderInfo, RenderOptions, Lrc<Session>) {
1a4d82fc
JJ
286 // Parse, resolve, and typecheck the given crate.
287
a1dfa0c6
XL
288 let RustdocOptions {
289 input,
290 crate_name,
e1599b0c 291 proc_macro_crate,
a1dfa0c6
XL
292 error_format,
293 libs,
294 externs,
e74abb32 295 mut cfgs,
a1dfa0c6 296 codegen_options,
1b1a35ee 297 debugging_opts,
a1dfa0c6
XL
298 target,
299 edition,
300 maybe_sysroot,
301 lint_opts,
302 describe_lints,
303 lint_cap,
3dfed10e
XL
304 default_passes,
305 manual_passes,
a1dfa0c6
XL
306 display_warnings,
307 render_options,
ba9703b0 308 output_format,
a1dfa0c6
XL
309 ..
310 } = options;
311
60c5eb7d
XL
312 let extern_names: Vec<String> = externs
313 .iter()
314 .filter(|(_, entry)| entry.add_prelude)
315 .map(|(name, _)| name)
316 .cloned()
317 .collect();
318
319 // Add the doc cfg into the doc build.
320 cfgs.push("doc".to_string());
e74abb32 321
a1dfa0c6
XL
322 let cpath = Some(input.clone());
323 let input = Input::File(input);
1a4d82fc 324
29967ef6
XL
325 let broken_intra_doc_links = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
326 let private_intra_doc_links = lint::builtin::PRIVATE_INTRA_DOC_LINKS.name;
94b46f34 327 let missing_docs = rustc_lint::builtin::MISSING_DOCS.name;
0bf4aa26 328 let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
a1dfa0c6 329 let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
ba9703b0 330 let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name;
3dfed10e 331 let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
29967ef6 332 let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
1b1a35ee 333 let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
29967ef6 334 let non_autolinks = rustc_lint::builtin::NON_AUTOLINKS.name;
1b1a35ee 335 let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
8faf50e0 336
f035d41b 337 // In addition to those specific lints, we also need to allow those given through
8faf50e0 338 // command line, otherwise they'll get ignored and we don't want that.
1b1a35ee 339 let lints_to_show = vec![
29967ef6
XL
340 broken_intra_doc_links.to_owned(),
341 private_intra_doc_links.to_owned(),
60c5eb7d
XL
342 missing_docs.to_owned(),
343 missing_doc_example.to_owned(),
344 private_doc_tests.to_owned(),
ba9703b0 345 no_crate_level_docs.to_owned(),
3dfed10e 346 invalid_codeblock_attributes_name.to_owned(),
29967ef6 347 invalid_html_tags.to_owned(),
1b1a35ee
XL
348 renamed_and_removed_lints.to_owned(),
349 unknown_lints.to_owned(),
29967ef6 350 non_autolinks.to_owned(),
60c5eb7d 351 ];
8faf50e0 352
1b1a35ee 353 let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
29967ef6
XL
354 // FIXME: why is this necessary?
355 if lint.name == broken_intra_doc_links || lint.name == invalid_codeblock_attributes_name {
f9f354fc
XL
356 None
357 } else {
358 Some((lint.name_lower(), lint::Allow))
359 }
360 });
1a4d82fc 361
f9f354fc
XL
362 let crate_types =
363 if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
83c7162d 364 // plays with error output here!
1a4d82fc 365 let sessopts = config::Options {
3b2f2976 366 maybe_sysroot,
a1dfa0c6 367 search_paths: libs,
e1599b0c 368 crate_types,
60c5eb7d 369 lint_opts: if !display_warnings { lint_opts } else { vec![] },
1b1a35ee 370 lint_cap,
a1dfa0c6 371 cg: codegen_options,
3b2f2976 372 externs,
e1599b0c 373 target_triple: target,
60c5eb7d 374 unstable_features: UnstableFeatures::from_environment(),
c30ab7b3 375 actually_rustdoc: true,
1b1a35ee 376 debugging_opts,
83c7162d
XL
377 error_format,
378 edition,
8faf50e0 379 describe_lints,
b7449926 380 ..Options::default()
a7813a04 381 };
94b46f34 382
532ac7d7
XL
383 let config = interface::Config {
384 opts: sessopts,
e74abb32 385 crate_cfg: interface::parse_cfgspecs(cfgs),
532ac7d7
XL
386 input,
387 input_path: cpath,
388 output_file: None,
389 output_dir: None,
390 file_loader: None,
391 diagnostic_output: DiagnosticOutput::Default,
392 stderr: None,
416331ca 393 crate_name,
532ac7d7 394 lint_caps,
e74abb32 395 register_lints: None,
3dfed10e
XL
396 override_queries: Some(|_sess, providers, _external_providers| {
397 // Most lints will require typechecking, so just don't run them.
398 providers.lint_mod = |_, _| {};
399 // Prevent `rustc_typeck::check_crate` from calling `typeck` on all bodies.
400 providers.typeck_item_bodies = |_, _| {};
401 // hack so that `used_trait_imports` won't try to call typeck
402 providers.used_trait_imports = |_, _| {
403 lazy_static! {
404 static ref EMPTY_SET: FxHashSet<LocalDefId> = FxHashSet::default();
405 }
406 &EMPTY_SET
407 };
408 // In case typeck does end up being called, don't ICE in case there were name resolution errors
409 providers.typeck = move |tcx, def_id| {
410 // Closures' tables come from their outermost function,
411 // as they are part of the same "inference environment".
412 // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
413 let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
414 if outer_def_id != def_id {
415 return tcx.typeck(outer_def_id);
416 }
417
418 let hir = tcx.hir();
419 let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(def_id)));
420 debug!("visiting body for {:?}", def_id);
421 tcx.sess.time("emit_ignored_resolution_errors", || {
422 EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
423 });
424 (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
425 };
426 }),
1b1a35ee 427 make_codegen_backend: None,
60c5eb7d 428 registry: rustc_driver::diagnostics_registry(),
532ac7d7 429 };
94b46f34 430
f035d41b 431 interface::create_compiler_and_run(config, |compiler| {
60c5eb7d
XL
432 compiler.enter(|queries| {
433 let sess = compiler.session();
434
435 // We need to hold on to the complete resolver, so we cause everything to be
436 // cloned for the analysis passes to use. Suboptimal, but necessary in the
437 // current architecture.
438 let resolver = {
439 let parts = abort_on_err(queries.expansion(), sess).peek();
440 let resolver = parts.1.borrow();
441
442 // Before we actually clone it, let's force all the extern'd crates to
443 // actually be loaded, just in case they're only referred to inside
444 // intra-doc-links
445 resolver.borrow_mut().access(|resolver| {
3dfed10e
XL
446 sess.time("load_extern_crates", || {
447 for extern_name in &extern_names {
1b1a35ee 448 debug!("loading extern crate {}", extern_name);
3dfed10e
XL
449 resolver
450 .resolve_str_path_error(
451 DUMMY_SP,
452 extern_name,
453 TypeNS,
454 LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
455 )
456 .unwrap_or_else(|()| {
457 panic!("Unable to resolve external crate {}", extern_name)
458 });
459 }
460 });
60c5eb7d 461 });
94b46f34 462
60c5eb7d
XL
463 // Now we're good to clone the resolver because everything should be loaded
464 resolver.clone()
94b46f34 465 };
94b46f34 466
60c5eb7d
XL
467 if sess.has_errors() {
468 sess.fatal("Compilation failed, aborting rustdoc");
469 }
94b46f34 470
60c5eb7d
XL
471 let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
472
3dfed10e
XL
473 let (krate, render_info, opts) = sess.time("run_global_ctxt", || {
474 global_ctxt.enter(|tcx| {
475 run_global_ctxt(
476 tcx,
477 resolver,
478 default_passes,
479 manual_passes,
480 render_options,
481 output_format,
482 )
483 })
484 });
485 (krate, render_info, opts, Lrc::clone(sess))
486 })
487 })
488}
ba9703b0 489
3dfed10e
XL
490fn run_global_ctxt(
491 tcx: TyCtxt<'_>,
492 resolver: Rc<RefCell<interface::BoxedResolver>>,
493 mut default_passes: passes::DefaultPassOption,
494 mut manual_passes: Vec<String>,
495 render_options: RenderOptions,
496 output_format: Option<OutputFormat>,
497) -> (clean::Crate, RenderInfo, RenderOptions) {
498 // Certain queries assume that some checks were run elsewhere
499 // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
500 // so type-check everything other than function bodies in this crate before running lints.
501
502 // NOTE: this does not call `tcx.analysis()` so that we won't
503 // typeck function bodies or run the default rustc lints.
504 // (see `override_queries` in the `config`)
505
506 // HACK(jynelson) this calls an _extremely_ limited subset of `typeck`
507 // and might break if queries change their assumptions in the future.
508
509 // NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
510 tcx.sess.time("item_types_checking", || {
511 for &module in tcx.hir().krate().modules.keys() {
512 tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
513 }
514 });
515 tcx.sess.abort_if_errors();
516 tcx.sess.time("missing_docs", || {
517 rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
518 });
519 tcx.sess.time("check_mod_attrs", || {
520 for &module in tcx.hir().krate().modules.keys() {
521 let local_def_id = tcx.hir().local_def_id(module);
522 tcx.ensure().check_mod_attrs(local_def_id);
523 }
524 });
60c5eb7d 525
3dfed10e
XL
526 let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
527 // Convert from a HirId set to a DefId set since we don't always have easy access
528 // to the map from defid -> hirid
529 let access_levels = AccessLevels {
530 map: access_levels
531 .map
532 .iter()
533 .map(|(&k, &v)| (tcx.hir().local_def_id(k).to_def_id(), v))
534 .collect(),
535 };
b7449926 536
3dfed10e
XL
537 let mut renderinfo = RenderInfo::default();
538 renderinfo.access_levels = access_levels;
539 renderinfo.output_format = output_format;
540
541 let mut ctxt = DocContext {
542 tcx,
543 resolver,
544 external_traits: Default::default(),
545 active_extern_traits: Default::default(),
546 renderinfo: RefCell::new(renderinfo),
547 ty_substs: Default::default(),
548 lt_substs: Default::default(),
549 ct_substs: Default::default(),
550 impl_trait_bounds: Default::default(),
551 fake_def_ids: Default::default(),
552 all_fake_def_ids: Default::default(),
553 generated_synthetics: Default::default(),
554 auto_traits: tcx
555 .all_traits(LOCAL_CRATE)
556 .iter()
557 .cloned()
558 .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
559 .collect(),
560 render_options,
561 module_trait_cache: RefCell::new(FxHashMap::default()),
562 };
563 debug!("crate: {:?}", tcx.hir().krate());
564
565 let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
566
567 if let Some(ref m) = krate.module {
568 if let None | Some("") = m.doc_value() {
569 let help = "The following guide may be of use:\n\
1b1a35ee 570 https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
3dfed10e
XL
571 tcx.struct_lint_node(
572 rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS,
573 ctxt.as_local_hir_id(m.def_id).unwrap(),
574 |lint| {
575 let mut diag =
576 lint.build("no documentation found for this crate's top-level module");
577 diag.help(help);
578 diag.emit();
579 },
580 );
581 }
582 }
b7449926 583
3dfed10e
XL
584 fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler) {
585 let mut msg = diag
586 .struct_warn(&format!("the `#![doc({})]` attribute is considered deprecated", name));
587 msg.warn(
588 "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
1b1a35ee 589 for more information",
3dfed10e 590 );
b7449926 591
3dfed10e
XL
592 if name == "no_default_passes" {
593 msg.help("you may want to use `#![doc(document_private_items)]`");
594 }
b7449926 595
3dfed10e
XL
596 msg.emit();
597 }
598
599 // Process all of the crate attributes, extracting plugin metadata along
600 // with the passes which we are supposed to run.
601 for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) {
602 let diag = ctxt.sess().diagnostic();
603
604 let name = attr.name_or_empty();
605 if attr.is_word() {
606 if name == sym::no_default_passes {
607 report_deprecated_attr("no_default_passes", diag);
608 if default_passes == passes::DefaultPassOption::Default {
609 default_passes = passes::DefaultPassOption::None;
60c5eb7d 610 }
3dfed10e
XL
611 }
612 } else if let Some(value) = attr.value_str() {
613 let sink = match name {
614 sym::passes => {
615 report_deprecated_attr("passes = \"...\"", diag);
616 &mut manual_passes
617 }
618 sym::plugins => {
619 report_deprecated_attr("plugins = \"...\"", diag);
620 eprintln!(
621 "WARNING: `#![doc(plugins = \"...\")]` \
1b1a35ee 622 no longer functions; see CVE-2018-1000622"
3dfed10e
XL
623 );
624 continue;
625 }
626 _ => continue,
627 };
628 for name in value.as_str().split_whitespace() {
629 sink.push(name.to_string());
630 }
631 }
b7449926 632
3dfed10e
XL
633 if attr.is_word() && name == sym::document_private_items {
634 ctxt.render_options.document_private = true;
635 }
636 }
b7449926 637
3dfed10e
XL
638 let passes = passes::defaults(default_passes).iter().copied().chain(
639 manual_passes.into_iter().flat_map(|name| {
640 if let Some(pass) = passes::find_pass(&name) {
641 Some(ConditionalPass::always(pass))
642 } else {
643 error!("unknown pass {}, skipping", name);
644 None
645 }
646 }),
647 );
648
649 info!("Executing passes");
650
651 for p in passes {
652 let run = match p.condition {
653 Always => true,
654 WhenDocumentPrivate => ctxt.render_options.document_private,
655 WhenNotDocumentPrivate => !ctxt.render_options.document_private,
656 WhenNotDocumentHidden => !ctxt.render_options.document_hidden,
657 };
658 if run {
659 debug!("running pass {}", p.pass.name);
660 krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &ctxt));
661 }
662 }
663
664 ctxt.sess().abort_if_errors();
665
666 (krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
667}
668
29967ef6 669/// Due to <https://github.com/rust-lang/rust/pull/73566>,
3dfed10e
XL
670/// the name resolution pass may find errors that are never emitted.
671/// If typeck is called after this happens, then we'll get an ICE:
672/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
673struct EmitIgnoredResolutionErrors<'tcx> {
674 tcx: TyCtxt<'tcx>,
675}
676
677impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
678 fn new(tcx: TyCtxt<'tcx>) -> Self {
679 Self { tcx }
680 }
681}
682
683impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
684 type Map = Map<'tcx>;
685
686 fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
687 // We need to recurse into nested closures,
688 // since those will fallback to the parent for type checking.
689 NestedVisitorMap::OnlyBodies(self.tcx.hir())
690 }
691
692 fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
693 debug!("visiting path {:?}", path);
694 if path.res == Res::Err {
695 // We have less context here than in rustc_resolve,
696 // so we can only emit the name and span.
697 // However we can give a hint that rustc_resolve will have more info.
698 let label = format!(
699 "could not resolve path `{}`",
700 path.segments
701 .iter()
702 .map(|segment| segment.ident.as_str().to_string())
703 .collect::<Vec<_>>()
704 .join("::")
705 );
706 let mut err = rustc_errors::struct_span_err!(
707 self.tcx.sess,
708 path.span,
709 E0433,
710 "failed to resolve: {}",
711 label
712 );
713 err.span_label(path.span, label);
714 err.note("this error was originally ignored because you are running `rustdoc`");
715 err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error");
716 err.emit();
717 }
718 // We could have an outer resolution that succeeded,
719 // but with generic parameters that failed.
720 // Recurse into the segments so we catch those too.
721 intravisit::walk_path(self, path);
722 }
1a4d82fc 723}
e1599b0c
XL
724
725/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
726/// for `impl Trait` in argument position.
727#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
728pub enum ImplTraitParam {
729 DefId(DefId),
730 ParamIndex(u32),
731}
732
733impl From<DefId> for ImplTraitParam {
734 fn from(did: DefId) -> Self {
735 ImplTraitParam::DefId(did)
736 }
737}
738
739impl From<u32> for ImplTraitParam {
740 fn from(idx: u32) -> Self {
741 ImplTraitParam::ParamIndex(idx)
742 }
743}