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