2019-12-24 05:02:53 +01:00
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
2020-05-02 01:30:23 +03:00
|
|
|
use rustc_data_structures::sync::{self, Lrc};
|
2018-12-08 20:30:23 +01:00
|
|
|
use rustc_driver::abort_on_err;
|
2020-03-11 12:49:08 +01:00
|
|
|
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
|
|
|
use rustc_errors::json::JsonEmitter;
|
2019-11-30 02:50:47 +01:00
|
|
|
use rustc_feature::UnstableFeatures;
|
2021-04-11 09:28:03 -04:00
|
|
|
use rustc_hir::def::Res;
|
2021-08-21 20:15:20 +00:00
|
|
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::HirId;
|
2020-07-10 17:24:17 -04:00
|
|
|
use rustc_hir::{
|
2020-07-10 17:50:03 -04:00
|
|
|
intravisit::{self, NestedVisitorMap, Visitor},
|
2020-07-10 17:24:17 -04:00
|
|
|
Path,
|
|
|
|
};
|
2020-12-11 21:46:58 -05:00
|
|
|
use rustc_interface::{interface, Queries};
|
2020-07-10 17:24:17 -04:00
|
|
|
use rustc_middle::hir::map::Map;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_middle::middle::privacy::AccessLevels;
|
2020-10-18 11:27:16 -04:00
|
|
|
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
2015-01-11 15:03:34 +13:00
|
|
|
use rustc_resolve as resolve;
|
2020-05-02 01:30:23 +03:00
|
|
|
use rustc_session::config::{self, CrateType, ErrorOutputType};
|
2020-01-09 06:42:42 +01:00
|
|
|
use rustc_session::lint;
|
2020-03-11 12:49:08 +01:00
|
|
|
use rustc_session::DiagnosticOutput;
|
2020-05-02 01:30:23 +03:00
|
|
|
use rustc_session::Session;
|
2020-01-01 19:25:28 +01:00
|
|
|
use rustc_span::source_map;
|
2020-01-01 19:30:57 +01:00
|
|
|
use rustc_span::symbol::sym;
|
2021-08-21 20:15:20 +00:00
|
|
|
use rustc_span::Span;
|
2013-08-15 16:28:54 -04:00
|
|
|
|
2020-12-29 23:16:16 -05:00
|
|
|
use std::cell::RefCell;
|
2021-09-29 17:20:52 +02:00
|
|
|
use std::lazy::SyncLazy;
|
2016-09-01 10:21:12 +03:00
|
|
|
use std::mem;
|
2018-12-08 20:30:23 +01:00
|
|
|
use std::rc::Rc;
|
2013-08-15 16:28:54 -04:00
|
|
|
|
2021-02-18 20:46:07 +01:00
|
|
|
use crate::clean::inline::build_external_trait;
|
2021-06-26 13:52:31 +02:00
|
|
|
use crate::clean::{self, ItemId, TraitWithExtraInfo};
|
2021-02-12 00:03:24 -05:00
|
|
|
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
|
2021-01-12 23:36:04 +01:00
|
|
|
use crate::formats::cache::Cache;
|
2020-01-04 10:58:32 -08:00
|
|
|
use crate::passes::{self, Condition::*, ConditionalPass};
|
2013-08-15 16:28:54 -04:00
|
|
|
|
2020-11-14 18:02:06 -05:00
|
|
|
crate use rustc_session::config::{DebuggingOptions, Input, Options};
|
2015-01-17 21:23:05 -08:00
|
|
|
|
2020-11-14 17:59:58 -05:00
|
|
|
crate struct DocContext<'tcx> {
|
|
|
|
crate tcx: TyCtxt<'tcx>,
|
2021-02-19 14:27:30 -08:00
|
|
|
/// Name resolver. Used for intra-doc links.
|
|
|
|
///
|
|
|
|
/// The `Rc<RefCell<...>>` wrapping is needed because that is what's returned by
|
|
|
|
/// [`Queries::expansion()`].
|
|
|
|
// FIXME: see if we can get rid of this RefCell somehow
|
2020-11-14 17:59:58 -05:00
|
|
|
crate resolver: Rc<RefCell<interface::BoxedResolver>>,
|
2020-10-18 11:27:16 -04:00
|
|
|
/// Used for normalization.
|
|
|
|
///
|
|
|
|
/// Most of this logic is copied from rustc_lint::late.
|
2021-02-20 17:12:22 -08:00
|
|
|
crate param_env: ParamEnv<'tcx>,
|
2021-01-12 23:36:04 +01:00
|
|
|
/// Later on moved through `clean::Crate` into `cache`
|
2021-02-12 14:33:32 +01:00
|
|
|
crate external_traits: Rc<RefCell<FxHashMap<DefId, clean::TraitWithExtraInfo>>>,
|
2018-02-21 18:33:42 -06:00
|
|
|
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
|
|
|
|
/// the same time.
|
2021-02-19 14:27:30 -08:00
|
|
|
crate active_extern_traits: FxHashSet<DefId>,
|
2016-09-01 10:21:12 +03:00
|
|
|
// The current set of type and lifetime substitutions,
|
|
|
|
// for expanding type aliases at the HIR level:
|
2019-04-20 19:46:19 +03:00
|
|
|
/// Table `DefId` of type parameter -> substituted type
|
2021-02-19 14:27:30 -08:00
|
|
|
crate ty_substs: FxHashMap<DefId, clean::Type>,
|
2019-04-20 19:46:19 +03:00
|
|
|
/// Table `DefId` of lifetime parameter -> substituted lifetime
|
2021-02-19 14:27:30 -08:00
|
|
|
crate lt_substs: FxHashMap<DefId, clean::Lifetime>,
|
2019-04-20 19:46:19 +03:00
|
|
|
/// Table `DefId` of const parameter -> substituted const
|
2021-02-19 14:27:30 -08:00
|
|
|
crate ct_substs: FxHashMap<DefId, clean::Constant>,
|
2019-06-21 12:23:05 +09:00
|
|
|
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
|
2021-02-19 14:27:30 -08:00
|
|
|
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
|
2019-04-22 22:52:51 +03:00
|
|
|
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
|
|
|
|
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
|
2021-02-19 14:27:30 -08:00
|
|
|
crate generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>,
|
2020-11-14 17:59:58 -05:00
|
|
|
crate auto_traits: Vec<DefId>,
|
2020-05-30 11:35:35 -04:00
|
|
|
/// The options given to rustdoc that could be relevant to a pass.
|
2020-11-14 17:59:58 -05:00
|
|
|
crate render_options: RenderOptions,
|
2020-08-08 14:57:35 -04:00
|
|
|
/// The traits in scope for a given module.
|
2020-07-29 21:11:14 -04:00
|
|
|
///
|
|
|
|
/// See `collect_intra_doc_links::traits_implemented_by` for more details.
|
2020-08-08 14:57:35 -04:00
|
|
|
/// `map<module, set<trait>>`
|
2021-02-22 09:21:47 -05:00
|
|
|
crate module_trait_cache: FxHashMap<DefId, FxHashSet<DefId>>,
|
2021-02-11 21:29:22 -05:00
|
|
|
/// This same cache is used throughout rustdoc, including in [`crate::html::render`].
|
2021-01-12 23:36:04 +01:00
|
|
|
crate cache: Cache,
|
2021-02-11 21:29:22 -05:00
|
|
|
/// Used by [`clean::inline`] to tell if an item has already been inlined.
|
2021-06-26 13:52:31 +02:00
|
|
|
crate inlined: FxHashSet<ItemId>,
|
2021-02-11 21:29:22 -05:00
|
|
|
/// Used by `calculate_doc_coverage`.
|
|
|
|
crate output_format: OutputFormat,
|
2014-03-05 16:36:01 +02:00
|
|
|
}
|
|
|
|
|
2018-12-08 20:30:23 +01:00
|
|
|
impl<'tcx> DocContext<'tcx> {
|
2021-02-12 01:59:20 -05:00
|
|
|
crate fn sess(&self) -> &'tcx Session {
|
2016-11-20 03:42:54 +02:00
|
|
|
&self.tcx.sess
|
2014-06-26 11:37:39 -07:00
|
|
|
}
|
2016-09-01 10:21:12 +03:00
|
|
|
|
2021-02-12 01:59:20 -05:00
|
|
|
crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
|
2021-02-20 17:12:22 -08:00
|
|
|
let old_param_env = mem::replace(&mut self.param_env, self.tcx.param_env(def_id));
|
2021-02-12 01:59:20 -05:00
|
|
|
let ret = f(self);
|
2021-02-20 17:12:22 -08:00
|
|
|
self.param_env = old_param_env;
|
2020-10-18 11:27:16 -04:00
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
2020-11-14 17:59:58 -05:00
|
|
|
crate fn enter_resolver<F, R>(&self, f: F) -> R
|
2019-12-22 17:42:04 -05:00
|
|
|
where
|
|
|
|
F: FnOnce(&mut resolve::Resolver<'_>) -> R,
|
|
|
|
{
|
2019-07-24 14:43:40 -04:00
|
|
|
self.resolver.borrow_mut().access(f)
|
2018-12-08 20:30:23 +01:00
|
|
|
}
|
|
|
|
|
2016-09-01 10:21:12 +03:00
|
|
|
/// Call the closure with the given parameters set as
|
|
|
|
/// the substitutions for a type alias' RHS.
|
2020-11-14 17:59:58 -05:00
|
|
|
crate fn enter_alias<F, R>(
|
2021-02-12 01:59:20 -05:00
|
|
|
&mut self,
|
2019-12-22 17:42:04 -05:00
|
|
|
ty_substs: FxHashMap<DefId, clean::Type>,
|
|
|
|
lt_substs: FxHashMap<DefId, clean::Lifetime>,
|
|
|
|
ct_substs: FxHashMap<DefId, clean::Constant>,
|
|
|
|
f: F,
|
|
|
|
) -> R
|
|
|
|
where
|
2021-02-12 01:59:20 -05:00
|
|
|
F: FnOnce(&mut Self) -> R,
|
2019-12-22 17:42:04 -05:00
|
|
|
{
|
2019-02-15 22:24:00 +00:00
|
|
|
let (old_tys, old_lts, old_cts) = (
|
2021-02-19 14:27:30 -08:00
|
|
|
mem::replace(&mut self.ty_substs, ty_substs),
|
|
|
|
mem::replace(&mut self.lt_substs, lt_substs),
|
|
|
|
mem::replace(&mut self.ct_substs, ct_substs),
|
2019-02-15 22:24:00 +00:00
|
|
|
);
|
2021-02-12 01:59:20 -05:00
|
|
|
let r = f(self);
|
2021-02-19 14:27:30 -08:00
|
|
|
self.ty_substs = old_tys;
|
|
|
|
self.lt_substs = old_lts;
|
|
|
|
self.ct_substs = old_cts;
|
2016-09-01 10:21:12 +03:00
|
|
|
r
|
|
|
|
}
|
2018-08-03 22:13:05 +02:00
|
|
|
|
2020-08-12 12:22:56 +02:00
|
|
|
/// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
|
2018-09-19 09:28:49 -05:00
|
|
|
/// (This avoids a slice-index-out-of-bounds panic.)
|
2021-06-27 09:28:17 +02:00
|
|
|
crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: ItemId) -> Option<HirId> {
|
|
|
|
match def_id {
|
2021-06-26 13:52:31 +02:00
|
|
|
ItemId::DefId(real_id) => {
|
2021-04-29 21:36:54 +02:00
|
|
|
real_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
|
|
|
|
}
|
2021-06-26 13:52:31 +02:00
|
|
|
// FIXME: Can this be `Some` for `Auto` or `Blanket`?
|
|
|
|
_ => None,
|
2019-03-04 09:00:30 +01:00
|
|
|
}
|
|
|
|
}
|
2013-08-15 16:28:54 -04:00
|
|
|
}
|
|
|
|
|
2018-04-24 18:29:04 -05:00
|
|
|
/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
|
|
|
|
///
|
2018-08-18 12:13:35 +02:00
|
|
|
/// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one
|
2018-04-24 18:29:04 -05:00
|
|
|
/// will be created for the handler.
|
2020-11-14 17:59:58 -05:00
|
|
|
crate fn new_handler(
|
2019-12-22 17:42:04 -05:00
|
|
|
error_format: ErrorOutputType,
|
|
|
|
source_map: Option<Lrc<source_map::SourceMap>>,
|
2019-12-29 23:07:23 +03:00
|
|
|
debugging_opts: &DebuggingOptions,
|
2020-01-09 11:18:47 +01:00
|
|
|
) -> rustc_errors::Handler {
|
2018-04-24 18:29:04 -05:00
|
|
|
let emitter: Box<dyn Emitter + sync::Send> = match error_format {
|
2019-03-25 11:16:58 +01:00
|
|
|
ErrorOutputType::HumanReadable(kind) => {
|
|
|
|
let (short, color_config) = kind.unzip();
|
|
|
|
Box::new(
|
|
|
|
EmitterWriter::stderr(
|
|
|
|
color_config,
|
2020-02-22 16:07:05 +02:00
|
|
|
source_map.map(|sm| sm as _),
|
2019-03-25 11:16:58 +01:00
|
|
|
short,
|
2019-12-29 23:07:23 +03:00
|
|
|
debugging_opts.teach,
|
|
|
|
debugging_opts.terminal_width,
|
2019-09-07 09:57:11 -04:00
|
|
|
false,
|
2019-12-22 17:42:04 -05:00
|
|
|
)
|
2020-04-02 16:44:47 +11:00
|
|
|
.ui_testing(debugging_opts.ui_testing),
|
2019-03-25 11:16:58 +01:00
|
|
|
)
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-03-25 11:16:58 +01:00
|
|
|
ErrorOutputType::Json { pretty, json_rendered } => {
|
2019-12-22 17:42:04 -05:00
|
|
|
let source_map = source_map.unwrap_or_else(|| {
|
2019-12-29 23:07:23 +03:00
|
|
|
Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty()))
|
2019-12-22 17:42:04 -05:00
|
|
|
});
|
2018-04-24 18:29:04 -05:00
|
|
|
Box::new(
|
2020-06-26 13:18:16 +01:00
|
|
|
JsonEmitter::stderr(
|
|
|
|
None,
|
|
|
|
source_map,
|
|
|
|
pretty,
|
|
|
|
json_rendered,
|
|
|
|
debugging_opts.terminal_width,
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
.ui_testing(debugging_opts.ui_testing),
|
2018-04-24 18:29:04 -05:00
|
|
|
)
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-04-24 18:29:04 -05:00
|
|
|
};
|
|
|
|
|
2020-01-09 11:18:47 +01:00
|
|
|
rustc_errors::Handler::with_emitter_and_flags(
|
|
|
|
emitter,
|
|
|
|
debugging_opts.diagnostic_handler_flags(true),
|
|
|
|
)
|
2018-04-24 18:29:04 -05:00
|
|
|
}
|
|
|
|
|
2020-12-11 21:37:14 -05:00
|
|
|
/// Parse, resolve, and typecheck the given crate.
|
2020-12-11 21:57:48 -05:00
|
|
|
crate fn create_config(
|
2020-12-11 21:37:14 -05:00
|
|
|
RustdocOptions {
|
2018-10-30 13:35:10 -05:00
|
|
|
input,
|
|
|
|
crate_name,
|
2019-07-20 16:34:41 -04:00
|
|
|
proc_macro_crate,
|
2018-10-30 13:35:10 -05:00
|
|
|
error_format,
|
|
|
|
libs,
|
|
|
|
externs,
|
2019-09-25 17:08:40 +02:00
|
|
|
mut cfgs,
|
2018-10-30 13:35:10 -05:00
|
|
|
codegen_options,
|
2020-08-25 09:22:26 -04:00
|
|
|
debugging_opts,
|
2018-10-30 13:35:10 -05:00
|
|
|
target,
|
|
|
|
edition,
|
|
|
|
maybe_sysroot,
|
|
|
|
lint_opts,
|
|
|
|
describe_lints,
|
|
|
|
lint_cap,
|
|
|
|
..
|
2020-12-11 21:37:14 -05:00
|
|
|
}: RustdocOptions,
|
|
|
|
) -> rustc_interface::Config {
|
2019-11-06 14:48:10 +01:00
|
|
|
// Add the doc cfg into the doc build.
|
2019-11-06 18:32:51 +01:00
|
|
|
cfgs.push("doc".to_string());
|
2019-09-25 17:08:40 +02:00
|
|
|
|
2018-10-30 13:35:10 -05:00
|
|
|
let cpath = Some(input.clone());
|
|
|
|
let input = Input::File(input);
|
2013-08-15 16:28:54 -04:00
|
|
|
|
2020-12-30 14:11:15 -05:00
|
|
|
// By default, rustdoc ignores all lints.
|
|
|
|
// Specifically unblock lints relevant to documentation or the lint machinery itself.
|
2020-12-29 23:16:16 -05:00
|
|
|
let mut lints_to_show = vec![
|
2021-05-19 23:13:26 -04:00
|
|
|
// it's unclear whether these should be part of rustdoc directly (#77364)
|
2020-12-29 23:16:16 -05:00
|
|
|
rustc_lint::builtin::MISSING_DOCS.name.to_string(),
|
2021-05-19 23:13:26 -04:00
|
|
|
rustc_lint::builtin::INVALID_DOC_ATTRIBUTES.name.to_string(),
|
2020-12-29 23:16:16 -05:00
|
|
|
// these are definitely not part of rustdoc, but we want to warn on them anyway.
|
|
|
|
rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
|
|
|
|
rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
|
2019-12-22 17:42:04 -05:00
|
|
|
];
|
2020-12-30 14:11:15 -05:00
|
|
|
lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string()));
|
2018-07-11 00:36:31 +02:00
|
|
|
|
2020-12-30 14:11:15 -05:00
|
|
|
let (lint_opts, lint_caps) = crate::lint::init_lints(lints_to_show, lint_opts, |lint| {
|
2021-04-22 23:40:43 -04:00
|
|
|
Some((lint.name_lower(), lint::Allow))
|
2020-04-26 14:07:13 +02:00
|
|
|
});
|
2014-06-04 14:35:58 -07:00
|
|
|
|
2020-05-02 01:30:23 +03:00
|
|
|
let crate_types =
|
|
|
|
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
|
2018-04-01 00:09:00 +02:00
|
|
|
// plays with error output here!
|
2014-05-18 16:56:13 +03:00
|
|
|
let sessopts = config::Options {
|
2017-08-06 22:54:09 -07:00
|
|
|
maybe_sysroot,
|
2018-10-30 13:35:10 -05:00
|
|
|
search_paths: libs,
|
2019-07-20 16:34:41 -04:00
|
|
|
crate_types,
|
2021-09-09 16:52:19 +02:00
|
|
|
lint_opts,
|
2020-08-25 09:18:57 -04:00
|
|
|
lint_cap,
|
2018-10-30 13:35:10 -05:00
|
|
|
cg: codegen_options,
|
2017-08-06 22:54:09 -07:00
|
|
|
externs,
|
2019-06-11 11:06:34 -07:00
|
|
|
target_triple: target,
|
2020-10-10 14:27:52 -04:00
|
|
|
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
|
2016-09-29 19:10:29 -07:00
|
|
|
actually_rustdoc: true,
|
2020-08-25 09:22:26 -04:00
|
|
|
debugging_opts,
|
2018-04-01 00:09:00 +02:00
|
|
|
error_format,
|
2018-04-20 14:47:23 -07:00
|
|
|
edition,
|
2018-06-23 15:09:21 +02:00
|
|
|
describe_lints,
|
2020-11-30 22:54:20 -05:00
|
|
|
crate_name,
|
2018-07-26 12:36:11 -06:00
|
|
|
..Options::default()
|
2013-08-15 16:28:54 -04:00
|
|
|
};
|
2018-07-01 00:27:44 +02:00
|
|
|
|
2020-12-11 21:37:14 -05:00
|
|
|
interface::Config {
|
2018-12-08 20:30:23 +01:00
|
|
|
opts: sessopts,
|
2019-10-11 23:48:16 +02:00
|
|
|
crate_cfg: interface::parse_cfgspecs(cfgs),
|
2018-12-08 20:30:23 +01:00
|
|
|
input,
|
|
|
|
input_path: cpath,
|
|
|
|
output_file: None,
|
|
|
|
output_dir: None,
|
|
|
|
file_loader: None,
|
|
|
|
diagnostic_output: DiagnosticOutput::Default,
|
|
|
|
stderr: None,
|
|
|
|
lint_caps,
|
2021-03-15 17:57:53 +08:00
|
|
|
parse_sess_created: None,
|
2021-09-21 01:49:47 +02:00
|
|
|
register_lints: Some(box crate::lint::register_lints),
|
2020-07-11 21:50:25 -04:00
|
|
|
override_queries: Some(|_sess, providers, _external_providers| {
|
2020-07-11 00:28:42 -04:00
|
|
|
// Most lints will require typechecking, so just don't run them.
|
2020-07-11 21:50:25 -04:00
|
|
|
providers.lint_mod = |_, _| {};
|
2020-07-17 08:47:04 +00:00
|
|
|
// Prevent `rustc_typeck::check_crate` from calling `typeck` on all bodies.
|
2020-07-11 21:50:25 -04:00
|
|
|
providers.typeck_item_bodies = |_, _| {};
|
2020-07-17 08:47:04 +00:00
|
|
|
// hack so that `used_trait_imports` won't try to call typeck
|
2020-07-11 21:50:25 -04:00
|
|
|
providers.used_trait_imports = |_, _| {
|
2021-09-29 17:20:52 +02:00
|
|
|
static EMPTY_SET: SyncLazy<FxHashSet<LocalDefId>> =
|
|
|
|
SyncLazy::new(FxHashSet::default);
|
2020-07-11 21:50:25 -04:00
|
|
|
&EMPTY_SET
|
|
|
|
};
|
2020-07-11 00:28:42 -04:00
|
|
|
// In case typeck does end up being called, don't ICE in case there were name resolution errors
|
2020-07-17 08:47:04 +00:00
|
|
|
providers.typeck = move |tcx, def_id| {
|
2020-07-09 09:13:59 -04:00
|
|
|
// Closures' tables come from their outermost function,
|
|
|
|
// as they are part of the same "inference environment".
|
2020-07-17 08:47:04 +00:00
|
|
|
// This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
|
2020-07-09 09:13:59 -04:00
|
|
|
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
|
|
|
|
if outer_def_id != def_id {
|
2020-07-17 08:47:04 +00:00
|
|
|
return tcx.typeck(outer_def_id);
|
2020-07-09 09:13:59 -04:00
|
|
|
}
|
|
|
|
|
2020-07-03 18:41:23 -04:00
|
|
|
let hir = tcx.hir();
|
2020-08-12 12:22:56 +02:00
|
|
|
let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(def_id)));
|
2020-07-03 18:41:23 -04:00
|
|
|
debug!("visiting body for {:?}", def_id);
|
2020-11-30 14:39:00 -05:00
|
|
|
EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
|
2020-07-17 08:47:04 +00:00
|
|
|
(rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
|
2020-07-03 18:41:23 -04:00
|
|
|
};
|
2020-06-20 16:41:39 -04:00
|
|
|
}),
|
2020-09-08 13:44:41 +02:00
|
|
|
make_codegen_backend: None,
|
2019-11-15 19:41:50 +01:00
|
|
|
registry: rustc_driver::diagnostics_registry(),
|
2020-12-11 21:37:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-11 21:57:48 -05:00
|
|
|
crate fn create_resolver<'a>(
|
2020-12-11 21:46:58 -05:00
|
|
|
queries: &Queries<'a>,
|
|
|
|
sess: &Session,
|
2020-12-16 16:02:15 -05:00
|
|
|
) -> Rc<RefCell<interface::BoxedResolver>> {
|
2021-08-21 20:15:20 +00:00
|
|
|
let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
|
|
|
|
let resolver = resolver.clone();
|
2021-03-31 22:33:07 -04:00
|
|
|
|
2021-08-21 20:14:56 +00:00
|
|
|
crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate)
|
2020-12-11 21:46:58 -05:00
|
|
|
}
|
|
|
|
|
2020-12-11 21:57:48 -05:00
|
|
|
crate fn run_global_ctxt(
|
2020-08-16 17:56:02 -04:00
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
resolver: Rc<RefCell<interface::BoxedResolver>>,
|
|
|
|
mut default_passes: passes::DefaultPassOption,
|
2021-02-28 22:41:05 -05:00
|
|
|
manual_passes: Vec<String>,
|
2020-08-16 17:56:02 -04:00
|
|
|
render_options: RenderOptions,
|
2021-01-28 18:00:07 -08:00
|
|
|
output_format: OutputFormat,
|
2021-02-11 21:29:22 -05:00
|
|
|
) -> (clean::Crate, RenderOptions, Cache) {
|
2020-08-23 22:57:47 -04:00
|
|
|
// Certain queries assume that some checks were run elsewhere
|
|
|
|
// (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
|
|
|
|
// so type-check everything other than function bodies in this crate before running lints.
|
|
|
|
|
|
|
|
// NOTE: this does not call `tcx.analysis()` so that we won't
|
|
|
|
// typeck function bodies or run the default rustc lints.
|
|
|
|
// (see `override_queries` in the `config`)
|
|
|
|
|
|
|
|
// HACK(jynelson) this calls an _extremely_ limited subset of `typeck`
|
|
|
|
// and might break if queries change their assumptions in the future.
|
|
|
|
|
|
|
|
// NOTE: This is copy/pasted from typeck/lib.rs and should be kept in sync with those changes.
|
|
|
|
tcx.sess.time("item_types_checking", || {
|
2021-07-18 18:12:17 +02:00
|
|
|
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
|
2020-08-23 22:57:47 -04:00
|
|
|
});
|
|
|
|
tcx.sess.abort_if_errors();
|
2020-08-16 17:40:47 -04:00
|
|
|
tcx.sess.time("missing_docs", || {
|
2020-08-23 22:57:47 -04:00
|
|
|
rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
|
|
|
|
});
|
2020-08-16 17:40:47 -04:00
|
|
|
tcx.sess.time("check_mod_attrs", || {
|
2021-07-18 18:12:17 +02:00
|
|
|
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
|
2020-08-16 17:40:47 -04:00
|
|
|
});
|
2021-02-27 22:02:41 +01:00
|
|
|
rustc_passes::stability::check_unused_or_stable_features(tcx);
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
let access_levels = AccessLevels {
|
2021-07-28 18:23:40 +03:00
|
|
|
map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(),
|
2020-08-23 22:57:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut ctxt = DocContext {
|
|
|
|
tcx,
|
|
|
|
resolver,
|
2021-02-20 17:12:22 -08:00
|
|
|
param_env: ParamEnv::empty(),
|
2020-08-23 22:57:47 -04:00
|
|
|
external_traits: Default::default(),
|
|
|
|
active_extern_traits: Default::default(),
|
|
|
|
ty_substs: Default::default(),
|
|
|
|
lt_substs: Default::default(),
|
|
|
|
ct_substs: Default::default(),
|
|
|
|
impl_trait_bounds: Default::default(),
|
|
|
|
generated_synthetics: Default::default(),
|
|
|
|
auto_traits: tcx
|
2021-05-11 14:22:02 +02:00
|
|
|
.all_traits(())
|
2020-08-23 22:57:47 -04:00
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id))
|
|
|
|
.collect(),
|
2021-02-22 09:21:47 -05:00
|
|
|
module_trait_cache: FxHashMap::default(),
|
2021-02-12 00:03:24 -05:00
|
|
|
cache: Cache::new(access_levels, render_options.document_private),
|
2021-02-11 21:29:22 -05:00
|
|
|
inlined: FxHashSet::default(),
|
|
|
|
output_format,
|
|
|
|
render_options,
|
2020-08-23 22:57:47 -04:00
|
|
|
};
|
2021-02-18 20:46:07 +01:00
|
|
|
|
|
|
|
// Small hack to force the Sized trait to be present.
|
|
|
|
//
|
|
|
|
// Note that in case of `#![no_core]`, the trait is not available.
|
|
|
|
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
|
|
|
|
let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
|
|
|
|
sized_trait.is_auto = true;
|
2021-04-01 13:26:29 -07:00
|
|
|
ctxt.external_traits
|
|
|
|
.borrow_mut()
|
|
|
|
.insert(sized_trait_did, TraitWithExtraInfo { trait_: sized_trait, is_notable: false });
|
2021-02-18 20:46:07 +01:00
|
|
|
}
|
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
debug!("crate: {:?}", tcx.hir().krate());
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2020-08-18 16:49:37 -04:00
|
|
|
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2021-03-23 11:04:09 -07:00
|
|
|
if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
|
2021-05-04 23:36:33 -04:00
|
|
|
let help = format!(
|
|
|
|
"The following guide may be of use:\n\
|
|
|
|
{}/rustdoc/how-to-write-documentation.html",
|
|
|
|
crate::DOC_RUST_LANG_ORG_CHANNEL
|
|
|
|
);
|
2021-03-23 11:04:09 -07:00
|
|
|
tcx.struct_lint_node(
|
|
|
|
crate::lint::MISSING_CRATE_LEVEL_DOCS,
|
2021-06-27 09:28:17 +02:00
|
|
|
DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
|
2021-03-23 11:04:09 -07:00
|
|
|
|lint| {
|
|
|
|
let mut diag =
|
|
|
|
lint.build("no documentation found for this crate's top-level module");
|
2021-05-04 23:36:33 -04:00
|
|
|
diag.help(&help);
|
2021-03-23 11:04:09 -07:00
|
|
|
diag.emit();
|
|
|
|
},
|
|
|
|
);
|
2020-08-23 22:57:47 -04:00
|
|
|
}
|
2019-12-01 20:12:49 +01:00
|
|
|
|
2021-02-28 22:41:05 -05:00
|
|
|
fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler, sp: Span) {
|
|
|
|
let mut msg =
|
|
|
|
diag.struct_span_warn(sp, &format!("the `#![doc({})]` attribute is deprecated", name));
|
|
|
|
msg.note(
|
2020-08-23 22:57:47 -04:00
|
|
|
"see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
2020-08-31 13:16:50 +02:00
|
|
|
for more information",
|
2020-08-23 22:57:47 -04:00
|
|
|
);
|
2019-12-22 17:42:04 -05:00
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
if name == "no_default_passes" {
|
|
|
|
msg.help("you may want to use `#![doc(document_private_items)]`");
|
2021-02-28 22:51:35 -05:00
|
|
|
} else if name.starts_with("plugins") {
|
|
|
|
msg.warn("`#![doc(plugins = \"...\")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>");
|
2020-08-23 22:57:47 -04:00
|
|
|
}
|
2018-07-27 10:22:16 -05:00
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
msg.emit();
|
|
|
|
}
|
|
|
|
|
2021-02-28 22:41:05 -05:00
|
|
|
let parse_pass = |name: &str, sp: Option<Span>| {
|
|
|
|
if let Some(pass) = passes::find_pass(name) {
|
|
|
|
Some(ConditionalPass::always(pass))
|
|
|
|
} else {
|
|
|
|
let msg = &format!("ignoring unknown pass `{}`", name);
|
|
|
|
let mut warning = if let Some(sp) = sp {
|
|
|
|
tcx.sess.struct_span_warn(sp, msg)
|
|
|
|
} else {
|
|
|
|
tcx.sess.struct_warn(msg)
|
|
|
|
};
|
|
|
|
if name == "collapse-docs" {
|
|
|
|
warning.note("the `collapse-docs` pass was removed in #80261 <https://github.com/rust-lang/rust/pull/80261>");
|
|
|
|
}
|
|
|
|
warning.emit();
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut manual_passes: Vec<_> =
|
|
|
|
manual_passes.into_iter().flat_map(|name| parse_pass(&name, None)).collect();
|
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
// Process all of the crate attributes, extracting plugin metadata along
|
|
|
|
// with the passes which we are supposed to run.
|
2021-03-23 11:04:09 -07:00
|
|
|
for attr in krate.module.attrs.lists(sym::doc) {
|
2020-08-23 22:57:47 -04:00
|
|
|
let diag = ctxt.sess().diagnostic();
|
|
|
|
|
|
|
|
let name = attr.name_or_empty();
|
|
|
|
if attr.is_word() {
|
|
|
|
if name == sym::no_default_passes {
|
2021-02-28 22:41:05 -05:00
|
|
|
report_deprecated_attr("no_default_passes", diag, attr.span());
|
2020-08-23 22:57:47 -04:00
|
|
|
if default_passes == passes::DefaultPassOption::Default {
|
|
|
|
default_passes = passes::DefaultPassOption::None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if let Some(value) = attr.value_str() {
|
2021-02-28 22:41:05 -05:00
|
|
|
match name {
|
2020-08-23 22:57:47 -04:00
|
|
|
sym::passes => {
|
2021-02-28 22:41:05 -05:00
|
|
|
report_deprecated_attr("passes = \"...\"", diag, attr.span());
|
2018-07-27 10:22:16 -05:00
|
|
|
}
|
2020-08-23 22:57:47 -04:00
|
|
|
sym::plugins => {
|
2021-02-28 22:41:05 -05:00
|
|
|
report_deprecated_attr("plugins = \"...\"", diag, attr.span());
|
2020-08-23 22:57:47 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
_ => continue,
|
|
|
|
};
|
|
|
|
for name in value.as_str().split_whitespace() {
|
2021-02-28 22:41:05 -05:00
|
|
|
let span = attr.name_value_literal_span().unwrap_or(attr.span());
|
|
|
|
manual_passes.extend(parse_pass(name, Some(span)));
|
2020-08-23 22:57:47 -04:00
|
|
|
}
|
|
|
|
}
|
2018-07-27 10:22:16 -05:00
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
if attr.is_word() && name == sym::document_private_items {
|
|
|
|
ctxt.render_options.document_private = true;
|
|
|
|
}
|
|
|
|
}
|
2018-07-27 10:22:16 -05:00
|
|
|
|
2021-02-28 22:41:05 -05:00
|
|
|
let passes = passes::defaults(default_passes).iter().copied().chain(manual_passes);
|
2020-08-23 22:57:47 -04:00
|
|
|
info!("Executing passes");
|
|
|
|
|
|
|
|
for p in passes {
|
|
|
|
let run = match p.condition {
|
|
|
|
Always => true,
|
|
|
|
WhenDocumentPrivate => ctxt.render_options.document_private,
|
|
|
|
WhenNotDocumentPrivate => !ctxt.render_options.document_private,
|
|
|
|
WhenNotDocumentHidden => !ctxt.render_options.document_hidden,
|
|
|
|
};
|
|
|
|
if run {
|
|
|
|
debug!("running pass {}", p.pass.name);
|
2021-02-12 01:11:32 -05:00
|
|
|
krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
|
2020-08-23 22:57:47 -04:00
|
|
|
}
|
|
|
|
}
|
2018-07-27 10:22:16 -05:00
|
|
|
|
2020-08-23 22:57:47 -04:00
|
|
|
ctxt.sess().abort_if_errors();
|
2018-07-28 00:06:51 -05:00
|
|
|
|
2021-02-11 21:29:22 -05:00
|
|
|
let render_options = ctxt.render_options;
|
|
|
|
let mut cache = ctxt.cache;
|
Give precedence to `html_root_url` over `--extern-html-root-url` by default, but add a way to opt-in to the previous behavior
## What is an HTML root url?
It tells rustdoc where it should link when documentation for a crate is
not available locally; for example, when a crate is a dependency of a
crate documented with `cargo doc --no-deps`.
## What is the difference between `html_root_url` and `--extern-html-root-url`?
Both of these tell rustdoc what the HTML root should be set to.
`doc(html_root_url)` is set by the crate author, while
`--extern-html-root-url` is set by the person documenting the crate.
These are often different. For example, docs.rs uses
`--extern-html-root-url https://docs.rs/crate-name/version` to ensure
all crates have documentation, even if `html_root_url` is not set.
Conversely, crates such as Rocket set `doc(html_root_url =
"https://api.rocket.rs")`, because they prefer users to view the
documentation on their own site.
Crates also set `html_root_url` to ensure they have
documentation when building locally when offline. This is unfortunate to
require, because it's more work from the library author. It also makes
it impossible to distinguish between crates that want to be viewed on a
different site (e.g. Rocket) and crates that just want documentation to
be visible offline at all (e.g. Tokio). I have authored a separate
change to the API guidelines to no longer recommend doing this:
https://github.com/rust-lang/api-guidelines/pull/230.
## Why change the default?
In the past, docs.rs has been the main user of `--extern-html-root-url`.
However, it's useful for other projects as well. In particular, Cargo
wants to pass it by default when running `--no-deps`
(https://github.com/rust-lang/cargo/issues/8296).
Unfortunately, for these other use cases, the priority order is
inverted. They want to give *precedence* to the URL the crate picks, and
only fall back to the `--extern-html-root` if no `html_root_url` is
present. That allows passing `--extern-html-root` unconditionally,
without having to parse the source code to see what attributes are
present.
For docs.rs, however, we still want to keep the old behavior, so that
all links on docs.rs stay on the site.
2021-03-04 15:03:22 -05:00
|
|
|
krate = tcx.sess.time("create_format_cache", || cache.populate(krate, tcx, &render_options));
|
2021-02-11 21:29:22 -05:00
|
|
|
|
2020-12-26 14:22:08 +01:00
|
|
|
// The main crate doc comments are always collapsed.
|
|
|
|
krate.collapsed = true;
|
|
|
|
|
2021-02-11 21:29:22 -05:00
|
|
|
(krate, render_options, cache)
|
2013-08-15 16:28:54 -04:00
|
|
|
}
|
2019-06-21 12:23:05 +09:00
|
|
|
|
2020-11-05 14:33:23 +01:00
|
|
|
/// Due to <https://github.com/rust-lang/rust/pull/73566>,
|
2020-07-03 18:41:23 -04:00
|
|
|
/// the name resolution pass may find errors that are never emitted.
|
|
|
|
/// If typeck is called after this happens, then we'll get an ICE:
|
|
|
|
/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
|
2020-07-10 18:07:31 -04:00
|
|
|
struct EmitIgnoredResolutionErrors<'tcx> {
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2020-07-03 18:41:23 -04:00
|
|
|
}
|
|
|
|
|
2020-07-10 18:07:31 -04:00
|
|
|
impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
|
|
|
|
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
2020-07-10 17:59:29 -04:00
|
|
|
Self { tcx }
|
2020-07-03 18:41:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 18:07:31 -04:00
|
|
|
impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
|
2020-07-10 17:59:29 -04:00
|
|
|
type Map = Map<'tcx>;
|
2020-07-03 18:41:23 -04:00
|
|
|
|
|
|
|
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
2020-07-09 09:13:59 -04:00
|
|
|
// We need to recurse into nested closures,
|
|
|
|
// since those will fallback to the parent for type checking.
|
2020-07-10 17:59:29 -04:00
|
|
|
NestedVisitorMap::OnlyBodies(self.tcx.hir())
|
2020-07-03 18:41:23 -04:00
|
|
|
}
|
|
|
|
|
2020-07-10 17:59:29 -04:00
|
|
|
fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
|
2020-07-10 17:24:17 -04:00
|
|
|
debug!("visiting path {:?}", path);
|
2020-07-03 18:41:23 -04:00
|
|
|
if path.res == Res::Err {
|
|
|
|
// We have less context here than in rustc_resolve,
|
|
|
|
// so we can only emit the name and span.
|
|
|
|
// However we can give a hint that rustc_resolve will have more info.
|
|
|
|
let label = format!(
|
|
|
|
"could not resolve path `{}`",
|
|
|
|
path.segments
|
|
|
|
.iter()
|
|
|
|
.map(|segment| segment.ident.as_str().to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("::")
|
|
|
|
);
|
|
|
|
let mut err = rustc_errors::struct_span_err!(
|
2020-07-10 17:59:29 -04:00
|
|
|
self.tcx.sess,
|
2020-07-03 18:41:23 -04:00
|
|
|
path.span,
|
|
|
|
E0433,
|
|
|
|
"failed to resolve: {}",
|
|
|
|
label
|
|
|
|
);
|
|
|
|
err.span_label(path.span, label);
|
|
|
|
err.note("this error was originally ignored because you are running `rustdoc`");
|
2020-07-10 17:51:38 -04:00
|
|
|
err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error");
|
2020-07-03 18:41:23 -04:00
|
|
|
err.emit();
|
|
|
|
}
|
2020-07-10 17:50:03 -04:00
|
|
|
// We could have an outer resolution that succeeded,
|
|
|
|
// but with generic parameters that failed.
|
|
|
|
// Recurse into the segments so we catch those too.
|
|
|
|
intravisit::walk_path(self, path);
|
2020-07-03 18:41:23 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-21 12:23:05 +09:00
|
|
|
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
|
|
|
|
/// for `impl Trait` in argument position.
|
2019-07-09 16:37:55 +09:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
2020-11-14 17:59:58 -05:00
|
|
|
crate enum ImplTraitParam {
|
2021-05-08 10:04:03 +02:00
|
|
|
DefId(DefId),
|
2019-06-21 12:23:05 +09:00
|
|
|
ParamIndex(u32),
|
|
|
|
}
|
|
|
|
|
2021-05-08 10:04:03 +02:00
|
|
|
impl From<DefId> for ImplTraitParam {
|
|
|
|
fn from(did: DefId) -> Self {
|
2019-06-21 12:23:05 +09:00
|
|
|
ImplTraitParam::DefId(did)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u32> for ImplTraitParam {
|
|
|
|
fn from(idx: u32) -> Self {
|
|
|
|
ImplTraitParam::ParamIndex(idx)
|
|
|
|
}
|
|
|
|
}
|