]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
781aab86 | 2 | use rustc_data_structures::sync::Lrc; |
2b03887a | 3 | use rustc_data_structures::unord::UnordSet; |
c620b35d | 4 | use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter}; |
ba9703b0 | 5 | use rustc_errors::json::JsonEmitter; |
c620b35d | 6 | use rustc_errors::{codes::*, ErrorGuaranteed, TerminalUrl}; |
60c5eb7d | 7 | use rustc_feature::UnstableFeatures; |
9ffffee4 FG |
8 | use rustc_hir::def::Res; |
9 | use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; | |
5099ac24 | 10 | use rustc_hir::intravisit::{self, Visitor}; |
9ffffee4 | 11 | use rustc_hir::{HirId, Path}; |
5099ac24 | 12 | use rustc_interface::interface; |
add651ee | 13 | use rustc_lint::{late_lint_mod, MissingDoc}; |
5099ac24 | 14 | use rustc_middle::hir::nested_filter; |
fc512014 | 15 | use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; |
9ffffee4 | 16 | use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks}; |
ed00b5ec | 17 | use rustc_session::lint; |
f9f354fc | 18 | use rustc_session::Session; |
dfeec247 | 19 | use rustc_span::symbol::sym; |
9ffffee4 | 20 | use rustc_span::{source_map, Span}; |
1a4d82fc | 21 | |
6a06907d | 22 | use std::cell::RefCell; |
c620b35d | 23 | use std::io; |
9e0c209e | 24 | use std::mem; |
532ac7d7 | 25 | use std::rc::Rc; |
923072b8 | 26 | use std::sync::LazyLock; |
ed00b5ec | 27 | use std::sync::{atomic::AtomicBool, Arc}; |
1a4d82fc | 28 | |
6a06907d | 29 | use crate::clean::inline::build_external_trait; |
2b03887a | 30 | use crate::clean::{self, ItemId}; |
6a06907d | 31 | use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; |
5869c6ff | 32 | use crate::formats::cache::Cache; |
a2a8927a | 33 | use crate::passes::{self, Condition::*}; |
1a4d82fc | 34 | |
064997fb | 35 | pub(crate) use rustc_session::config::{Input, Options, UnstableOptions}; |
85aaf69f | 36 | |
923072b8 FG |
37 | pub(crate) struct DocContext<'tcx> { |
38 | pub(crate) tcx: TyCtxt<'tcx>, | |
fc512014 XL |
39 | /// Used for normalization. |
40 | /// | |
41 | /// Most of this logic is copied from rustc_lint::late. | |
923072b8 | 42 | pub(crate) param_env: ParamEnv<'tcx>, |
5869c6ff | 43 | /// Later on moved through `clean::Crate` into `cache` |
2b03887a | 44 | pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>, |
0531ce1d XL |
45 | /// Used while populating `external_traits` to ensure we don't process the same trait twice at |
46 | /// the same time. | |
9ffffee4 | 47 | pub(crate) active_extern_traits: DefIdSet, |
c620b35d FG |
48 | /// The current set of parameter instantiations for expanding type aliases at the HIR level. |
49 | /// | |
50 | /// Maps from the `DefId` of a lifetime or type parameter to the | |
51 | /// generic argument it's currently instantiated to in this context. | |
52 | // FIXME(#82852): We don't record const params since we don't visit const exprs at all and | |
53 | // therefore wouldn't use the corresp. generic arg anyway. Add support for them. | |
54 | pub(crate) args: DefIdMap<clean::GenericArg>, | |
49aad941 | 55 | pub(crate) current_type_aliases: DefIdMap<usize>, |
e1599b0c | 56 | /// Table synthetic type parameter for `impl Trait` in argument position -> bounds |
923072b8 | 57 | pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>, |
48663c56 XL |
58 | /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. |
59 | // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. | |
923072b8 FG |
60 | pub(crate) generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>, |
61 | pub(crate) auto_traits: Vec<DefId>, | |
f035d41b | 62 | /// The options given to rustdoc that could be relevant to a pass. |
923072b8 | 63 | pub(crate) render_options: RenderOptions, |
6a06907d | 64 | /// This same cache is used throughout rustdoc, including in [`crate::html::render`]. |
923072b8 | 65 | pub(crate) cache: Cache, |
6a06907d | 66 | /// Used by [`clean::inline`] to tell if an item has already been inlined. |
923072b8 | 67 | pub(crate) inlined: FxHashSet<ItemId>, |
6a06907d | 68 | /// Used by `calculate_doc_coverage`. |
923072b8 | 69 | pub(crate) output_format: OutputFormat, |
064997fb FG |
70 | /// Used by `strip_private`. |
71 | pub(crate) show_coverage: bool, | |
476ff2be | 72 | } |
1a4d82fc | 73 | |
532ac7d7 | 74 | impl<'tcx> DocContext<'tcx> { |
923072b8 | 75 | pub(crate) fn sess(&self) -> &'tcx Session { |
3c0e092e | 76 | self.tcx.sess |
1a4d82fc | 77 | } |
9e0c209e | 78 | |
923072b8 FG |
79 | pub(crate) fn with_param_env<T, F: FnOnce(&mut Self) -> T>( |
80 | &mut self, | |
81 | def_id: DefId, | |
82 | f: F, | |
83 | ) -> T { | |
6a06907d XL |
84 | let old_param_env = mem::replace(&mut self.param_env, self.tcx.param_env(def_id)); |
85 | let ret = f(self); | |
86 | self.param_env = old_param_env; | |
fc512014 XL |
87 | ret |
88 | } | |
89 | ||
9e0c209e | 90 | /// Call the closure with the given parameters set as |
c620b35d | 91 | /// the generic parameters for a type alias' RHS. |
49aad941 FG |
92 | pub(crate) fn enter_alias<F, R>( |
93 | &mut self, | |
c620b35d | 94 | args: DefIdMap<clean::GenericArg>, |
49aad941 FG |
95 | def_id: DefId, |
96 | f: F, | |
97 | ) -> R | |
60c5eb7d | 98 | where |
6a06907d | 99 | F: FnOnce(&mut Self) -> R, |
60c5eb7d | 100 | { |
add651ee | 101 | let old_args = mem::replace(&mut self.args, args); |
49aad941 | 102 | *self.current_type_aliases.entry(def_id).or_insert(0) += 1; |
6a06907d | 103 | let r = f(self); |
add651ee | 104 | self.args = old_args; |
49aad941 FG |
105 | if let Some(count) = self.current_type_aliases.get_mut(&def_id) { |
106 | *count -= 1; | |
107 | if *count == 0 { | |
108 | self.current_type_aliases.remove(&def_id); | |
109 | } | |
110 | } | |
9e0c209e SL |
111 | r |
112 | } | |
b7449926 | 113 | |
4b012472 | 114 | /// Like `tcx.local_def_id_to_hir_id()`, but skips calling it on fake DefIds. |
0bf4aa26 | 115 | /// (This avoids a slice-index-out-of-bounds panic.) |
923072b8 | 116 | pub(crate) fn as_local_hir_id(tcx: TyCtxt<'_>, item_id: ItemId) -> Option<HirId> { |
04454e1e | 117 | match item_id { |
136023e0 | 118 | ItemId::DefId(real_id) => { |
4b012472 | 119 | real_id.as_local().map(|def_id| tcx.local_def_id_to_hir_id(def_id)) |
17df50a5 | 120 | } |
136023e0 XL |
121 | // FIXME: Can this be `Some` for `Auto` or `Blanket`? |
122 | _ => None, | |
532ac7d7 XL |
123 | } |
124 | } | |
a7813a04 | 125 | } |
1a4d82fc | 126 | |
4b012472 | 127 | /// Creates a new `DiagCtxt` that can be used to emit warnings and errors. |
94b46f34 | 128 | /// |
b7449926 | 129 | /// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one |
4b012472 FG |
130 | /// will be created for the `DiagCtxt`. |
131 | pub(crate) fn new_dcx( | |
60c5eb7d XL |
132 | error_format: ErrorOutputType, |
133 | source_map: Option<Lrc<source_map::SourceMap>>, | |
064997fb FG |
134 | diagnostic_width: Option<usize>, |
135 | unstable_opts: &UnstableOptions, | |
4b012472 | 136 | ) -> rustc_errors::DiagCtxt { |
9ffffee4 FG |
137 | let fallback_bundle = rustc_errors::fallback_fluent_bundle( |
138 | rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), | |
139 | false, | |
140 | ); | |
781aab86 | 141 | let emitter: Box<DynEmitter> = match error_format { |
48663c56 XL |
142 | ErrorOutputType::HumanReadable(kind) => { |
143 | let (short, color_config) = kind.unzip(); | |
144 | Box::new( | |
c620b35d | 145 | HumanEmitter::new(stderr_destination(color_config), fallback_bundle) |
add651ee FG |
146 | .sm(source_map.map(|sm| sm as _)) |
147 | .short_message(short) | |
148 | .teach(unstable_opts.teach) | |
149 | .diagnostic_width(diagnostic_width) | |
150 | .track_diagnostics(unstable_opts.track_diagnostics) | |
151 | .ui_testing(unstable_opts.ui_testing), | |
48663c56 | 152 | ) |
60c5eb7d | 153 | } |
48663c56 | 154 | ErrorOutputType::Json { pretty, json_rendered } => { |
60c5eb7d | 155 | let source_map = source_map.unwrap_or_else(|| { |
dfeec247 | 156 | Lrc::new(source_map::SourceMap::new(source_map::FilePathMapping::empty())) |
60c5eb7d | 157 | }); |
94b46f34 | 158 | Box::new( |
c620b35d FG |
159 | JsonEmitter::new( |
160 | Box::new(io::BufWriter::new(io::stderr())), | |
f035d41b | 161 | source_map, |
04454e1e | 162 | fallback_bundle, |
f035d41b XL |
163 | pretty, |
164 | json_rendered, | |
f035d41b | 165 | ) |
c620b35d FG |
166 | .ui_testing(unstable_opts.ui_testing) |
167 | .diagnostic_width(diagnostic_width) | |
168 | .track_diagnostics(unstable_opts.track_diagnostics) | |
169 | .terminal_url(TerminalUrl::No), | |
94b46f34 | 170 | ) |
60c5eb7d | 171 | } |
94b46f34 XL |
172 | }; |
173 | ||
c620b35d | 174 | rustc_errors::DiagCtxt::new(emitter).with_flags(unstable_opts.dcx_flags(true)) |
94b46f34 XL |
175 | } |
176 | ||
fc512014 | 177 | /// Parse, resolve, and typecheck the given crate. |
923072b8 | 178 | pub(crate) fn create_config( |
fc512014 | 179 | RustdocOptions { |
a1dfa0c6 XL |
180 | input, |
181 | crate_name, | |
e1599b0c | 182 | proc_macro_crate, |
a1dfa0c6 | 183 | error_format, |
064997fb | 184 | diagnostic_width, |
a1dfa0c6 XL |
185 | libs, |
186 | externs, | |
e74abb32 | 187 | mut cfgs, |
5e7ed085 | 188 | check_cfgs, |
a1dfa0c6 | 189 | codegen_options, |
064997fb | 190 | unstable_opts, |
a1dfa0c6 XL |
191 | target, |
192 | edition, | |
193 | maybe_sysroot, | |
194 | lint_opts, | |
195 | describe_lints, | |
196 | lint_cap, | |
5099ac24 | 197 | scrape_examples_options, |
781aab86 | 198 | expanded_args, |
a1dfa0c6 | 199 | .. |
fc512014 | 200 | }: RustdocOptions, |
9ffffee4 | 201 | RenderOptions { document_private, .. }: &RenderOptions, |
ed00b5ec | 202 | using_internal_features: Arc<AtomicBool>, |
fc512014 | 203 | ) -> rustc_interface::Config { |
60c5eb7d XL |
204 | // Add the doc cfg into the doc build. |
205 | cfgs.push("doc".to_string()); | |
e74abb32 | 206 | |
a1dfa0c6 | 207 | let input = Input::File(input); |
1a4d82fc | 208 | |
6a06907d XL |
209 | // By default, rustdoc ignores all lints. |
210 | // Specifically unblock lints relevant to documentation or the lint machinery itself. | |
211 | let mut lints_to_show = vec![ | |
17df50a5 | 212 | // it's unclear whether these should be part of rustdoc directly (#77364) |
6a06907d | 213 | rustc_lint::builtin::MISSING_DOCS.name.to_string(), |
17df50a5 | 214 | rustc_lint::builtin::INVALID_DOC_ATTRIBUTES.name.to_string(), |
6a06907d XL |
215 | // these are definitely not part of rustdoc, but we want to warn on them anyway. |
216 | rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(), | |
217 | rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(), | |
5e7ed085 | 218 | rustc_lint::builtin::UNEXPECTED_CFGS.name.to_string(), |
04454e1e FG |
219 | // this lint is needed to support `#[expect]` attributes |
220 | rustc_lint::builtin::UNFULFILLED_LINT_EXPECTATIONS.name.to_string(), | |
60c5eb7d | 221 | ]; |
6a06907d | 222 | lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string())); |
8faf50e0 | 223 | |
6a06907d | 224 | let (lint_opts, lint_caps) = crate::lint::init_lints(lints_to_show, lint_opts, |lint| { |
17df50a5 | 225 | Some((lint.name_lower(), lint::Allow)) |
f9f354fc | 226 | }); |
1a4d82fc | 227 | |
f9f354fc XL |
228 | let crate_types = |
229 | if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; | |
353b0b11 FG |
230 | let resolve_doc_links = |
231 | if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported }; | |
5099ac24 | 232 | let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false); |
83c7162d | 233 | // plays with error output here! |
1a4d82fc | 234 | let sessopts = config::Options { |
3b2f2976 | 235 | maybe_sysroot, |
a1dfa0c6 | 236 | search_paths: libs, |
e1599b0c | 237 | crate_types, |
c295e0f8 | 238 | lint_opts, |
1b1a35ee | 239 | lint_cap, |
a1dfa0c6 | 240 | cg: codegen_options, |
3b2f2976 | 241 | externs, |
e1599b0c | 242 | target_triple: target, |
fc512014 | 243 | unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), |
c30ab7b3 | 244 | actually_rustdoc: true, |
9ffffee4 | 245 | resolve_doc_links, |
064997fb | 246 | unstable_opts, |
83c7162d | 247 | error_format, |
064997fb | 248 | diagnostic_width, |
83c7162d | 249 | edition, |
8faf50e0 | 250 | describe_lints, |
fc512014 | 251 | crate_name, |
5099ac24 | 252 | test, |
b7449926 | 253 | ..Options::default() |
a7813a04 | 254 | }; |
94b46f34 | 255 | |
fc512014 | 256 | interface::Config { |
532ac7d7 | 257 | opts: sessopts, |
ed00b5ec FG |
258 | crate_cfg: cfgs, |
259 | crate_check_cfg: check_cfgs, | |
532ac7d7 | 260 | input, |
532ac7d7 XL |
261 | output_file: None, |
262 | output_dir: None, | |
263 | file_loader: None, | |
9ffffee4 | 264 | locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES, |
532ac7d7 | 265 | lint_caps, |
c620b35d | 266 | psess_created: None, |
ed00b5ec | 267 | hash_untracked_state: None, |
064997fb | 268 | register_lints: Some(Box::new(crate::lint::register_lints)), |
781aab86 | 269 | override_queries: Some(|_sess, providers| { |
add651ee | 270 | // We do not register late module lints, so this only runs `MissingDoc`. |
3dfed10e | 271 | // Most lints will require typechecking, so just don't run them. |
add651ee | 272 | providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc); |
3dfed10e XL |
273 | // hack so that `used_trait_imports` won't try to call typeck |
274 | providers.used_trait_imports = |_, _| { | |
2b03887a | 275 | static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default); |
3dfed10e XL |
276 | &EMPTY_SET |
277 | }; | |
278 | // In case typeck does end up being called, don't ICE in case there were name resolution errors | |
279 | providers.typeck = move |tcx, def_id| { | |
280 | // Closures' tables come from their outermost function, | |
281 | // as they are part of the same "inference environment". | |
282 | // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`) | |
3c0e092e XL |
283 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); |
284 | if typeck_root_def_id != def_id { | |
285 | return tcx.typeck(typeck_root_def_id); | |
3dfed10e XL |
286 | } |
287 | ||
288 | let hir = tcx.hir(); | |
064997fb | 289 | let body = hir.body(hir.body_owned_by(def_id)); |
add651ee | 290 | debug!("visiting body for {def_id:?}"); |
fc512014 | 291 | EmitIgnoredResolutionErrors::new(tcx).visit_body(body); |
3dfed10e XL |
292 | (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) |
293 | }; | |
294 | }), | |
1b1a35ee | 295 | make_codegen_backend: None, |
60c5eb7d | 296 | registry: rustc_driver::diagnostics_registry(), |
add651ee | 297 | ice_file: None, |
ed00b5ec | 298 | using_internal_features, |
781aab86 | 299 | expanded_args, |
fc512014 XL |
300 | } |
301 | } | |
94b46f34 | 302 | |
923072b8 | 303 | pub(crate) fn run_global_ctxt( |
3dfed10e | 304 | tcx: TyCtxt<'_>, |
a2a8927a | 305 | show_coverage: bool, |
3dfed10e | 306 | render_options: RenderOptions, |
5869c6ff | 307 | output_format: OutputFormat, |
c620b35d | 308 | ) -> Result<(clean::Crate, RenderOptions, Cache), ErrorGuaranteed> { |
3dfed10e XL |
309 | // Certain queries assume that some checks were run elsewhere |
310 | // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), | |
311 | // so type-check everything other than function bodies in this crate before running lints. | |
312 | ||
313 | // NOTE: this does not call `tcx.analysis()` so that we won't | |
314 | // typeck function bodies or run the default rustc lints. | |
315 | // (see `override_queries` in the `config`) | |
316 | ||
ed00b5ec FG |
317 | // NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes. |
318 | let _ = tcx.sess.time("wf_checking", || { | |
319 | tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) | |
320 | }); | |
ed00b5ec | 321 | |
c620b35d FG |
322 | if let Some(guar) = tcx.dcx().has_errors() { |
323 | return Err(guar); | |
324 | } | |
325 | ||
add651ee | 326 | tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx)); |
3dfed10e | 327 | tcx.sess.time("check_mod_attrs", || { |
c295e0f8 | 328 | tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) |
3dfed10e | 329 | }); |
6a06907d | 330 | rustc_passes::stability::check_unused_or_stable_features(tcx); |
60c5eb7d | 331 | |
2b03887a FG |
332 | let auto_traits = |
333 | tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); | |
b7449926 | 334 | |
3dfed10e XL |
335 | let mut ctxt = DocContext { |
336 | tcx, | |
6a06907d | 337 | param_env: ParamEnv::empty(), |
3dfed10e XL |
338 | external_traits: Default::default(), |
339 | active_extern_traits: Default::default(), | |
add651ee | 340 | args: Default::default(), |
49aad941 | 341 | current_type_aliases: Default::default(), |
3dfed10e | 342 | impl_trait_bounds: Default::default(), |
3dfed10e | 343 | generated_synthetics: Default::default(), |
5099ac24 | 344 | auto_traits, |
add651ee | 345 | cache: Cache::new(render_options.document_private, render_options.document_hidden), |
6a06907d XL |
346 | inlined: FxHashSet::default(), |
347 | output_format, | |
3dfed10e | 348 | render_options, |
064997fb | 349 | show_coverage, |
3dfed10e | 350 | }; |
6a06907d | 351 | |
9ffffee4 FG |
352 | for cnum in tcx.crates(()) { |
353 | crate::visit_lib::lib_embargo_visit_item(&mut ctxt, cnum.as_def_id()); | |
354 | } | |
355 | ||
6a06907d XL |
356 | // Small hack to force the Sized trait to be present. |
357 | // | |
358 | // Note that in case of `#![no_core]`, the trait is not available. | |
359 | if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() { | |
064997fb | 360 | let sized_trait = build_external_trait(&mut ctxt, sized_trait_did); |
2b03887a | 361 | ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait); |
6a06907d XL |
362 | } |
363 | ||
3dfed10e XL |
364 | debug!("crate: {:?}", tcx.hir().krate()); |
365 | ||
366 | let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt)); | |
367 | ||
49aad941 | 368 | if krate.module.doc_value().is_empty() { |
17df50a5 XL |
369 | let help = format!( |
370 | "The following guide may be of use:\n\ | |
371 | {}/rustdoc/how-to-write-documentation.html", | |
372 | crate::DOC_RUST_LANG_ORG_CHANNEL | |
373 | ); | |
c0240ec0 | 374 | tcx.node_lint( |
cdc7bbd5 | 375 | crate::lint::MISSING_CRATE_LEVEL_DOCS, |
04454e1e | 376 | DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(), |
2b03887a | 377 | "no documentation found for this crate's top-level module", |
4b012472 FG |
378 | |lint| { |
379 | lint.help(help); | |
380 | }, | |
cdc7bbd5 | 381 | ); |
3dfed10e | 382 | } |
b7449926 | 383 | |
4b012472 | 384 | fn report_deprecated_attr(name: &str, dcx: &rustc_errors::DiagCtxt, sp: Span) { |
6a06907d | 385 | let mut msg = |
4b012472 | 386 | dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated")); |
6a06907d | 387 | msg.note( |
3dfed10e | 388 | "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \ |
a2a8927a | 389 | for more information", |
3dfed10e | 390 | ); |
b7449926 | 391 | |
3dfed10e | 392 | if name == "no_default_passes" { |
a2a8927a XL |
393 | msg.help("`#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`"); |
394 | } else if name.starts_with("passes") { | |
395 | msg.help("`#![doc(passes = \"...\")]` no longer functions; you may want to use `#![doc(document_private_items)]`"); | |
6a06907d XL |
396 | } else if name.starts_with("plugins") { |
397 | msg.warn("`#![doc(plugins = \"...\")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>"); | |
3dfed10e | 398 | } |
b7449926 | 399 | |
3dfed10e XL |
400 | msg.emit(); |
401 | } | |
402 | ||
403 | // Process all of the crate attributes, extracting plugin metadata along | |
404 | // with the passes which we are supposed to run. | |
cdc7bbd5 | 405 | for attr in krate.module.attrs.lists(sym::doc) { |
4b012472 | 406 | let dcx = ctxt.sess().dcx(); |
3dfed10e XL |
407 | |
408 | let name = attr.name_or_empty(); | |
a2a8927a XL |
409 | // `plugins = "..."`, `no_default_passes`, and `passes = "..."` have no effect |
410 | if attr.is_word() && name == sym::no_default_passes { | |
4b012472 | 411 | report_deprecated_attr("no_default_passes", dcx, attr.span()); |
a2a8927a | 412 | } else if attr.value_str().is_some() { |
6a06907d | 413 | match name { |
3dfed10e | 414 | sym::passes => { |
4b012472 | 415 | report_deprecated_attr("passes = \"...\"", dcx, attr.span()); |
3dfed10e XL |
416 | } |
417 | sym::plugins => { | |
4b012472 | 418 | report_deprecated_attr("plugins = \"...\"", dcx, attr.span()); |
3dfed10e | 419 | } |
a2a8927a | 420 | _ => (), |
3dfed10e XL |
421 | } |
422 | } | |
b7449926 | 423 | |
3dfed10e XL |
424 | if attr.is_word() && name == sym::document_private_items { |
425 | ctxt.render_options.document_private = true; | |
426 | } | |
427 | } | |
b7449926 | 428 | |
3dfed10e XL |
429 | info!("Executing passes"); |
430 | ||
a2a8927a | 431 | for p in passes::defaults(show_coverage) { |
3dfed10e XL |
432 | let run = match p.condition { |
433 | Always => true, | |
434 | WhenDocumentPrivate => ctxt.render_options.document_private, | |
435 | WhenNotDocumentPrivate => !ctxt.render_options.document_private, | |
436 | WhenNotDocumentHidden => !ctxt.render_options.document_hidden, | |
437 | }; | |
438 | if run { | |
439 | debug!("running pass {}", p.pass.name); | |
3c0e092e | 440 | krate = tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt)); |
3dfed10e XL |
441 | } |
442 | } | |
443 | ||
04454e1e FG |
444 | tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); |
445 | ||
c620b35d FG |
446 | if let Some(guar) = tcx.dcx().has_errors() { |
447 | return Err(guar); | |
3c0e092e | 448 | } |
3dfed10e | 449 | |
3c0e092e | 450 | krate = tcx.sess.time("create_format_cache", || Cache::populate(&mut ctxt, krate)); |
6a06907d | 451 | |
c620b35d | 452 | Ok((krate, ctxt.render_options, ctxt.cache)) |
3dfed10e XL |
453 | } |
454 | ||
29967ef6 | 455 | /// Due to <https://github.com/rust-lang/rust/pull/73566>, |
3dfed10e XL |
456 | /// the name resolution pass may find errors that are never emitted. |
457 | /// If typeck is called after this happens, then we'll get an ICE: | |
458 | /// 'Res::Error found but not reported'. To avoid this, emit the errors now. | |
459 | struct EmitIgnoredResolutionErrors<'tcx> { | |
460 | tcx: TyCtxt<'tcx>, | |
461 | } | |
462 | ||
463 | impl<'tcx> EmitIgnoredResolutionErrors<'tcx> { | |
464 | fn new(tcx: TyCtxt<'tcx>) -> Self { | |
465 | Self { tcx } | |
466 | } | |
467 | } | |
468 | ||
469 | impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { | |
5099ac24 | 470 | type NestedFilter = nested_filter::OnlyBodies; |
3dfed10e | 471 | |
5099ac24 | 472 | fn nested_visit_map(&mut self) -> Self::Map { |
3dfed10e XL |
473 | // We need to recurse into nested closures, |
474 | // since those will fallback to the parent for type checking. | |
5099ac24 | 475 | self.tcx.hir() |
3dfed10e XL |
476 | } |
477 | ||
487cf647 | 478 | fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { |
add651ee | 479 | debug!("visiting path {path:?}"); |
3dfed10e XL |
480 | if path.res == Res::Err { |
481 | // We have less context here than in rustc_resolve, | |
482 | // so we can only emit the name and span. | |
483 | // However we can give a hint that rustc_resolve will have more info. | |
484 | let label = format!( | |
485 | "could not resolve path `{}`", | |
486 | path.segments | |
487 | .iter() | |
5099ac24 FG |
488 | .map(|segment| segment.ident.as_str()) |
489 | .intersperse("::") | |
490 | .collect::<String>() | |
3dfed10e | 491 | ); |
c0240ec0 FG |
492 | rustc_errors::struct_span_code_err!( |
493 | self.tcx.dcx(), | |
3dfed10e XL |
494 | path.span, |
495 | E0433, | |
add651ee | 496 | "failed to resolve: {label}", |
c0240ec0 FG |
497 | ) |
498 | .with_span_label(path.span, label) | |
499 | .with_note("this error was originally ignored because you are running `rustdoc`") | |
500 | .with_note("try running again with `rustc` or `cargo check` and you may get a more detailed error") | |
501 | .emit(); | |
3dfed10e XL |
502 | } |
503 | // We could have an outer resolution that succeeded, | |
504 | // but with generic parameters that failed. | |
505 | // Recurse into the segments so we catch those too. | |
506 | intravisit::walk_path(self, path); | |
507 | } | |
1a4d82fc | 508 | } |
e1599b0c XL |
509 | |
510 | /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter | |
511 | /// for `impl Trait` in argument position. | |
e8be2606 | 512 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] |
923072b8 | 513 | pub(crate) enum ImplTraitParam { |
e1599b0c XL |
514 | DefId(DefId), |
515 | ParamIndex(u32), | |
516 | } | |
517 | ||
518 | impl From<DefId> for ImplTraitParam { | |
519 | fn from(did: DefId) -> Self { | |
520 | ImplTraitParam::DefId(did) | |
521 | } | |
522 | } | |
523 | ||
524 | impl From<u32> for ImplTraitParam { | |
525 | fn from(idx: u32) -> Self { | |
526 | ImplTraitParam::ParamIndex(idx) | |
527 | } | |
528 | } |