rustc_builtin_macros/
standard_library_imports.rs

1use rustc_ast::{self as ast, attr};
2use rustc_expand::base::{ExtCtxt, ResolverExpand};
3use rustc_expand::expand::ExpansionConfig;
4use rustc_feature::Features;
5use rustc_session::Session;
6use rustc_span::edition::Edition::*;
7use rustc_span::hygiene::AstPass;
8use rustc_span::{DUMMY_SP, Ident, Symbol, kw, sym};
9use thin_vec::thin_vec;
10
11pub fn inject(
12    krate: &mut ast::Crate,
13    pre_configured_attrs: &[ast::Attribute],
14    resolver: &mut dyn ResolverExpand,
15    sess: &Session,
16    features: &Features,
17) -> usize {
18    let orig_num_items = krate.items.len();
19    let edition = sess.psess.edition;
20
21    // the first name in this list is the crate name of the crate with the prelude
22    let name: Symbol = if attr::contains_name(pre_configured_attrs, sym::no_core) {
23        return 0;
24    } else if attr::contains_name(pre_configured_attrs, sym::no_std) {
25        sym::core
26    } else {
27        sym::std
28    };
29
30    let expn_id = resolver.expansion_for_ast_pass(
31        DUMMY_SP,
32        AstPass::StdImports,
33        &[sym::prelude_import],
34        None,
35    );
36    let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
37    let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id());
38
39    let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features);
40    let cx = ExtCtxt::new(sess, ecfg, resolver, None);
41
42    let ident_span = if edition >= Edition2018 { span } else { call_site };
43
44    let item = cx.item(
45        span,
46        Ident::new(name, ident_span),
47        thin_vec![cx.attr_word(sym::macro_use, span)],
48        ast::ItemKind::ExternCrate(None),
49    );
50
51    krate.items.insert(0, item);
52
53    let root = (edition == Edition2015).then_some(kw::PathRoot);
54
55    let import_path = root
56        .iter()
57        .chain(&[name, sym::prelude])
58        .chain(&[match edition {
59            Edition2015 => sym::rust_2015,
60            Edition2018 => sym::rust_2018,
61            Edition2021 => sym::rust_2021,
62            Edition2024 => sym::rust_2024,
63            EditionFuture => sym::rust_future,
64        }])
65        .map(|&symbol| Ident::new(symbol, span))
66        .collect();
67
68    // Inject the relevant crate's prelude.
69    let use_item = cx.item(
70        span,
71        Ident::empty(),
72        thin_vec![cx.attr_word(sym::prelude_import, span)],
73        ast::ItemKind::Use(ast::UseTree {
74            prefix: cx.path(span, import_path),
75            kind: ast::UseTreeKind::Glob,
76            span,
77        }),
78    );
79
80    krate.items.insert(0, use_item);
81    krate.items.len() - orig_num_items
82}