Auto merge of #138630 - matthiaskrgr:rollup-kk1gogr, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #138384 (Move `hir::Item::ident` into `hir::ItemKind`.) - #138508 (Clarify "owned data" in E0515.md) - #138531 (Store test diffs in job summaries and improve analysis formatting) - #138533 (Only use `DIST_TRY_BUILD` for try jobs that were not selected explicitly) - #138556 (Fix ICE: attempted to remap an already remapped filename) - #138608 (rustc_target: Add target feature constraints for LoongArch) - #138619 (Flatten `if`s in `rustc_codegen_ssa`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
259fdb5212
105 changed files with 1345 additions and 1150 deletions
19
.github/workflows/ci.yml
vendored
19
.github/workflows/ci.yml
vendored
|
@ -239,16 +239,31 @@ jobs:
|
|||
if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1'
|
||||
|
||||
- name: postprocess metrics into the summary
|
||||
# This step is not critical, and if some I/O problem happens, we don't want
|
||||
# to cancel the build.
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if [ -f build/metrics.json ]; then
|
||||
./build/citool/debug/citool postprocess-metrics build/metrics.json ${GITHUB_STEP_SUMMARY}
|
||||
METRICS=build/metrics.json
|
||||
elif [ -f obj/build/metrics.json ]; then
|
||||
./build/citool/debug/citool postprocess-metrics obj/build/metrics.json ${GITHUB_STEP_SUMMARY}
|
||||
METRICS=obj/build/metrics.json
|
||||
else
|
||||
echo "No metrics.json found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get closest bors merge commit
|
||||
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
|
||||
|
||||
./build/citool/debug/citool postprocess-metrics \
|
||||
--job-name ${CI_JOB_NAME} \
|
||||
--parent ${PARENT_COMMIT} \
|
||||
${METRICS} >> ${GITHUB_STEP_SUMMARY}
|
||||
|
||||
- name: upload job metrics to DataDog
|
||||
# This step is not critical, and if some I/O problem happens, we don't want
|
||||
# to cancel the build.
|
||||
continue-on-error: true
|
||||
if: needs.calculate_matrix.outputs.run_type != 'pr'
|
||||
env:
|
||||
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
|
||||
|
|
|
@ -164,7 +164,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
fn visit_item(&mut self, i: &'hir Item<'hir>) {
|
||||
debug_assert_eq!(i.owner_id, self.owner);
|
||||
self.with_parent(i.hir_id(), |this| {
|
||||
if let ItemKind::Struct(struct_def, _) = &i.kind {
|
||||
if let ItemKind::Struct(_, struct_def, _) = &i.kind {
|
||||
// If this is a tuple or unit-like struct, register the constructor.
|
||||
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
|
||||
this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
|
||||
|
|
|
@ -111,6 +111,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_foreign_item(&mut self, item: &ForeignItem) {
|
||||
debug_assert_ne!(item.ident.name, kw::Empty);
|
||||
self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
|
||||
}
|
||||
}
|
||||
|
@ -154,14 +155,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
|
||||
let mut ident = i.ident;
|
||||
let vis_span = self.lower_span(i.vis.span);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
|
||||
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
|
||||
let kind = self.lower_item_kind(i.span, i.id, hir_id, i.ident, attrs, vis_span, &i.kind);
|
||||
let item = hir::Item {
|
||||
owner_id: hir_id.expect_owner(),
|
||||
ident: self.lower_ident(ident),
|
||||
kind,
|
||||
vis_span,
|
||||
span: self.lower_span(i.span),
|
||||
|
@ -174,25 +173,34 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span: Span,
|
||||
id: NodeId,
|
||||
hir_id: hir::HirId,
|
||||
ident: &mut Ident,
|
||||
ident: Ident,
|
||||
attrs: &'hir [hir::Attribute],
|
||||
vis_span: Span,
|
||||
i: &ItemKind,
|
||||
) -> hir::ItemKind<'hir> {
|
||||
match i {
|
||||
ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(*orig_name),
|
||||
ItemKind::ExternCrate(orig_name) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
hir::ItemKind::ExternCrate(*orig_name, ident)
|
||||
}
|
||||
ItemKind::Use(use_tree) => {
|
||||
debug_assert_eq!(ident.name, kw::Empty);
|
||||
// Start with an empty prefix.
|
||||
let prefix = Path { segments: ThinVec::new(), span: use_tree.span, tokens: None };
|
||||
|
||||
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
|
||||
self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs)
|
||||
}
|
||||
ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (ty, body_id) =
|
||||
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
|
||||
hir::ItemKind::Static(ty, *m, body_id)
|
||||
hir::ItemKind::Static(ident, ty, *m, body_id)
|
||||
}
|
||||
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (generics, (ty, body_id)) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
|
@ -201,7 +209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy)
|
||||
},
|
||||
);
|
||||
hir::ItemKind::Const(ty, generics, body_id)
|
||||
hir::ItemKind::Const(ident, ty, generics, body_id)
|
||||
}
|
||||
ItemKind::Fn(box Fn {
|
||||
sig: FnSig { decl, header, span: fn_sig_span },
|
||||
|
@ -211,6 +219,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
define_opaque,
|
||||
..
|
||||
}) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
self.with_new_scopes(*fn_sig_span, |this| {
|
||||
// Note: we don't need to change the return type from `T` to
|
||||
// `impl Future<Output = T>` here because lower_body
|
||||
|
@ -238,28 +247,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
span: this.lower_span(*fn_sig_span),
|
||||
};
|
||||
this.lower_define_opaque(hir_id, &define_opaque);
|
||||
hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
|
||||
let ident = this.lower_ident(ident);
|
||||
hir::ItemKind::Fn {
|
||||
ident,
|
||||
sig,
|
||||
generics,
|
||||
body: body_id,
|
||||
has_body: body.is_some(),
|
||||
}
|
||||
})
|
||||
}
|
||||
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _, spans, _) => {
|
||||
hir::ItemKind::Mod(self.lower_mod(items, spans))
|
||||
ItemKind::Mod(_, mod_kind) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
match mod_kind {
|
||||
ModKind::Loaded(items, _, spans, _) => {
|
||||
hir::ItemKind::Mod(ident, self.lower_mod(items, spans))
|
||||
}
|
||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
||||
}
|
||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
||||
},
|
||||
ItemKind::ForeignMod(fm) => hir::ItemKind::ForeignMod {
|
||||
abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)),
|
||||
items: self
|
||||
.arena
|
||||
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
|
||||
},
|
||||
}
|
||||
ItemKind::ForeignMod(fm) => {
|
||||
debug_assert_eq!(ident.name, kw::Empty);
|
||||
hir::ItemKind::ForeignMod {
|
||||
abi: fm.abi.map_or(ExternAbi::FALLBACK, |abi| self.lower_abi(abi)),
|
||||
items: self
|
||||
.arena
|
||||
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
|
||||
}
|
||||
}
|
||||
ItemKind::GlobalAsm(asm) => {
|
||||
debug_assert_eq!(ident.name, kw::Empty);
|
||||
let asm = self.lower_inline_asm(span, asm);
|
||||
let fake_body =
|
||||
self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm))));
|
||||
hir::ItemKind::GlobalAsm { asm, fake_body }
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
// We lower
|
||||
//
|
||||
// type Foo = impl Trait
|
||||
|
@ -268,6 +293,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
//
|
||||
// type Foo = Foo1
|
||||
// opaque type Foo1: Trait
|
||||
let ident = self.lower_ident(ident);
|
||||
let mut generics = generics.clone();
|
||||
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
|
||||
let (generics, ty) = self.lower_generics(
|
||||
|
@ -293,9 +319,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
),
|
||||
},
|
||||
);
|
||||
hir::ItemKind::TyAlias(ty, generics)
|
||||
hir::ItemKind::TyAlias(ident, ty, generics)
|
||||
}
|
||||
ItemKind::Enum(enum_definition, generics) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (generics, variants) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
|
@ -306,25 +334,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
},
|
||||
);
|
||||
hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
|
||||
hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics)
|
||||
}
|
||||
ItemKind::Struct(struct_def, generics) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (generics, struct_def) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, struct_def),
|
||||
);
|
||||
hir::ItemKind::Struct(struct_def, generics)
|
||||
hir::ItemKind::Struct(ident, struct_def, generics)
|
||||
}
|
||||
ItemKind::Union(vdata, generics) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (generics, vdata) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, vdata),
|
||||
);
|
||||
hir::ItemKind::Union(vdata, generics)
|
||||
hir::ItemKind::Union(ident, vdata, generics)
|
||||
}
|
||||
ItemKind::Impl(box Impl {
|
||||
safety,
|
||||
|
@ -336,6 +368,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self_ty: ty,
|
||||
items: impl_items,
|
||||
}) => {
|
||||
debug_assert_eq!(ident.name, kw::Empty);
|
||||
// Lower the "impl header" first. This ordering is important
|
||||
// for in-band lifetimes! Consider `'a` here:
|
||||
//
|
||||
|
@ -401,6 +434,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}))
|
||||
}
|
||||
ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (generics, (safety, items, bounds)) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
|
@ -417,9 +452,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(safety, items, bounds)
|
||||
},
|
||||
);
|
||||
hir::ItemKind::Trait(*is_auto, safety, generics, bounds, items)
|
||||
hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items)
|
||||
}
|
||||
ItemKind::TraitAlias(generics, bounds) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let (generics, bounds) = self.lower_generics(
|
||||
generics,
|
||||
id,
|
||||
|
@ -431,9 +468,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
},
|
||||
);
|
||||
hir::ItemKind::TraitAlias(generics, bounds)
|
||||
hir::ItemKind::TraitAlias(ident, generics, bounds)
|
||||
}
|
||||
ItemKind::MacroDef(MacroDef { body, macro_rules }) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let body = P(self.lower_delim_args(body));
|
||||
let def_id = self.local_def_id(id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
|
@ -444,11 +483,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
};
|
||||
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
|
||||
hir::ItemKind::Macro(macro_def, macro_kind)
|
||||
hir::ItemKind::Macro(ident, macro_def, macro_kind)
|
||||
}
|
||||
ItemKind::Delegation(box delegation) => {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let ident = self.lower_ident(ident);
|
||||
let delegation_results = self.lower_delegation(delegation, id);
|
||||
hir::ItemKind::Fn {
|
||||
ident,
|
||||
sig: delegation_results.sig,
|
||||
generics: delegation_results.generics,
|
||||
body: delegation_results.body_id,
|
||||
|
@ -479,7 +521,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
prefix: &Path,
|
||||
id: NodeId,
|
||||
vis_span: Span,
|
||||
ident: &mut Ident,
|
||||
attrs: &'hir [hir::Attribute],
|
||||
) -> hir::ItemKind<'hir> {
|
||||
let path = &tree.prefix;
|
||||
|
@ -487,7 +528,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
match tree.kind {
|
||||
UseTreeKind::Simple(rename) => {
|
||||
*ident = tree.ident();
|
||||
let mut ident = tree.ident();
|
||||
|
||||
// First, apply the prefix to the path.
|
||||
let mut path = Path { segments, span: path.span, tokens: None };
|
||||
|
@ -498,13 +539,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
{
|
||||
let _ = path.segments.pop();
|
||||
if rename.is_none() {
|
||||
*ident = path.segments.last().unwrap().ident;
|
||||
ident = path.segments.last().unwrap().ident;
|
||||
}
|
||||
}
|
||||
|
||||
let res = self.lower_import_res(id, path.span);
|
||||
let path = self.lower_use_path(res, &path, ParamMode::Explicit);
|
||||
hir::ItemKind::Use(path, hir::UseKind::Single)
|
||||
let ident = self.lower_ident(ident);
|
||||
hir::ItemKind::Use(path, hir::UseKind::Single(ident))
|
||||
}
|
||||
UseTreeKind::Glob => {
|
||||
let res = self.expect_full_res(id);
|
||||
|
@ -551,20 +593,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// own its own names, we have to adjust the owner before
|
||||
// lowering the rest of the import.
|
||||
self.with_hir_id_owner(id, |this| {
|
||||
let mut ident = *ident;
|
||||
|
||||
// `prefix` is lowered multiple times, but in different HIR owners.
|
||||
// So each segment gets renewed `HirId` with the same
|
||||
// `ItemLocalId` and the new owner. (See `lower_node_id`)
|
||||
let kind =
|
||||
this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
|
||||
let kind = this.lower_use_tree(use_tree, &prefix, id, vis_span, attrs);
|
||||
if !attrs.is_empty() {
|
||||
this.attrs.insert(hir::ItemLocalId::ZERO, attrs);
|
||||
}
|
||||
|
||||
let item = hir::Item {
|
||||
owner_id: hir::OwnerId { def_id: new_hir_id },
|
||||
ident: this.lower_ident(ident),
|
||||
kind,
|
||||
vis_span,
|
||||
span: this.lower_span(use_tree.span),
|
||||
|
@ -604,7 +642,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ItemKind::Impl(impl_) => {
|
||||
self.is_in_trait_impl = impl_.of_trait.is_some();
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, _, _, _) => {}
|
||||
hir::ItemKind::Trait(..) => {}
|
||||
kind => {
|
||||
span_bug!(item.span, "assoc item has unexpected kind of parent: {}", kind.descr())
|
||||
}
|
||||
|
@ -760,6 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||
debug_assert_ne!(i.ident.name, kw::Empty);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
|
||||
let trait_item_def_id = hir_id.expect_owner();
|
||||
|
@ -907,6 +946,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
|
||||
debug_assert_ne!(i.ident.name, kw::Empty);
|
||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||
let has_value = true;
|
||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||
|
|
|
@ -691,7 +691,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
true,
|
||||
td.is_local(),
|
||||
td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => {
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(_, _, _, _, _, items), ..
|
||||
}) => {
|
||||
let mut f_in_trait_opt = None;
|
||||
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
|
||||
let hi = fi.hir_id();
|
||||
|
@ -980,7 +982,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let arg = match tcx.hir_get_if_local(callee_def_id) {
|
||||
Some(
|
||||
hir::Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Fn { sig, .. }, ..
|
||||
kind: hir::ItemKind::Fn { ident, sig, .. }, ..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
ident,
|
||||
|
@ -1021,7 +1023,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// return type.
|
||||
match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(fn_call_id).def_id) {
|
||||
hir::Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Fn { sig, .. }, ..
|
||||
kind: hir::ItemKind::Fn { ident, sig, .. }, ..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
ident,
|
||||
|
|
|
@ -389,11 +389,10 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
|
|||
mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
|
||||
) -> io::Result<()> {
|
||||
let mut archive_path = archive_path.to_path_buf();
|
||||
if self.sess.target.llvm_target.contains("-apple-macosx") {
|
||||
if let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)?
|
||||
{
|
||||
archive_path = new_archive_path
|
||||
}
|
||||
if self.sess.target.llvm_target.contains("-apple-macosx")
|
||||
&& let Some(new_archive_path) = try_extract_macho_fat_archive(self.sess, &archive_path)?
|
||||
{
|
||||
archive_path = new_archive_path
|
||||
}
|
||||
|
||||
if self.src_archives.iter().any(|archive| archive.0 == archive_path) {
|
||||
|
|
|
@ -151,17 +151,17 @@ pub fn link_binary(
|
|||
sess.dcx().emit_artifact_notification(&out_filename, "link");
|
||||
}
|
||||
|
||||
if sess.prof.enabled() {
|
||||
if let Some(artifact_name) = out_filename.file_name() {
|
||||
// Record size for self-profiling
|
||||
let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
|
||||
if sess.prof.enabled()
|
||||
&& let Some(artifact_name) = out_filename.file_name()
|
||||
{
|
||||
// Record size for self-profiling
|
||||
let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
|
||||
|
||||
sess.prof.artifact_size(
|
||||
"linked_artifact",
|
||||
artifact_name.to_string_lossy(),
|
||||
file_size,
|
||||
);
|
||||
}
|
||||
sess.prof.artifact_size(
|
||||
"linked_artifact",
|
||||
artifact_name.to_string_lossy(),
|
||||
file_size,
|
||||
);
|
||||
}
|
||||
|
||||
if output.is_stdout() {
|
||||
|
@ -186,16 +186,12 @@ pub fn link_binary(
|
|||
|
||||
let maybe_remove_temps_from_module =
|
||||
|preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
|
||||
if !preserve_objects {
|
||||
if let Some(ref obj) = module.object {
|
||||
ensure_removed(sess.dcx(), obj);
|
||||
}
|
||||
if !preserve_objects && let Some(ref obj) = module.object {
|
||||
ensure_removed(sess.dcx(), obj);
|
||||
}
|
||||
|
||||
if !preserve_dwarf_objects {
|
||||
if let Some(ref dwo_obj) = module.dwarf_object {
|
||||
ensure_removed(sess.dcx(), dwo_obj);
|
||||
}
|
||||
if !preserve_dwarf_objects && let Some(ref dwo_obj) = module.dwarf_object {
|
||||
ensure_removed(sess.dcx(), dwo_obj);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2116,11 +2112,11 @@ fn add_local_crate_metadata_objects(
|
|||
// When linking a dynamic library, we put the metadata into a section of the
|
||||
// executable. This metadata is in a separate object file from the main
|
||||
// object file, so we link that in here.
|
||||
if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro {
|
||||
if let Some(obj) = codegen_results.metadata_module.as_ref().and_then(|m| m.object.as_ref())
|
||||
{
|
||||
cmd.add_object(obj);
|
||||
}
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro)
|
||||
&& let Some(m) = &codegen_results.metadata_module
|
||||
&& let Some(obj) = &m.object
|
||||
{
|
||||
cmd.add_object(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2540,10 +2536,11 @@ fn add_order_independent_options(
|
|||
|
||||
cmd.output_filename(out_filename);
|
||||
|
||||
if crate_type == CrateType::Executable && sess.target.is_like_windows {
|
||||
if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
|
||||
cmd.subsystem(s);
|
||||
}
|
||||
if crate_type == CrateType::Executable
|
||||
&& sess.target.is_like_windows
|
||||
&& let Some(s) = &codegen_results.crate_info.windows_subsystem
|
||||
{
|
||||
cmd.subsystem(s);
|
||||
}
|
||||
|
||||
// Try to strip as much out of the generated object by removing unused
|
||||
|
|
|
@ -111,24 +111,22 @@ pub(crate) fn get_linker<'a>(
|
|||
// PATH for the child.
|
||||
let mut new_path = sess.get_tools_search_paths(self_contained);
|
||||
let mut msvc_changed_path = false;
|
||||
if sess.target.is_like_msvc {
|
||||
if let Some(ref tool) = msvc_tool {
|
||||
cmd.args(tool.args());
|
||||
for (k, v) in tool.env() {
|
||||
if k == "PATH" {
|
||||
new_path.extend(env::split_paths(v));
|
||||
msvc_changed_path = true;
|
||||
} else {
|
||||
cmd.env(k, v);
|
||||
}
|
||||
if sess.target.is_like_msvc
|
||||
&& let Some(ref tool) = msvc_tool
|
||||
{
|
||||
cmd.args(tool.args());
|
||||
for (k, v) in tool.env() {
|
||||
if k == "PATH" {
|
||||
new_path.extend(env::split_paths(v));
|
||||
msvc_changed_path = true;
|
||||
} else {
|
||||
cmd.env(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !msvc_changed_path {
|
||||
if let Some(path) = env::var_os("PATH") {
|
||||
new_path.extend(env::split_paths(&path));
|
||||
}
|
||||
if !msvc_changed_path && let Some(path) = env::var_os("PATH") {
|
||||
new_path.extend(env::split_paths(&path));
|
||||
}
|
||||
cmd.env("PATH", env::join_paths(new_path).unwrap());
|
||||
|
||||
|
|
|
@ -566,16 +566,13 @@ fn produce_final_output_artifacts(
|
|||
|
||||
// Produce final compile outputs.
|
||||
let copy_gracefully = |from: &Path, to: &OutFileName| match to {
|
||||
OutFileName::Stdout => {
|
||||
if let Err(e) = copy_to_stdout(from) {
|
||||
sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
|
||||
}
|
||||
OutFileName::Stdout if let Err(e) = copy_to_stdout(from) => {
|
||||
sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
|
||||
}
|
||||
OutFileName::Real(path) => {
|
||||
if let Err(e) = fs::copy(from, path) {
|
||||
sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
|
||||
}
|
||||
OutFileName::Real(path) if let Err(e) = fs::copy(from, path) => {
|
||||
sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| {
|
||||
|
@ -685,14 +682,12 @@ fn produce_final_output_artifacts(
|
|||
needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1);
|
||||
|
||||
for module in compiled_modules.modules.iter() {
|
||||
if let Some(ref path) = module.object {
|
||||
if !keep_numbered_objects {
|
||||
if !keep_numbered_objects {
|
||||
if let Some(ref path) = module.object {
|
||||
ensure_removed(sess.dcx(), path);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref path) = module.dwarf_object {
|
||||
if !keep_numbered_objects {
|
||||
if let Some(ref path) = module.dwarf_object {
|
||||
ensure_removed(sess.dcx(), path);
|
||||
}
|
||||
}
|
||||
|
@ -704,12 +699,11 @@ fn produce_final_output_artifacts(
|
|||
}
|
||||
}
|
||||
|
||||
if !user_wants_bitcode {
|
||||
if let Some(ref allocator_module) = compiled_modules.allocator_module {
|
||||
if let Some(ref path) = allocator_module.bytecode {
|
||||
ensure_removed(sess.dcx(), path);
|
||||
}
|
||||
}
|
||||
if !user_wants_bitcode
|
||||
&& let Some(ref allocator_module) = compiled_modules.allocator_module
|
||||
&& let Some(ref path) = allocator_module.bytecode
|
||||
{
|
||||
ensure_removed(sess.dcx(), path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -555,11 +555,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
|
|||
|
||||
pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
|
||||
let def_key = tcx.def_key(def_id);
|
||||
if qualified {
|
||||
if let Some(parent) = def_key.parent {
|
||||
push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
|
||||
output.push_str("::");
|
||||
}
|
||||
if qualified && let Some(parent) = def_key.parent {
|
||||
push_item_name(tcx, DefId { krate: def_id.krate, index: parent }, true, output);
|
||||
output.push_str("::");
|
||||
}
|
||||
|
||||
push_unqualified_item_name(tcx, def_id, def_key.disambiguated_data, output);
|
||||
|
|
|
@ -163,25 +163,25 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
mergeable_succ: bool,
|
||||
) -> MergingSucc {
|
||||
let tcx = bx.tcx();
|
||||
if let Some(instance) = instance {
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
|
||||
if destination.is_some() {
|
||||
let caller_def = fx.instance.def_id();
|
||||
let e = CompilerBuiltinsCannotCall {
|
||||
span: tcx.def_span(caller_def),
|
||||
caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
|
||||
callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
|
||||
};
|
||||
tcx.dcx().emit_err(e);
|
||||
} else {
|
||||
info!(
|
||||
"compiler_builtins call to diverging function {:?} replaced with abort",
|
||||
instance.def_id()
|
||||
);
|
||||
bx.abort();
|
||||
bx.unreachable();
|
||||
return MergingSucc::False;
|
||||
}
|
||||
if let Some(instance) = instance
|
||||
&& is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance)
|
||||
{
|
||||
if destination.is_some() {
|
||||
let caller_def = fx.instance.def_id();
|
||||
let e = CompilerBuiltinsCannotCall {
|
||||
span: tcx.def_span(caller_def),
|
||||
caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
|
||||
callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
|
||||
};
|
||||
tcx.dcx().emit_err(e);
|
||||
} else {
|
||||
info!(
|
||||
"compiler_builtins call to diverging function {:?} replaced with abort",
|
||||
instance.def_id()
|
||||
);
|
||||
bx.abort();
|
||||
bx.unreachable();
|
||||
return MergingSucc::False;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -837,15 +837,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
|
||||
// ZST are passed as operands and require special handling
|
||||
// because codegen_place() panics if Local is operand.
|
||||
if let Some(index) = place.as_local() {
|
||||
if let LocalRef::Operand(op) = self.locals[index] {
|
||||
if let ty::Array(_, n) = op.layout.ty.kind() {
|
||||
let n = n
|
||||
.try_to_target_usize(bx.tcx())
|
||||
.expect("expected monomorphic const in codegen");
|
||||
return bx.cx().const_usize(n);
|
||||
}
|
||||
}
|
||||
if let Some(index) = place.as_local()
|
||||
&& let LocalRef::Operand(op) = self.locals[index]
|
||||
&& let ty::Array(_, n) = op.layout.ty.kind()
|
||||
{
|
||||
let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen");
|
||||
return bx.cx().const_usize(n);
|
||||
}
|
||||
// use common size calculation for non zero-sized types
|
||||
let cg_value = self.codegen_place(bx, place.as_ref());
|
||||
|
|
|
@ -17,10 +17,13 @@ fn get_dangling_iterator<'a>() -> Iter<'a, i32> {
|
|||
}
|
||||
```
|
||||
|
||||
Local variables, function parameters and temporaries are all dropped before the
|
||||
end of the function body. So a reference to them cannot be returned.
|
||||
Local variables, function parameters and temporaries are all dropped before
|
||||
the end of the function body. A returned reference (or struct containing a
|
||||
reference) to such a dropped value would immediately be invalid. Therefore
|
||||
it is not allowed to return such a reference.
|
||||
|
||||
Consider returning an owned value instead:
|
||||
Consider returning a value that takes ownership of local data instead of
|
||||
referencing it:
|
||||
|
||||
```
|
||||
use std::vec::IntoIter;
|
||||
|
|
|
@ -3755,7 +3755,10 @@ pub enum UseKind {
|
|||
/// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
|
||||
/// Also produced for each element of a list `use`, e.g.
|
||||
/// `use foo::{a, b}` lowers to `use foo::a; use foo::b;`.
|
||||
Single,
|
||||
///
|
||||
/// The identifier is the name defined by the import. E.g. for `use
|
||||
/// foo::bar` it is `bar`, for `use foo::bar as baz` it is `baz`.
|
||||
Single(Ident),
|
||||
|
||||
/// Glob import, e.g., `use foo::*`.
|
||||
Glob,
|
||||
|
@ -3897,8 +3900,6 @@ impl ItemId {
|
|||
|
||||
/// An item
|
||||
///
|
||||
/// The name might be a dummy name in case of anonymous items
|
||||
///
|
||||
/// For more details, see the [rust lang reference].
|
||||
/// Note that the reference does not document nightly-only features.
|
||||
/// There may be also slight differences in the names and representation of AST nodes between
|
||||
|
@ -3907,7 +3908,6 @@ impl ItemId {
|
|||
/// [rust lang reference]: https://doc.rust-lang.org/reference/items.html
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Item<'hir> {
|
||||
pub ident: Ident,
|
||||
pub owner_id: OwnerId,
|
||||
pub kind: ItemKind<'hir>,
|
||||
pub span: Span,
|
||||
|
@ -3937,46 +3937,56 @@ impl<'hir> Item<'hir> {
|
|||
}
|
||||
|
||||
expect_methods_self_kind! {
|
||||
expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
|
||||
expect_extern_crate, (Option<Symbol>, Ident),
|
||||
ItemKind::ExternCrate(s, ident), (*s, *ident);
|
||||
|
||||
expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk);
|
||||
|
||||
expect_static, (&'hir Ty<'hir>, Mutability, BodyId),
|
||||
ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body);
|
||||
expect_static, (Ident, &'hir Ty<'hir>, Mutability, BodyId),
|
||||
ItemKind::Static(ident, ty, mutbl, body), (*ident, ty, *mutbl, *body);
|
||||
|
||||
expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Const(ty, generics, body), (ty, generics, *body);
|
||||
expect_const, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Const(ident, ty, generics, body), (*ident, ty, generics, *body);
|
||||
|
||||
expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Fn { sig, generics, body, .. }, (sig, generics, *body);
|
||||
expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body);
|
||||
|
||||
expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk);
|
||||
expect_macro, (Ident, &ast::MacroDef, MacroKind),
|
||||
ItemKind::Macro(ident, def, mk), (*ident, def, *mk);
|
||||
|
||||
expect_mod, &'hir Mod<'hir>, ItemKind::Mod(m), m;
|
||||
expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m);
|
||||
|
||||
expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]),
|
||||
ItemKind::ForeignMod { abi, items }, (*abi, items);
|
||||
|
||||
expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm;
|
||||
|
||||
expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::TyAlias(ty, generics), (ty, generics);
|
||||
expect_ty_alias, (Ident, &'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::TyAlias(ident, ty, generics), (*ident, ty, generics);
|
||||
|
||||
expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, generics), (def, generics);
|
||||
expect_enum, (Ident, &EnumDef<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Enum(ident, def, generics), (*ident, def, generics);
|
||||
|
||||
expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Struct(data, generics), (data, generics);
|
||||
expect_struct, (Ident, &VariantData<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Struct(ident, data, generics), (*ident, data, generics);
|
||||
|
||||
expect_union, (&VariantData<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Union(data, generics), (data, generics);
|
||||
expect_union, (Ident, &VariantData<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Union(ident, data, generics), (*ident, data, generics);
|
||||
|
||||
expect_trait,
|
||||
(IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
|
||||
ItemKind::Trait(is_auto, safety, generics, bounds, items),
|
||||
(*is_auto, *safety, generics, bounds, items);
|
||||
(
|
||||
IsAuto,
|
||||
Safety,
|
||||
Ident,
|
||||
&'hir Generics<'hir>,
|
||||
GenericBounds<'hir>,
|
||||
&'hir [TraitItemRef]
|
||||
),
|
||||
ItemKind::Trait(is_auto, safety, ident, generics, bounds, items),
|
||||
(*is_auto, *safety, *ident, generics, bounds, items);
|
||||
|
||||
expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
ItemKind::TraitAlias(generics, bounds), (generics, bounds);
|
||||
expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
|
||||
|
||||
expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
|
||||
}
|
||||
|
@ -4094,7 +4104,7 @@ pub enum ItemKind<'hir> {
|
|||
/// An `extern crate` item, with optional *original* crate name if the crate was renamed.
|
||||
///
|
||||
/// E.g., `extern crate foo` or `extern crate foo_bar as foo`.
|
||||
ExternCrate(Option<Symbol>),
|
||||
ExternCrate(Option<Symbol>, Ident),
|
||||
|
||||
/// `use foo::bar::*;` or `use foo::bar::baz as quux;`
|
||||
///
|
||||
|
@ -4104,11 +4114,12 @@ pub enum ItemKind<'hir> {
|
|||
Use(&'hir UsePath<'hir>, UseKind),
|
||||
|
||||
/// A `static` item.
|
||||
Static(&'hir Ty<'hir>, Mutability, BodyId),
|
||||
Static(Ident, &'hir Ty<'hir>, Mutability, BodyId),
|
||||
/// A `const` item.
|
||||
Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
Const(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
/// A function declaration.
|
||||
Fn {
|
||||
ident: Ident,
|
||||
sig: FnSig<'hir>,
|
||||
generics: &'hir Generics<'hir>,
|
||||
body: BodyId,
|
||||
|
@ -4118,9 +4129,9 @@ pub enum ItemKind<'hir> {
|
|||
has_body: bool,
|
||||
},
|
||||
/// A MBE macro definition (`macro_rules!` or `macro`).
|
||||
Macro(&'hir ast::MacroDef, MacroKind),
|
||||
Macro(Ident, &'hir ast::MacroDef, MacroKind),
|
||||
/// A module.
|
||||
Mod(&'hir Mod<'hir>),
|
||||
Mod(Ident, &'hir Mod<'hir>),
|
||||
/// An external module, e.g. `extern { .. }`.
|
||||
ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] },
|
||||
/// Module-level inline assembly (from `global_asm!`).
|
||||
|
@ -4134,17 +4145,17 @@ pub enum ItemKind<'hir> {
|
|||
fake_body: BodyId,
|
||||
},
|
||||
/// A type alias, e.g., `type Foo = Bar<u8>`.
|
||||
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
|
||||
Enum(EnumDef<'hir>, &'hir Generics<'hir>),
|
||||
TyAlias(Ident, &'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||
/// An enum definition, e.g., `enum Foo<A, B> { C<A>, D<B> }`.
|
||||
Enum(Ident, EnumDef<'hir>, &'hir Generics<'hir>),
|
||||
/// A struct definition, e.g., `struct Foo<A> {x: A}`.
|
||||
Struct(VariantData<'hir>, &'hir Generics<'hir>),
|
||||
Struct(Ident, VariantData<'hir>, &'hir Generics<'hir>),
|
||||
/// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
|
||||
Union(VariantData<'hir>, &'hir Generics<'hir>),
|
||||
Union(Ident, VariantData<'hir>, &'hir Generics<'hir>),
|
||||
/// A trait definition.
|
||||
Trait(IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
|
||||
Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
|
||||
/// A trait alias.
|
||||
TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
|
||||
/// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
|
||||
Impl(&'hir Impl<'hir>),
|
||||
|
@ -4173,16 +4184,39 @@ pub struct Impl<'hir> {
|
|||
}
|
||||
|
||||
impl ItemKind<'_> {
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
match *self {
|
||||
ItemKind::ExternCrate(_, ident)
|
||||
| ItemKind::Use(_, UseKind::Single(ident))
|
||||
| ItemKind::Static(ident, ..)
|
||||
| ItemKind::Const(ident, ..)
|
||||
| ItemKind::Fn { ident, .. }
|
||||
| ItemKind::Macro(ident, ..)
|
||||
| ItemKind::Mod(ident, ..)
|
||||
| ItemKind::TyAlias(ident, ..)
|
||||
| ItemKind::Enum(ident, ..)
|
||||
| ItemKind::Struct(ident, ..)
|
||||
| ItemKind::Union(ident, ..)
|
||||
| ItemKind::Trait(_, _, ident, ..)
|
||||
| ItemKind::TraitAlias(ident, ..) => Some(ident),
|
||||
|
||||
ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
|
||||
| ItemKind::ForeignMod { .. }
|
||||
| ItemKind::GlobalAsm { .. }
|
||||
| ItemKind::Impl(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generics(&self) -> Option<&Generics<'_>> {
|
||||
Some(match self {
|
||||
ItemKind::Fn { generics, .. }
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
| ItemKind::Const(_, generics, _)
|
||||
| ItemKind::Enum(_, generics)
|
||||
| ItemKind::Struct(_, generics)
|
||||
| ItemKind::Union(_, generics)
|
||||
| ItemKind::Trait(_, _, generics, _, _)
|
||||
| ItemKind::TraitAlias(generics, _)
|
||||
| ItemKind::TyAlias(_, _, generics)
|
||||
| ItemKind::Const(_, _, generics, _)
|
||||
| ItemKind::Enum(_, _, generics)
|
||||
| ItemKind::Struct(_, _, generics)
|
||||
| ItemKind::Union(_, _, generics)
|
||||
| ItemKind::Trait(_, _, _, generics, _, _)
|
||||
| ItemKind::TraitAlias(_, generics, _)
|
||||
| ItemKind::Impl(Impl { generics, .. }) => generics,
|
||||
_ => return None,
|
||||
})
|
||||
|
@ -4374,8 +4408,8 @@ impl<'hir> OwnerNode<'hir> {
|
|||
match self {
|
||||
OwnerNode::Item(Item {
|
||||
kind:
|
||||
ItemKind::Static(_, _, body)
|
||||
| ItemKind::Const(_, _, body)
|
||||
ItemKind::Static(_, _, _, body)
|
||||
| ItemKind::Const(_, _, _, body)
|
||||
| ItemKind::Fn { body, .. },
|
||||
..
|
||||
})
|
||||
|
@ -4518,12 +4552,12 @@ impl<'hir> Node<'hir> {
|
|||
/// ```
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
match self {
|
||||
Node::Item(item) => item.kind.ident(),
|
||||
Node::TraitItem(TraitItem { ident, .. })
|
||||
| Node::ImplItem(ImplItem { ident, .. })
|
||||
| Node::ForeignItem(ForeignItem { ident, .. })
|
||||
| Node::Field(FieldDef { ident, .. })
|
||||
| Node::Variant(Variant { ident, .. })
|
||||
| Node::Item(Item { ident, .. })
|
||||
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
|
||||
Node::Lifetime(lt) => Some(lt.ident),
|
||||
Node::GenericParam(p) => Some(p.name.ident()),
|
||||
|
@ -4599,9 +4633,9 @@ impl<'hir> Node<'hir> {
|
|||
pub fn ty(self) -> Option<&'hir Ty<'hir>> {
|
||||
match self {
|
||||
Node::Item(it) => match it.kind {
|
||||
ItemKind::TyAlias(ty, _)
|
||||
| ItemKind::Static(ty, _, _)
|
||||
| ItemKind::Const(ty, _, _) => Some(ty),
|
||||
ItemKind::TyAlias(_, ty, _)
|
||||
| ItemKind::Static(_, ty, _, _)
|
||||
| ItemKind::Const(_, ty, _, _) => Some(ty),
|
||||
ItemKind::Impl(impl_item) => Some(&impl_item.self_ty),
|
||||
_ => None,
|
||||
},
|
||||
|
@ -4621,7 +4655,7 @@ impl<'hir> Node<'hir> {
|
|||
|
||||
pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> {
|
||||
match self {
|
||||
Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty),
|
||||
Node::Item(Item { kind: ItemKind::TyAlias(_, ty, _), .. }) => Some(ty),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -4632,7 +4666,9 @@ impl<'hir> Node<'hir> {
|
|||
Node::Item(Item {
|
||||
owner_id,
|
||||
kind:
|
||||
ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn { body, .. },
|
||||
ItemKind::Const(_, _, _, body)
|
||||
| ItemKind::Static(.., body)
|
||||
| ItemKind::Fn { body, .. },
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(TraitItem {
|
||||
|
@ -4693,8 +4729,8 @@ impl<'hir> Node<'hir> {
|
|||
pub fn fn_kind(self) -> Option<FnKind<'hir>> {
|
||||
match self {
|
||||
Node::Item(i) => match i.kind {
|
||||
ItemKind::Fn { sig, generics, .. } => {
|
||||
Some(FnKind::ItemFn(i.ident, generics, sig.header))
|
||||
ItemKind::Fn { ident, sig, generics, .. } => {
|
||||
Some(FnKind::ItemFn(ident, generics, sig.header))
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
|
@ -4767,7 +4803,7 @@ mod size_asserts {
|
|||
static_assert_size!(ImplItem<'_>, 88);
|
||||
static_assert_size!(ImplItemKind<'_>, 40);
|
||||
static_assert_size!(Item<'_>, 88);
|
||||
static_assert_size!(ItemKind<'_>, 56);
|
||||
static_assert_size!(ItemKind<'_>, 64);
|
||||
static_assert_size!(LetStmt<'_>, 64);
|
||||
static_assert_size!(Param<'_>, 32);
|
||||
static_assert_size!(Pat<'_>, 72);
|
||||
|
|
|
@ -533,34 +533,44 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) ->
|
|||
|
||||
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(item.hir_id()));
|
||||
try_visit!(visitor.visit_ident(item.ident));
|
||||
match item.kind {
|
||||
ItemKind::ExternCrate(orig_name) => {
|
||||
ItemKind::ExternCrate(orig_name, ident) => {
|
||||
visit_opt!(visitor, visit_name, orig_name);
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
}
|
||||
ItemKind::Use(ref path, _) => {
|
||||
ItemKind::Use(ref path, kind) => {
|
||||
try_visit!(visitor.visit_use(path, item.hir_id()));
|
||||
match kind {
|
||||
UseKind::Single(ident) => try_visit!(visitor.visit_ident(ident)),
|
||||
UseKind::Glob | UseKind::ListStem => {}
|
||||
}
|
||||
}
|
||||
ItemKind::Static(ref typ, _, body) => {
|
||||
ItemKind::Static(ident, ref typ, _, body) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_ty_unambig(typ));
|
||||
try_visit!(visitor.visit_nested_body(body));
|
||||
}
|
||||
ItemKind::Const(ref typ, ref generics, body) => {
|
||||
ItemKind::Const(ident, ref typ, ref generics, body) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_ty_unambig(typ));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_nested_body(body));
|
||||
}
|
||||
ItemKind::Fn { sig, generics, body: body_id, .. } => {
|
||||
ItemKind::Fn { ident, sig, generics, body: body_id, .. } => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_fn(
|
||||
FnKind::ItemFn(item.ident, generics, sig.header),
|
||||
FnKind::ItemFn(ident, generics, sig.header),
|
||||
sig.decl,
|
||||
body_id,
|
||||
item.span,
|
||||
item.owner_id.def_id,
|
||||
));
|
||||
}
|
||||
ItemKind::Macro(..) => {}
|
||||
ItemKind::Mod(ref module) => {
|
||||
ItemKind::Macro(ident, _def, _kind) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
}
|
||||
ItemKind::Mod(ident, ref module) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_mod(module, item.span, item.hir_id()));
|
||||
}
|
||||
ItemKind::ForeignMod { abi: _, items } => {
|
||||
|
@ -573,11 +583,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
|
|||
// typeck results set correctly.
|
||||
try_visit!(visitor.visit_nested_body(fake_body));
|
||||
}
|
||||
ItemKind::TyAlias(ref ty, ref generics) => {
|
||||
ItemKind::TyAlias(ident, ref ty, ref generics) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_ty_unambig(ty));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
}
|
||||
ItemKind::Enum(ref enum_definition, ref generics) => {
|
||||
ItemKind::Enum(ident, ref enum_definition, ref generics) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_enum_def(enum_definition));
|
||||
}
|
||||
|
@ -597,17 +609,20 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
|
|||
try_visit!(visitor.visit_ty_unambig(self_ty));
|
||||
walk_list!(visitor, visit_impl_item_ref, *items);
|
||||
}
|
||||
ItemKind::Struct(ref struct_definition, ref generics)
|
||||
| ItemKind::Union(ref struct_definition, ref generics) => {
|
||||
ItemKind::Struct(ident, ref struct_definition, ref generics)
|
||||
| ItemKind::Union(ident, ref struct_definition, ref generics) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_variant_data(struct_definition));
|
||||
}
|
||||
ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
|
||||
ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
|
||||
}
|
||||
ItemKind::TraitAlias(ref generics, bounds) => {
|
||||
ItemKind::TraitAlias(ident, ref generics, bounds) => {
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
|
|
|
@ -269,26 +269,26 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
|
|||
}
|
||||
res
|
||||
}
|
||||
hir::ItemKind::Fn { sig, .. } => {
|
||||
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
|
||||
hir::ItemKind::Fn { ident, sig, .. } => {
|
||||
check_item_fn(tcx, def_id, ident, item.span, sig.decl)
|
||||
}
|
||||
hir::ItemKind::Static(ty, ..) => {
|
||||
hir::ItemKind::Static(_, ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
|
||||
}
|
||||
hir::ItemKind::Const(ty, ..) => {
|
||||
hir::ItemKind::Const(_, ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid)
|
||||
}
|
||||
hir::ItemKind::Struct(_, hir_generics) => {
|
||||
hir::ItemKind::Struct(_, _, hir_generics) => {
|
||||
let res = check_type_defn(tcx, item, false);
|
||||
check_variances_for_type_defn(tcx, item, hir_generics);
|
||||
res
|
||||
}
|
||||
hir::ItemKind::Union(_, hir_generics) => {
|
||||
hir::ItemKind::Union(_, _, hir_generics) => {
|
||||
let res = check_type_defn(tcx, item, true);
|
||||
check_variances_for_type_defn(tcx, item, hir_generics);
|
||||
res
|
||||
}
|
||||
hir::ItemKind::Enum(_, hir_generics) => {
|
||||
hir::ItemKind::Enum(_, _, hir_generics) => {
|
||||
let res = check_type_defn(tcx, item, true);
|
||||
check_variances_for_type_defn(tcx, item, hir_generics);
|
||||
res
|
||||
|
@ -297,7 +297,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
|
|||
hir::ItemKind::TraitAlias(..) => check_trait(tcx, item),
|
||||
// `ForeignItem`s are handled separately.
|
||||
hir::ItemKind::ForeignMod { .. } => Ok(()),
|
||||
hir::ItemKind::TyAlias(hir_ty, hir_generics) if tcx.type_alias_is_lazy(item.owner_id) => {
|
||||
hir::ItemKind::TyAlias(_, hir_ty, hir_generics)
|
||||
if tcx.type_alias_is_lazy(item.owner_id) =>
|
||||
{
|
||||
let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
|
||||
|
@ -822,10 +824,10 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
|
|||
///
|
||||
/// In such cases, suggest using `Self` instead.
|
||||
fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
|
||||
let (trait_name, trait_def_id) =
|
||||
let (trait_ident, trait_def_id) =
|
||||
match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(item.hir_id()).def_id) {
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Trait(..) => (item.ident, item.owner_id),
|
||||
hir::ItemKind::Trait(_, _, ident, ..) => (ident, item.owner_id),
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
|
@ -862,7 +864,7 @@ fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitI
|
|||
trait_should_be_self,
|
||||
"associated item referring to unboxed trait object for its own trait",
|
||||
)
|
||||
.with_span_label(trait_name.span, "in this trait")
|
||||
.with_span_label(trait_ident.span, "in this trait")
|
||||
.with_multipart_suggestion(
|
||||
"you might have meant to use `Self` to refer to the implementing type",
|
||||
sugg,
|
||||
|
|
|
@ -247,13 +247,13 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
|
|||
item: &'tcx hir::Item<'tcx>,
|
||||
) {
|
||||
let (generics, suggest) = match &item.kind {
|
||||
hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::TraitAlias(generics, _)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
hir::ItemKind::Union(_, _, generics)
|
||||
| hir::ItemKind::Enum(_, _, generics)
|
||||
| hir::ItemKind::TraitAlias(_, generics, _)
|
||||
| hir::ItemKind::Trait(_, _, _, generics, ..)
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. })
|
||||
| hir::ItemKind::Struct(_, generics) => (generics, true),
|
||||
hir::ItemKind::TyAlias(_, generics) => (generics, false),
|
||||
| hir::ItemKind::Struct(_, _, generics) => (generics, true),
|
||||
hir::ItemKind::TyAlias(_, _, generics) => (generics, false),
|
||||
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
|
||||
_ => return,
|
||||
};
|
||||
|
@ -470,9 +470,9 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
.tcx
|
||||
.hir_expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id);
|
||||
match &item.kind {
|
||||
hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Struct(_, generics)
|
||||
| hir::ItemKind::Union(_, generics) => {
|
||||
hir::ItemKind::Enum(_, _, generics)
|
||||
| hir::ItemKind::Struct(_, _, generics)
|
||||
| hir::ItemKind::Union(_, _, generics) => {
|
||||
let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
|
||||
let (lt_sp, sugg) = match generics.params {
|
||||
[] => (generics.span, format!("<{lt_name}>")),
|
||||
|
@ -667,16 +667,16 @@ fn get_new_lifetime_name<'tcx>(
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
||||
let it = tcx.hir_item(item_id);
|
||||
debug!(item = %it.ident, id = %it.hir_id());
|
||||
debug!(item = ?it.kind.ident(), id = %it.hir_id());
|
||||
let def_id = item_id.owner_id.def_id;
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
|
||||
match &it.kind {
|
||||
// These don't define types.
|
||||
hir::ItemKind::ExternCrate(_)
|
||||
hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::Use(..)
|
||||
| hir::ItemKind::Macro(..)
|
||||
| hir::ItemKind::Mod(_)
|
||||
| hir::ItemKind::Mod(..)
|
||||
| hir::ItemKind::GlobalAsm { .. } => {}
|
||||
hir::ItemKind::ForeignMod { items, .. } => {
|
||||
for item in *items {
|
||||
|
@ -736,7 +736,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
tcx.at(it.span).explicit_super_predicates_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => {
|
||||
hir::ItemKind::Struct(_, struct_def, _) | hir::ItemKind::Union(_, struct_def, _) => {
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
|
@ -758,7 +758,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
tcx.ensure_ok().predicates_of(def_id);
|
||||
}
|
||||
|
||||
hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => {
|
||||
hir::ItemKind::Static(_, ty, ..) | hir::ItemKind::Const(_, ty, ..) => {
|
||||
tcx.ensure_ok().generics_of(def_id);
|
||||
tcx.ensure_ok().type_of(def_id);
|
||||
tcx.ensure_ok().predicates_of(def_id);
|
||||
|
@ -1089,7 +1089,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
|||
|
||||
let repr = tcx.repr_options_of_def(def_id);
|
||||
let (kind, variants) = match &item.kind {
|
||||
ItemKind::Enum(def, _) => {
|
||||
ItemKind::Enum(_, def, _) => {
|
||||
let mut distance_from_explicit = 0;
|
||||
let variants = def
|
||||
.variants
|
||||
|
@ -1117,7 +1117,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
|||
|
||||
(AdtKind::Enum, variants)
|
||||
}
|
||||
ItemKind::Struct(def, _) | ItemKind::Union(def, _) => {
|
||||
ItemKind::Struct(ident, def, _) | ItemKind::Union(ident, def, _) => {
|
||||
let adt_kind = match item.kind {
|
||||
ItemKind::Struct(..) => AdtKind::Struct,
|
||||
_ => AdtKind::Union,
|
||||
|
@ -1125,7 +1125,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
|||
let variants = std::iter::once(lower_variant(
|
||||
tcx,
|
||||
None,
|
||||
item.ident,
|
||||
*ident,
|
||||
ty::VariantDiscr::Relative(0),
|
||||
def,
|
||||
adt_kind,
|
||||
|
|
|
@ -134,7 +134,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
|
|||
};
|
||||
tcx.vtable_entries(trait_ref)
|
||||
}
|
||||
hir::ItemKind::TyAlias(_, _) => {
|
||||
hir::ItemKind::TyAlias(..) => {
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
if ty.has_non_region_param() {
|
||||
tcx.dcx().span_err(
|
||||
|
|
|
@ -163,7 +163,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
}
|
||||
}
|
||||
|
||||
ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => {
|
||||
ItemKind::Trait(_, _, _, _, self_bounds, ..)
|
||||
| ItemKind::TraitAlias(_, _, self_bounds) => {
|
||||
is_trait = Some(self_bounds);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -615,7 +616,7 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
|
|||
|
||||
let (generics, superbounds) = match item.kind {
|
||||
hir::ItemKind::Trait(.., generics, supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(generics, supertraits) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
|
||||
_ => span_bug!(item.span, "super_predicates invoked on non-trait"),
|
||||
};
|
||||
|
||||
|
@ -959,7 +960,7 @@ pub(super) fn const_conditions<'tcx>(
|
|||
Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
|
||||
hir::ItemKind::Fn { generics, .. } => (generics, None, false),
|
||||
hir::ItemKind::Trait(_, _, generics, supertraits, _) => {
|
||||
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => {
|
||||
(generics, Some((item.owner_id.def_id, supertraits)), false)
|
||||
}
|
||||
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
|
||||
|
|
|
@ -617,7 +617,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
hir::ItemKind::ExternCrate(_)
|
||||
hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::Use(..)
|
||||
| hir::ItemKind::Macro(..)
|
||||
| hir::ItemKind::Mod(..)
|
||||
|
@ -627,13 +627,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
// These sorts of items have no lifetime parameters at all.
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Const(_, generics, _)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Struct(_, generics)
|
||||
| hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
| hir::ItemKind::TraitAlias(generics, ..)
|
||||
hir::ItemKind::TyAlias(_, _, generics)
|
||||
| hir::ItemKind::Const(_, _, generics, _)
|
||||
| hir::ItemKind::Enum(_, _, generics)
|
||||
| hir::ItemKind::Struct(_, _, generics)
|
||||
| hir::ItemKind::Union(_, _, generics)
|
||||
| hir::ItemKind::Trait(_, _, _, generics, ..)
|
||||
| hir::ItemKind::TraitAlias(_, generics, ..)
|
||||
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
|
||||
// These kinds of items have only early-bound lifetime parameters.
|
||||
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));
|
||||
|
|
|
@ -202,35 +202,35 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
|||
},
|
||||
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::Static(ty, .., body_id) => {
|
||||
ItemKind::Static(ident, ty, .., body_id) => {
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
infer_placeholder_type(
|
||||
icx.lowerer(),
|
||||
def_id,
|
||||
body_id,
|
||||
ty.span,
|
||||
item.ident,
|
||||
ident,
|
||||
"static variable",
|
||||
)
|
||||
} else {
|
||||
icx.lower_ty(ty)
|
||||
}
|
||||
}
|
||||
ItemKind::Const(ty, _, body_id) => {
|
||||
ItemKind::Const(ident, ty, _, body_id) => {
|
||||
if ty.is_suggestable_infer_ty() {
|
||||
infer_placeholder_type(
|
||||
icx.lowerer(),
|
||||
def_id,
|
||||
body_id,
|
||||
ty.span,
|
||||
item.ident,
|
||||
ident,
|
||||
"constant",
|
||||
)
|
||||
} else {
|
||||
icx.lower_ty(ty)
|
||||
}
|
||||
}
|
||||
ItemKind::TyAlias(self_ty, _) => icx.lower_ty(self_ty),
|
||||
ItemKind::TyAlias(_, self_ty, _) => icx.lower_ty(self_ty),
|
||||
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
|
||||
spans if spans.len() > 0 => {
|
||||
let guar = tcx
|
||||
|
@ -479,5 +479,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().0).is_break()
|
||||
HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().1).is_break()
|
||||
}
|
||||
|
|
|
@ -140,14 +140,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let generics = match tcx.hir_node_by_def_id(parent_item) {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(variant, generics), ..
|
||||
kind: hir::ItemKind::Struct(_, variant, generics),
|
||||
..
|
||||
}) => {
|
||||
if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
|
||||
return false;
|
||||
}
|
||||
generics
|
||||
}
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(def, generics), .. }) => {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, def, generics), .. }) => {
|
||||
if !def
|
||||
.variants
|
||||
.iter()
|
||||
|
@ -267,7 +268,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::Node::Field(field) => {
|
||||
// Enums can't have unsized fields, fields can only have an unsized tail field.
|
||||
if let hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(variant, _), ..
|
||||
kind: hir::ItemKind::Struct(_, variant, _), ..
|
||||
}) = tcx.parent_hir_node(field.hir_id)
|
||||
&& variant
|
||||
.fields()
|
||||
|
|
|
@ -136,9 +136,9 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
ref item => bug!("Unexpected TraitItem {:?}", item),
|
||||
},
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::TyAlias(ty, _)
|
||||
| hir::ItemKind::Static(ty, _, _)
|
||||
| hir::ItemKind::Const(ty, _, _) => vec![ty],
|
||||
hir::ItemKind::TyAlias(_, ty, _)
|
||||
| hir::ItemKind::Static(_, ty, _, _)
|
||||
| hir::ItemKind::Const(_, ty, _, _) => vec![ty],
|
||||
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
|
||||
Some(t) => t
|
||||
.path
|
||||
|
|
|
@ -559,7 +559,7 @@ impl<'a> State<'a> {
|
|||
self.print_attrs_as_outer(attrs);
|
||||
self.ann.pre(self, AnnNode::Item(item));
|
||||
match item.kind {
|
||||
hir::ItemKind::ExternCrate(orig_name) => {
|
||||
hir::ItemKind::ExternCrate(orig_name, ident) => {
|
||||
self.head("extern crate");
|
||||
if let Some(orig_name) = orig_name {
|
||||
self.print_name(orig_name);
|
||||
|
@ -567,7 +567,7 @@ impl<'a> State<'a> {
|
|||
self.word("as");
|
||||
self.space();
|
||||
}
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
|
@ -577,11 +577,11 @@ impl<'a> State<'a> {
|
|||
self.print_path(path, false);
|
||||
|
||||
match kind {
|
||||
hir::UseKind::Single => {
|
||||
if path.segments.last().unwrap().ident != item.ident {
|
||||
hir::UseKind::Single(ident) => {
|
||||
if path.segments.last().unwrap().ident != ident {
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
}
|
||||
self.word(";");
|
||||
}
|
||||
|
@ -591,12 +591,12 @@ impl<'a> State<'a> {
|
|||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
}
|
||||
hir::ItemKind::Static(ty, m, expr) => {
|
||||
hir::ItemKind::Static(ident, ty, m, expr) => {
|
||||
self.head("static");
|
||||
if m.is_mut() {
|
||||
self.word_space("mut");
|
||||
}
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
self.space();
|
||||
|
@ -607,9 +607,9 @@ impl<'a> State<'a> {
|
|||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
}
|
||||
hir::ItemKind::Const(ty, generics, expr) => {
|
||||
hir::ItemKind::Const(ident, ty, generics, expr) => {
|
||||
self.head("const");
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
|
@ -622,30 +622,23 @@ impl<'a> State<'a> {
|
|||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
}
|
||||
hir::ItemKind::Fn { sig, generics, body, .. } => {
|
||||
hir::ItemKind::Fn { ident, sig, generics, body, .. } => {
|
||||
self.head("");
|
||||
self.print_fn(
|
||||
sig.decl,
|
||||
sig.header,
|
||||
Some(item.ident.name),
|
||||
generics,
|
||||
&[],
|
||||
Some(body),
|
||||
);
|
||||
self.print_fn(sig.decl, sig.header, Some(ident.name), generics, &[], Some(body));
|
||||
self.word(" ");
|
||||
self.end(); // need to close a box
|
||||
self.end(); // need to close a box
|
||||
self.ann.nested(self, Nested::Body(body));
|
||||
}
|
||||
hir::ItemKind::Macro(macro_def, _) => {
|
||||
self.print_mac_def(macro_def, &item.ident, item.span, |_| {});
|
||||
hir::ItemKind::Macro(ident, macro_def, _) => {
|
||||
self.print_mac_def(macro_def, &ident, item.span, |_| {});
|
||||
}
|
||||
hir::ItemKind::Mod(_mod) => {
|
||||
hir::ItemKind::Mod(ident, mod_) => {
|
||||
self.head("mod");
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
self.print_mod(_mod, attrs);
|
||||
self.print_mod(mod_, attrs);
|
||||
self.bclose(item.span);
|
||||
}
|
||||
hir::ItemKind::ForeignMod { abi, items } => {
|
||||
|
@ -663,9 +656,9 @@ impl<'a> State<'a> {
|
|||
self.print_inline_asm(asm);
|
||||
self.end()
|
||||
}
|
||||
hir::ItemKind::TyAlias(ty, generics) => {
|
||||
hir::ItemKind::TyAlias(ident, ty, generics) => {
|
||||
self.head("type");
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.end(); // end the inner ibox
|
||||
|
||||
|
@ -676,16 +669,16 @@ impl<'a> State<'a> {
|
|||
self.word(";");
|
||||
self.end(); // end the outer ibox
|
||||
}
|
||||
hir::ItemKind::Enum(ref enum_definition, params) => {
|
||||
self.print_enum_def(enum_definition, params, item.ident.name, item.span);
|
||||
hir::ItemKind::Enum(ident, ref enum_definition, params) => {
|
||||
self.print_enum_def(enum_definition, params, ident.name, item.span);
|
||||
}
|
||||
hir::ItemKind::Struct(ref struct_def, generics) => {
|
||||
hir::ItemKind::Struct(ident, ref struct_def, generics) => {
|
||||
self.head("struct");
|
||||
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
|
||||
self.print_struct(struct_def, generics, ident.name, item.span, true);
|
||||
}
|
||||
hir::ItemKind::Union(ref struct_def, generics) => {
|
||||
hir::ItemKind::Union(ident, ref struct_def, generics) => {
|
||||
self.head("union");
|
||||
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
|
||||
self.print_struct(struct_def, generics, ident.name, item.span, true);
|
||||
}
|
||||
hir::ItemKind::Impl(&hir::Impl {
|
||||
constness,
|
||||
|
@ -733,12 +726,12 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.bclose(item.span);
|
||||
}
|
||||
hir::ItemKind::Trait(is_auto, safety, generics, bounds, trait_items) => {
|
||||
hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => {
|
||||
self.head("");
|
||||
self.print_is_auto(is_auto);
|
||||
self.print_safety(safety);
|
||||
self.word_nbsp("trait");
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.print_bounds(":", bounds);
|
||||
self.print_where_clause(generics);
|
||||
|
@ -749,9 +742,9 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.bclose(item.span);
|
||||
}
|
||||
hir::ItemKind::TraitAlias(generics, bounds) => {
|
||||
hir::ItemKind::TraitAlias(ident, generics, bounds) => {
|
||||
self.head("trait");
|
||||
self.print_ident(item.ident);
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.nbsp();
|
||||
self.print_bounds("=", bounds);
|
||||
|
|
|
@ -713,8 +713,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for id in self.tcx.hir_free_items() {
|
||||
if let Some(node) = self.tcx.hir_get_if_local(id.owner_id.into())
|
||||
&& let hir::Node::Item(item) = node
|
||||
&& let hir::ItemKind::Fn { .. } = item.kind
|
||||
&& item.ident.name == segment.ident.name
|
||||
&& let hir::ItemKind::Fn { ident, .. } = item.kind
|
||||
&& ident.name == segment.ident.name
|
||||
{
|
||||
err.span_label(
|
||||
self.tcx.def_span(id.owner_id),
|
||||
|
|
|
@ -721,8 +721,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
},
|
||||
)) => {
|
||||
if let Some(hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
|
||||
kind:
|
||||
hir::ItemKind::Static(ident, ty, ..)
|
||||
| hir::ItemKind::Const(ident, ty, ..),
|
||||
..
|
||||
})) = self.tcx.hir_get_if_local(*def_id)
|
||||
{
|
||||
|
|
|
@ -904,7 +904,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// Assumes given function doesn't have a explicit return type.
|
||||
fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
|
||||
match self.tcx.hir_node_by_def_id(fn_id) {
|
||||
Node::Item(&hir::Item { ident, .. }) => {
|
||||
Node::Item(item) => {
|
||||
let (ident, _, _, _) = item.expect_fn();
|
||||
// This is less than ideal, it will not suggest a return type span on any
|
||||
// method called `main`, regardless of whether it is actually the entry point,
|
||||
// but it will still present it as the reason for the expected type.
|
||||
|
|
|
@ -367,20 +367,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.collect();
|
||||
|
||||
// Find an identifier with which this trait was imported (note that `_` doesn't count).
|
||||
let any_id = import_items.iter().find_map(|item| {
|
||||
if item.ident.name != kw::Underscore { Some(item.ident) } else { None }
|
||||
});
|
||||
if let Some(any_id) = any_id {
|
||||
if any_id.name == kw::Empty {
|
||||
// Glob import, so just use its name.
|
||||
return None;
|
||||
} else {
|
||||
return Some(format!("{any_id}"));
|
||||
for item in import_items.iter() {
|
||||
let (_, kind) = item.expect_use();
|
||||
match kind {
|
||||
hir::UseKind::Single(ident) => {
|
||||
if ident.name != kw::Underscore {
|
||||
return Some(format!("{}", ident.name));
|
||||
}
|
||||
}
|
||||
hir::UseKind::Glob => return None, // Glob import, so just use its name.
|
||||
hir::UseKind::ListStem => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
|
||||
// so just take the first one.
|
||||
// All that is left is `_`! We need to use the full path. It doesn't matter which one we
|
||||
// pick, so just take the first one.
|
||||
match import_items[0].kind {
|
||||
ItemKind::Use(path, _) => Some(
|
||||
path.segments
|
||||
|
|
|
@ -1204,13 +1204,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
Some(
|
||||
Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..),
|
||||
kind:
|
||||
hir::ItemKind::Trait(_, _, ident, ..)
|
||||
| hir::ItemKind::TraitAlias(ident, ..),
|
||||
..
|
||||
})
|
||||
// We may also encounter unsatisfied GAT or method bounds
|
||||
| Node::TraitItem(hir::TraitItem { ident, .. })
|
||||
| Node::ImplItem(hir::ImplItem { ident, .. }),
|
||||
| Node::ImplItem(hir::ImplItem { ident, .. })
|
||||
) => {
|
||||
skip_list.insert(p);
|
||||
let entry = spanned_predicates.entry(ident.span);
|
||||
|
@ -3960,8 +3961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(.., bounds, _),
|
||||
ident,
|
||||
kind: hir::ItemKind::Trait(_, _, ident, _, bounds, _),
|
||||
..
|
||||
}) => {
|
||||
let (sp, sep, article) = if bounds.is_empty() {
|
||||
|
|
|
@ -1250,7 +1250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match opt_def_id {
|
||||
Some(def_id) => match self.tcx.hir_get_if_local(def_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(_, _, body_id),
|
||||
kind: hir::ItemKind::Const(_, _, _, body_id),
|
||||
..
|
||||
})) => match self.tcx.hir_node(body_id.hir_id) {
|
||||
hir::Node::Expr(expr) => {
|
||||
|
|
|
@ -441,7 +441,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
|||
// so we will continue to exclude them for compatibility.
|
||||
//
|
||||
// The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
|
||||
if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(_) =
|
||||
if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) =
|
||||
it.kind
|
||||
{
|
||||
return;
|
||||
|
@ -545,21 +545,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
|
|||
return;
|
||||
}
|
||||
let (def, ty) = match item.kind {
|
||||
hir::ItemKind::Struct(_, ast_generics) => {
|
||||
hir::ItemKind::Struct(_, _, ast_generics) => {
|
||||
if !ast_generics.params.is_empty() {
|
||||
return;
|
||||
}
|
||||
let def = cx.tcx.adt_def(item.owner_id);
|
||||
(def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
|
||||
}
|
||||
hir::ItemKind::Union(_, ast_generics) => {
|
||||
hir::ItemKind::Union(_, _, ast_generics) => {
|
||||
if !ast_generics.params.is_empty() {
|
||||
return;
|
||||
}
|
||||
let def = cx.tcx.adt_def(item.owner_id);
|
||||
(def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
|
||||
}
|
||||
hir::ItemKind::Enum(_, ast_generics) => {
|
||||
hir::ItemKind::Enum(_, _, ast_generics) => {
|
||||
if !ast_generics.params.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
@ -1416,7 +1416,7 @@ impl TypeAliasBounds {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
let hir::ItemKind::TyAlias(hir_ty, generics) = item.kind else { return };
|
||||
let hir::ItemKind::TyAlias(_, hir_ty, generics) = item.kind else { return };
|
||||
|
||||
// There must not be a where clause.
|
||||
if generics.predicates.is_empty() {
|
||||
|
@ -2119,9 +2119,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||
|
||||
let def_id = item.owner_id.def_id;
|
||||
if let hir::ItemKind::Struct(_, hir_generics)
|
||||
| hir::ItemKind::Enum(_, hir_generics)
|
||||
| hir::ItemKind::Union(_, hir_generics) = item.kind
|
||||
if let hir::ItemKind::Struct(_, _, hir_generics)
|
||||
| hir::ItemKind::Enum(_, _, hir_generics)
|
||||
| hir::ItemKind::Union(_, _, hir_generics) = item.kind
|
||||
{
|
||||
let inferred_outlives = cx.tcx.inferred_outlives_of(def_id);
|
||||
if inferred_outlives.is_empty() {
|
||||
|
@ -2257,7 +2257,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||
// generics, except for tuple struct, which have the `where`
|
||||
// after the fields of the struct.
|
||||
let full_where_span =
|
||||
if let hir::ItemKind::Struct(hir::VariantData::Tuple(..), _) = item.kind {
|
||||
if let hir::ItemKind::Struct(_, hir::VariantData::Tuple(..), _) = item.kind {
|
||||
where_span
|
||||
} else {
|
||||
hir_generics.span.shrink_to_hi().to(where_span)
|
||||
|
|
|
@ -93,7 +93,11 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
|
|||
let orig_fields = match cx.tcx.hir_get_if_local(type_def_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Struct(hir::VariantData::Struct { fields, recovered: _ }, _generics),
|
||||
hir::ItemKind::Struct(
|
||||
_,
|
||||
hir::VariantData::Struct { fields, recovered: _ },
|
||||
_generics,
|
||||
),
|
||||
..
|
||||
})) => fields.iter().map(|f| (f.ident.name, f)).collect::<FxHashMap<_, _>>(),
|
||||
_ => return,
|
||||
|
|
|
@ -308,18 +308,18 @@ impl<'tcx> LateLintPass<'tcx> for TypeIr {
|
|||
[.., penultimate, segment]
|
||||
if penultimate.res.opt_def_id().is_some_and(is_mod_inherent) =>
|
||||
{
|
||||
(segment.ident.span, item.ident.span, "*")
|
||||
(segment.ident.span, item.kind.ident().unwrap().span, "*")
|
||||
}
|
||||
[.., segment]
|
||||
if path.res.iter().flat_map(Res::opt_def_id).any(is_mod_inherent)
|
||||
&& let rustc_hir::UseKind::Single = kind =>
|
||||
&& let rustc_hir::UseKind::Single(ident) = kind =>
|
||||
{
|
||||
let (lo, snippet) =
|
||||
match cx.tcx.sess.source_map().span_to_snippet(path.span).as_deref() {
|
||||
Ok("self") => (path.span, "*"),
|
||||
_ => (segment.ident.span.shrink_to_hi(), "::*"),
|
||||
};
|
||||
(lo, if segment.ident == item.ident { lo } else { item.ident.span }, snippet)
|
||||
(lo, if segment.ident == ident { lo } else { ident.span }, snippet)
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
|
|||
let def_id = item.owner_id.to_def_id();
|
||||
// NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because
|
||||
// the latter will report `where_clause_object_safety` lint.
|
||||
if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
|
||||
if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind
|
||||
&& cx.tcx.is_dyn_compatible(def_id)
|
||||
{
|
||||
let direct_super_traits_iter = cx
|
||||
|
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
|
|||
cx.emit_span_lint(
|
||||
MULTIPLE_SUPERTRAIT_UPCASTABLE,
|
||||
cx.tcx.def_span(def_id),
|
||||
crate::lints::MultipleSupertraitUpcastable { ident: item.ident },
|
||||
crate::lints::MultipleSupertraitUpcastable { ident },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,10 +181,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
&& parent_opt_item_name != Some(kw::Underscore)
|
||||
&& let Some(parent) = parent.as_local()
|
||||
&& let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent)
|
||||
&& let ItemKind::Const(ty, _, _) = item.kind
|
||||
&& let ItemKind::Const(ident, ty, _, _) = item.kind
|
||||
&& let TyKind::Tup(&[]) = ty.kind
|
||||
{
|
||||
Some(item.ident.span)
|
||||
Some(ident.span)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -238,7 +238,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
},
|
||||
)
|
||||
}
|
||||
ItemKind::Macro(_macro, MacroKind::Bang)
|
||||
ItemKind::Macro(_, _macro, MacroKind::Bang)
|
||||
if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
|
||||
{
|
||||
cx.emit_span_lint(
|
||||
|
|
|
@ -415,8 +415,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
|||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
if let hir::ItemKind::Mod(_) = it.kind {
|
||||
self.check_snake_case(cx, "module", &it.ident);
|
||||
if let hir::ItemKind::Mod(ident, _) = it.kind {
|
||||
self.check_snake_case(cx, "module", &ident);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,11 +498,13 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
|
|||
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
let attrs = cx.tcx.hir_attrs(it.hir_id());
|
||||
match it.kind {
|
||||
hir::ItemKind::Static(..) if !ast::attr::contains_name(attrs, sym::no_mangle) => {
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
|
||||
hir::ItemKind::Static(ident, ..)
|
||||
if !ast::attr::contains_name(attrs, sym::no_mangle) =>
|
||||
{
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident);
|
||||
}
|
||||
hir::ItemKind::Const(..) => {
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "constant", &it.ident);
|
||||
hir::ItemKind::Const(ident, ..) => {
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "constant", &ident);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -1664,7 +1664,7 @@ impl ImproperCTypesDefinitions {
|
|||
&& cx.tcx.sess.target.os == "aix"
|
||||
&& !adt_def.all_fields().next().is_none()
|
||||
{
|
||||
let struct_variant_data = item.expect_struct().0;
|
||||
let struct_variant_data = item.expect_struct().1;
|
||||
for (index, ..) in struct_variant_data.fields().iter().enumerate() {
|
||||
// Struct fields (after the first field) are checked for the
|
||||
// power alignment rule, as fields after the first are likely
|
||||
|
@ -1696,9 +1696,9 @@ impl ImproperCTypesDefinitions {
|
|||
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
match item.kind {
|
||||
hir::ItemKind::Static(ty, ..)
|
||||
| hir::ItemKind::Const(ty, ..)
|
||||
| hir::ItemKind::TyAlias(ty, ..) => {
|
||||
hir::ItemKind::Static(_, ty, ..)
|
||||
| hir::ItemKind::Const(_, ty, ..)
|
||||
| hir::ItemKind::TyAlias(_, ty, ..) => {
|
||||
self.check_ty_maybe_containing_foreign_fnptr(
|
||||
cx,
|
||||
ty,
|
||||
|
@ -1765,7 +1765,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
|
||||
if let hir::ItemKind::Enum(_, ref enum_definition, _) = it.kind {
|
||||
let t = cx.tcx.type_of(it.owner_id).instantiate_identity();
|
||||
let ty = cx.tcx.erase_regions(t);
|
||||
let Ok(layout) = cx.layout_of(ty) else { return };
|
||||
|
|
|
@ -1835,7 +1835,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
fn encode_info_for_macro(&mut self, def_id: LocalDefId) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let hir::ItemKind::Macro(macro_def, _) = tcx.hir_expect_item(def_id).kind else { bug!() };
|
||||
let (_, macro_def, _) = tcx.hir_expect_item(def_id).expect_macro();
|
||||
self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules);
|
||||
record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body);
|
||||
}
|
||||
|
|
|
@ -385,7 +385,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) {
|
||||
let hir_id = HirId::make_owner(module.to_local_def_id());
|
||||
match self.hir_owner_node(hir_id.owner) {
|
||||
OwnerNode::Item(&Item { span, kind: ItemKind::Mod(m), .. }) => (m, span, hir_id),
|
||||
OwnerNode::Item(&Item { span, kind: ItemKind::Mod(_, m), .. }) => (m, span, hir_id),
|
||||
OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id),
|
||||
node => panic!("not a module: {node:?}"),
|
||||
}
|
||||
|
@ -847,7 +847,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// A `Ctor` doesn't have an identifier itself, but its parent
|
||||
// struct/variant does. Compare with `hir::Map::span`.
|
||||
Node::Ctor(..) => match self.parent_hir_node(id) {
|
||||
Node::Item(item) => Some(item.ident),
|
||||
Node::Item(item) => Some(item.kind.ident().unwrap()),
|
||||
Node::Variant(variant) => Some(variant.ident),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
@ -894,18 +894,14 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
|
||||
fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) -> Span {
|
||||
if ident.name != kw::Empty {
|
||||
let mut span = until_within(item_span, ident.span);
|
||||
if let Some(g) = generics
|
||||
&& !g.span.is_dummy()
|
||||
&& let Some(g_span) = g.span.find_ancestor_inside(item_span)
|
||||
{
|
||||
span = span.to(g_span);
|
||||
}
|
||||
span
|
||||
} else {
|
||||
item_span
|
||||
let mut span = until_within(item_span, ident.span);
|
||||
if let Some(g) = generics
|
||||
&& !g.span.is_dummy()
|
||||
&& let Some(g_span) = g.span.find_ancestor_inside(item_span)
|
||||
{
|
||||
span = span.to(g_span);
|
||||
}
|
||||
span
|
||||
}
|
||||
|
||||
let span = match self.tcx.hir_node(hir_id) {
|
||||
|
@ -936,7 +932,7 @@ impl<'hir> Map<'hir> {
|
|||
}) => until_within(*outer_span, generics.where_clause_span),
|
||||
// Constants and Statics.
|
||||
Node::Item(Item {
|
||||
kind: ItemKind::Const(ty, ..) | ItemKind::Static(ty, ..),
|
||||
kind: ItemKind::Const(_, ty, ..) | ItemKind::Static(_, ty, ..),
|
||||
span: outer_span,
|
||||
..
|
||||
})
|
||||
|
@ -957,7 +953,7 @@ impl<'hir> Map<'hir> {
|
|||
}) => until_within(*outer_span, ty.span),
|
||||
// With generics and bounds.
|
||||
Node::Item(Item {
|
||||
kind: ItemKind::Trait(_, _, generics, bounds, _),
|
||||
kind: ItemKind::Trait(_, _, _, generics, bounds, _),
|
||||
span: outer_span,
|
||||
..
|
||||
})
|
||||
|
@ -977,7 +973,13 @@ impl<'hir> Map<'hir> {
|
|||
// SyntaxContext of the path.
|
||||
path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span)
|
||||
}
|
||||
_ => named_span(item.span, item.ident, item.kind.generics()),
|
||||
_ => {
|
||||
if let Some(ident) = item.kind.ident() {
|
||||
named_span(item.span, ident, item.kind.generics())
|
||||
} else {
|
||||
item.span
|
||||
}
|
||||
}
|
||||
},
|
||||
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
|
||||
Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
|
||||
|
@ -1327,7 +1329,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
|||
self.items.push(item.item_id());
|
||||
|
||||
// Items that are modules are handled here instead of in visit_mod.
|
||||
if let ItemKind::Mod(module) = &item.kind {
|
||||
if let ItemKind::Mod(_, module) = &item.kind {
|
||||
self.submodules.push(item.owner_id);
|
||||
// A module collector does not recurse inside nested modules.
|
||||
if self.crate_collector {
|
||||
|
|
|
@ -3406,20 +3406,18 @@ define_print_and_forward_display! {
|
|||
}
|
||||
|
||||
fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
|
||||
// Iterate all local crate items no matter where they are defined.
|
||||
// Iterate all (non-anonymous) local crate items no matter where they are defined.
|
||||
for id in tcx.hir_free_items() {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let item = tcx.hir_item(id);
|
||||
if item.ident.name == kw::Empty {
|
||||
continue;
|
||||
}
|
||||
let Some(ident) = item.kind.ident() else { continue };
|
||||
|
||||
let def_id = item.owner_id.to_def_id();
|
||||
let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
|
||||
collect_fn(&item.ident, ns, def_id);
|
||||
collect_fn(&ident, ns, def_id);
|
||||
}
|
||||
|
||||
// Now take care of extern crate items.
|
||||
|
|
|
@ -563,7 +563,7 @@ fn construct_const<'a, 'tcx>(
|
|||
// Figure out what primary body this item has.
|
||||
let (span, const_ty_span) = match tcx.hir_node(hir_id) {
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _, _),
|
||||
kind: hir::ItemKind::Static(_, ty, _, _) | hir::ItemKind::Const(_, ty, _, _),
|
||||
span,
|
||||
..
|
||||
})
|
||||
|
|
|
@ -1044,7 +1044,6 @@ fn find_fallback_pattern_typo<'tcx>(
|
|||
if let DefKind::Use = cx.tcx.def_kind(item.owner_id) {
|
||||
// Look for consts being re-exported.
|
||||
let item = cx.tcx.hir_expect_item(item.owner_id.def_id);
|
||||
let use_name = item.ident.name;
|
||||
let hir::ItemKind::Use(path, _) = item.kind else {
|
||||
continue;
|
||||
};
|
||||
|
@ -1064,8 +1063,9 @@ fn find_fallback_pattern_typo<'tcx>(
|
|||
{
|
||||
// The const is accessible only through the re-export, point at
|
||||
// the `use`.
|
||||
imported.push(use_name);
|
||||
imported_spans.push(item.ident.span);
|
||||
let ident = item.kind.ident().unwrap();
|
||||
imported.push(ident.name);
|
||||
imported_spans.push(ident.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -743,7 +743,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
match target {
|
||||
Target::Struct => {
|
||||
if let Some(ItemLike::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(hir::VariantData::Struct { fields, .. }, _),
|
||||
kind: hir::ItemKind::Struct(_, hir::VariantData::Struct { fields, .. }, _),
|
||||
..
|
||||
})) = item
|
||||
&& !fields.is_empty()
|
||||
|
@ -1019,7 +1019,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
_ => None,
|
||||
};
|
||||
match item_kind {
|
||||
Some(ItemKind::Mod(module)) => {
|
||||
Some(ItemKind::Mod(_, module)) => {
|
||||
if !module.item_ids.is_empty() {
|
||||
self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
|
||||
return;
|
||||
|
@ -1072,9 +1072,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
return;
|
||||
};
|
||||
match item.kind {
|
||||
ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics)
|
||||
ItemKind::Enum(_, _, generics) | ItemKind::Struct(_, _, generics)
|
||||
if generics.params.len() != 0 => {}
|
||||
ItemKind::Trait(_, _, generics, _, items)
|
||||
ItemKind::Trait(_, _, _, generics, _, items)
|
||||
if generics.params.len() != 0
|
||||
|| items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
|
||||
_ => {
|
||||
|
@ -2293,7 +2293,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
} else {
|
||||
// special case when `#[macro_export]` is applied to a macro 2.0
|
||||
let (macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
|
||||
let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
|
||||
let is_decl_macro = !macro_definition.macro_rules;
|
||||
|
||||
if is_decl_macro {
|
||||
|
@ -2624,7 +2624,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
|||
// Historically we've run more checks on non-exported than exported macros,
|
||||
// so this lets us continue to run them while maintaining backwards compatibility.
|
||||
// In the long run, the checks should be harmonized.
|
||||
if let ItemKind::Macro(macro_def, _) = item.kind {
|
||||
if let ItemKind::Macro(_, macro_def, _) = item.kind {
|
||||
let def_id = item.owner_id.to_def_id();
|
||||
if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
|
||||
check_non_exported_macro_for_invalid_attrs(self.tcx, item);
|
||||
|
@ -2736,7 +2736,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
fn is_c_like_enum(item: &Item<'_>) -> bool {
|
||||
if let ItemKind::Enum(ref def, _) = item.kind {
|
||||
if let ItemKind::Enum(_, ref def, _) = item.kind {
|
||||
for variant in def.variants {
|
||||
match variant.data {
|
||||
hir::VariantData::Unit(..) => { /* continue */ }
|
||||
|
@ -2784,7 +2784,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
|||
.map(|id| tcx.hir_item(id))
|
||||
.find(|item| !item.span.is_dummy()) // Skip prelude `use`s
|
||||
.map(|item| errors::ItemFollowingInnerAttr {
|
||||
span: item.ident.span,
|
||||
span: if let Some(ident) = item.kind.ident() { ident.span } else { item.span },
|
||||
kind: item.kind.descr(),
|
||||
});
|
||||
let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {
|
||||
|
|
|
@ -751,7 +751,7 @@ fn check_item<'tcx>(
|
|||
match tcx.def_kind(id.owner_id) {
|
||||
DefKind::Enum => {
|
||||
let item = tcx.hir_item(id);
|
||||
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
|
||||
if let hir::ItemKind::Enum(_, ref enum_def, _) = item.kind {
|
||||
if let Some(comes_from_allow) = allow_dead_code {
|
||||
worklist.extend(
|
||||
enum_def.variants.iter().map(|variant| (variant.def_id, comes_from_allow)),
|
||||
|
@ -806,7 +806,7 @@ fn check_item<'tcx>(
|
|||
}
|
||||
DefKind::Struct => {
|
||||
let item = tcx.hir_item(id);
|
||||
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
|
||||
if let hir::ItemKind::Struct(_, ref variant_data, _) = item.kind
|
||||
&& let Some(ctor_def_id) = variant_data.ctor_def_id()
|
||||
{
|
||||
struct_constructors.insert(ctor_def_id, item.owner_id.def_id);
|
||||
|
@ -987,7 +987,7 @@ impl<'tcx> DeadVisitor<'tcx> {
|
|||
&& let Some(enum_did) = tcx.opt_parent(may_variant.to_def_id())
|
||||
&& let Some(enum_local_id) = enum_did.as_local()
|
||||
&& let Node::Item(item) = tcx.hir_node_by_def_id(enum_local_id)
|
||||
&& let ItemKind::Enum(_, _) = item.kind
|
||||
&& let ItemKind::Enum(..) = item.kind
|
||||
{
|
||||
enum_local_id
|
||||
} else {
|
||||
|
@ -1062,7 +1062,7 @@ impl<'tcx> DeadVisitor<'tcx> {
|
|||
let tuple_fields = if let Some(parent_id) = parent_item
|
||||
&& let node = tcx.hir_node_by_def_id(parent_id)
|
||||
&& let hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(hir::VariantData::Tuple(fields, _, _), _),
|
||||
kind: hir::ItemKind::Struct(_, hir::VariantData::Tuple(fields, _, _), _),
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
|
|
|
@ -204,7 +204,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
hir::ItemKind::Const(_, _, init) => {
|
||||
hir::ItemKind::Const(_, _, _, init) => {
|
||||
// Only things actually ending up in the final constant value are reachable
|
||||
// for codegen. Everything else is only needed during const-eval, so even if
|
||||
// const-eval happens in a downstream crate, all they need is
|
||||
|
@ -232,7 +232,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
// These are normal, nothing reachable about these
|
||||
// inherently and their children are already in the
|
||||
// worklist, as determined by the privacy pass
|
||||
hir::ItemKind::ExternCrate(_)
|
||||
hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::Use(..)
|
||||
| hir::ItemKind::TyAlias(..)
|
||||
| hir::ItemKind::Macro(..)
|
||||
|
|
|
@ -430,7 +430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
|
|||
kind = AnnotationKind::DeprecationProhibited;
|
||||
const_stab_inherit = InheritConstStability::Yes;
|
||||
}
|
||||
hir::ItemKind::Struct(ref sd, _) => {
|
||||
hir::ItemKind::Struct(_, ref sd, _) => {
|
||||
if let Some(ctor_def_id) = sd.ctor_def_id() {
|
||||
self.annotate(
|
||||
ctor_def_id,
|
||||
|
@ -773,10 +773,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
match item.kind {
|
||||
hir::ItemKind::ExternCrate(_) => {
|
||||
hir::ItemKind::ExternCrate(_, ident) => {
|
||||
// compiler-generated `extern crate` items have a dummy span.
|
||||
// `std` is still checked for the `restricted-std` feature.
|
||||
if item.span.is_dummy() && item.ident.name != sym::std {
|
||||
if item.span.is_dummy() && ident.name != sym::std {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -574,7 +574,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
|||
// privacy and mark them reachable.
|
||||
DefKind::Macro(_) => {
|
||||
let item = self.tcx.hir_expect_item(def_id);
|
||||
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
|
||||
if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind {
|
||||
if vis.is_accessible_from(module, self.tcx) {
|
||||
self.update(def_id, macro_ev, Level::Reachable);
|
||||
}
|
||||
|
@ -598,8 +598,8 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
|||
DefKind::Struct | DefKind::Union => {
|
||||
// While structs and unions have type privacy, their fields do not.
|
||||
let item = self.tcx.hir_expect_item(def_id);
|
||||
if let hir::ItemKind::Struct(ref struct_def, _)
|
||||
| hir::ItemKind::Union(ref struct_def, _) = item.kind
|
||||
if let hir::ItemKind::Struct(_, ref struct_def, _)
|
||||
| hir::ItemKind::Union(_, ref struct_def, _) = item.kind
|
||||
{
|
||||
for field in struct_def.fields() {
|
||||
let field_vis = self.tcx.local_visibility(field.def_id);
|
||||
|
@ -653,7 +653,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||
| hir::ItemKind::GlobalAsm { .. } => {}
|
||||
// The interface is empty, and all nested items are processed by `visit_item`.
|
||||
hir::ItemKind::Mod(..) => {}
|
||||
hir::ItemKind::Macro(macro_def, _) => {
|
||||
hir::ItemKind::Macro(_, macro_def, _) => {
|
||||
if let Some(item_ev) = item_ev {
|
||||
self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
|
||||
}
|
||||
|
@ -724,7 +724,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Enum(ref def, _) => {
|
||||
hir::ItemKind::Enum(_, ref def, _) => {
|
||||
if let Some(item_ev) = item_ev {
|
||||
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
|
||||
}
|
||||
|
@ -762,7 +762,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
|
||||
hir::ItemKind::Struct(_, ref struct_def, _)
|
||||
| hir::ItemKind::Union(_, ref struct_def, _) => {
|
||||
if let Some(item_ev) = item_ev {
|
||||
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
|
||||
for field in struct_def.fields() {
|
||||
|
@ -866,7 +867,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
|
|||
self.effective_visibility_diagnostic(item.owner_id.def_id);
|
||||
|
||||
match item.kind {
|
||||
hir::ItemKind::Enum(ref def, _) => {
|
||||
hir::ItemKind::Enum(_, ref def, _) => {
|
||||
for variant in def.variants.iter() {
|
||||
self.effective_visibility_diagnostic(variant.def_id);
|
||||
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
|
||||
|
@ -877,7 +878,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
|
||||
hir::ItemKind::Struct(_, ref def, _) | hir::ItemKind::Union(_, ref def, _) => {
|
||||
if let Some(ctor_def_id) = def.ctor_def_id() {
|
||||
self.effective_visibility_diagnostic(ctor_def_id);
|
||||
}
|
||||
|
@ -1636,7 +1637,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
|
|||
}
|
||||
DefKind::Enum => {
|
||||
let item = tcx.hir_item(id);
|
||||
if let hir::ItemKind::Enum(ref def, _) = item.kind {
|
||||
if let hir::ItemKind::Enum(_, ref def, _) = item.kind {
|
||||
self.check_unnameable(item.owner_id.def_id, effective_vis);
|
||||
|
||||
self.check(item.owner_id.def_id, item_visibility, effective_vis)
|
||||
|
@ -1674,8 +1675,8 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
|
|||
// Subitems of structs and unions have their own publicity.
|
||||
DefKind::Struct | DefKind::Union => {
|
||||
let item = tcx.hir_item(id);
|
||||
if let hir::ItemKind::Struct(ref struct_def, _)
|
||||
| hir::ItemKind::Union(ref struct_def, _) = item.kind
|
||||
if let hir::ItemKind::Struct(_, ref struct_def, _)
|
||||
| hir::ItemKind::Union(_, ref struct_def, _) = item.kind
|
||||
{
|
||||
self.check_unnameable(item.owner_id.def_id, effective_vis);
|
||||
self.check(item.owner_id.def_id, item_visibility, effective_vis)
|
||||
|
|
|
@ -923,6 +923,28 @@ impl Target {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
"loongarch64" => {
|
||||
// LoongArch handles ABI in a very sane way, being fully explicit via `llvm_abiname`
|
||||
// about what the intended ABI is.
|
||||
match &*self.llvm_abiname {
|
||||
"ilp32d" | "lp64d" => {
|
||||
// Requires d (which implies f), incompatible with nothing.
|
||||
FeatureConstraints { required: &["d"], incompatible: &[] }
|
||||
}
|
||||
"ilp32f" | "lp64f" => {
|
||||
// Requires f, incompatible with nothing.
|
||||
FeatureConstraints { required: &["f"], incompatible: &[] }
|
||||
}
|
||||
"ilp32s" | "lp64s" => {
|
||||
// The soft-float ABI does not require any features and is also not
|
||||
// incompatible with any features. Rust targets explicitly specify the
|
||||
// LLVM ABI names, which allows for enabling hard-float support even on
|
||||
// soft-float targets, and ensures that the ABI behavior is as expected.
|
||||
NOTHING
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => NOTHING,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2026,7 +2026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
LetVisitor { span }.visit_body(body).break_value()
|
||||
}
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }) => {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, ty, _, _), .. }) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None,
|
||||
|
|
|
@ -338,7 +338,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
..
|
||||
},
|
||||
hir::PathSegment {
|
||||
ident: assoc_item_name,
|
||||
ident: assoc_item_ident,
|
||||
res: Res::Def(_, item_id),
|
||||
..
|
||||
},
|
||||
|
@ -368,17 +368,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
if let Some(local_def_id) = data.trait_ref.def_id.as_local()
|
||||
&& let hir::Node::Item(hir::Item {
|
||||
ident: trait_name,
|
||||
kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
|
||||
kind: hir::ItemKind::Trait(_, _, trait_ident, _, _, trait_item_refs),
|
||||
..
|
||||
}) = self.tcx.hir_node_by_def_id(local_def_id)
|
||||
&& let Some(method_ref) = trait_item_refs
|
||||
.iter()
|
||||
.find(|item_ref| item_ref.ident == *assoc_item_name)
|
||||
.find(|item_ref| item_ref.ident == *assoc_item_ident)
|
||||
{
|
||||
err.span_label(
|
||||
method_ref.span,
|
||||
format!("`{trait_name}::{assoc_item_name}` defined here"),
|
||||
format!("`{trait_ident}::{assoc_item_ident}` defined here"),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -419,7 +419,12 @@ pub fn report_dyn_incompatibility<'tcx>(
|
|||
) -> Diag<'tcx> {
|
||||
let trait_str = tcx.def_path_str(trait_def_id);
|
||||
let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
|
||||
hir::Node::Item(item) => Some(item.ident.span),
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => {
|
||||
Some(ident.span)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => None,
|
||||
});
|
||||
|
||||
|
|
|
@ -267,8 +267,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let node = self.tcx.hir_node_by_def_id(body_id);
|
||||
match node {
|
||||
hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Trait(_, _, generics, bounds, _),
|
||||
kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _),
|
||||
..
|
||||
}) if self_ty == self.tcx.types.self_param => {
|
||||
assert!(param_ty);
|
||||
|
@ -282,7 +281,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
None,
|
||||
projection,
|
||||
trait_pred,
|
||||
Some((ident, bounds)),
|
||||
Some((&ident, bounds)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -331,7 +330,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}
|
||||
hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Trait(_, _, generics, ..)
|
||||
hir::ItemKind::Trait(_, _, _, generics, ..)
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. }),
|
||||
..
|
||||
}) if projection.is_some() => {
|
||||
|
@ -352,15 +351,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Struct(_, generics)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
hir::ItemKind::Struct(_, _, generics)
|
||||
| hir::ItemKind::Enum(_, _, generics)
|
||||
| hir::ItemKind::Union(_, _, generics)
|
||||
| hir::ItemKind::Trait(_, _, _, generics, ..)
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. })
|
||||
| hir::ItemKind::Fn { generics, .. }
|
||||
| hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Const(_, generics, _)
|
||||
| hir::ItemKind::TraitAlias(generics, _),
|
||||
| hir::ItemKind::TyAlias(_, _, generics)
|
||||
| hir::ItemKind::Const(_, _, generics, _)
|
||||
| hir::ItemKind::TraitAlias(_, generics, _),
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem { generics, .. })
|
||||
|
@ -412,15 +411,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Struct(_, generics)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
hir::ItemKind::Struct(_, _, generics)
|
||||
| hir::ItemKind::Enum(_, _, generics)
|
||||
| hir::ItemKind::Union(_, _, generics)
|
||||
| hir::ItemKind::Trait(_, _, _, generics, ..)
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. })
|
||||
| hir::ItemKind::Fn { generics, .. }
|
||||
| hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Const(_, generics, _)
|
||||
| hir::ItemKind::TraitAlias(generics, _),
|
||||
| hir::ItemKind::TyAlias(_, _, generics)
|
||||
| hir::ItemKind::Const(_, _, generics, _)
|
||||
| hir::ItemKind::TraitAlias(_, generics, _),
|
||||
..
|
||||
}) if !param_ty => {
|
||||
// Missing generic type parameter bound.
|
||||
|
@ -842,7 +841,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
name.to_string()
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Fn { .. }, ..
|
||||
kind: hir::ItemKind::Fn { ident, .. }, ..
|
||||
})) => {
|
||||
err.span_label(ident.span, "consider calling this function");
|
||||
ident.to_string()
|
||||
|
@ -1588,20 +1587,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if let Some(typeck_results) = &self.typeck_results
|
||||
&& let ty = typeck_results.expr_ty_adjusted(base)
|
||||
&& let ty::FnDef(def_id, _args) = ty.kind()
|
||||
&& let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
|
||||
self.tcx.hir_get_if_local(*def_id)
|
||||
&& let Some(hir::Node::Item(item)) = self.tcx.hir_get_if_local(*def_id)
|
||||
{
|
||||
let (ident, _, _, _) = item.expect_fn();
|
||||
let msg = format!("alternatively, consider making `fn {ident}` asynchronous");
|
||||
if vis_span.is_empty() {
|
||||
if item.vis_span.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
item.span.shrink_to_lo(),
|
||||
msg,
|
||||
"async ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
vis_span.shrink_to_hi(),
|
||||
item.vis_span.shrink_to_hi(),
|
||||
msg,
|
||||
" async",
|
||||
Applicability::MaybeIncorrect,
|
||||
|
@ -3303,8 +3302,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let mut is_auto_trait = false;
|
||||
match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
|
||||
Some(Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(is_auto, ..),
|
||||
ident,
|
||||
kind: hir::ItemKind::Trait(is_auto, _, ident, ..),
|
||||
..
|
||||
})) => {
|
||||
// FIXME: we should do something else so that it works even on crate foreign
|
||||
|
|
|
@ -516,7 +516,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
|
||||
{
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(_, _, generics, ..),
|
||||
kind: hir::ItemKind::Trait(_, _, _, generics, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::Item(hir::Item {
|
||||
|
|
362
src/ci/citool/src/analysis.rs
Normal file
362
src/ci/citool/src/analysis.rs
Normal file
|
@ -0,0 +1,362 @@
|
|||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
use build_helper::metrics::{
|
||||
BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps,
|
||||
};
|
||||
|
||||
use crate::metrics;
|
||||
use crate::metrics::{JobMetrics, JobName, get_test_suites};
|
||||
use crate::utils::{output_details, pluralize};
|
||||
|
||||
pub fn output_bootstrap_stats(metrics: &JsonRoot) {
|
||||
if !metrics.invocations.is_empty() {
|
||||
println!("# Bootstrap steps");
|
||||
record_bootstrap_step_durations(&metrics);
|
||||
record_test_suites(&metrics);
|
||||
}
|
||||
}
|
||||
|
||||
fn record_bootstrap_step_durations(metrics: &JsonRoot) {
|
||||
for invocation in &metrics.invocations {
|
||||
let step = BuildStep::from_invocation(invocation);
|
||||
let table = format_build_steps(&step);
|
||||
eprintln!("Step `{}`\n{table}\n", invocation.cmdline);
|
||||
output_details(&invocation.cmdline, || {
|
||||
println!("<pre><code>{table}</code></pre>");
|
||||
});
|
||||
}
|
||||
eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len());
|
||||
}
|
||||
|
||||
fn record_test_suites(metrics: &JsonRoot) {
|
||||
let suites = metrics::get_test_suites(&metrics);
|
||||
|
||||
if !suites.is_empty() {
|
||||
let aggregated = aggregate_test_suites(&suites);
|
||||
let table = render_table(aggregated);
|
||||
println!("\n# Test results\n");
|
||||
println!("{table}");
|
||||
} else {
|
||||
eprintln!("No test suites found in metrics");
|
||||
}
|
||||
}
|
||||
|
||||
fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string();
|
||||
writeln!(table, "|:------|------:|------:|------:|").unwrap();
|
||||
|
||||
fn compute_pct(value: f64, total: f64) -> f64 {
|
||||
if total == 0.0 { 0.0 } else { value / total }
|
||||
}
|
||||
|
||||
fn write_row(
|
||||
buffer: &mut String,
|
||||
name: &str,
|
||||
record: &TestSuiteRecord,
|
||||
surround: &str,
|
||||
) -> std::fmt::Result {
|
||||
let TestSuiteRecord { passed, ignored, failed } = record;
|
||||
let total = (record.passed + record.ignored + record.failed) as f64;
|
||||
let passed_pct = compute_pct(*passed as f64, total) * 100.0;
|
||||
let ignored_pct = compute_pct(*ignored as f64, total) * 100.0;
|
||||
let failed_pct = compute_pct(*failed as f64, total) * 100.0;
|
||||
|
||||
write!(buffer, "| {surround}{name}{surround} |")?;
|
||||
write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?;
|
||||
write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?;
|
||||
writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mut total = TestSuiteRecord::default();
|
||||
for (name, record) in suites {
|
||||
write_row(&mut table, &name, &record, "").unwrap();
|
||||
total.passed += record.passed;
|
||||
total.ignored += record.ignored;
|
||||
total.failed += record.failed;
|
||||
}
|
||||
write_row(&mut table, "Total", &total, "**").unwrap();
|
||||
table
|
||||
}
|
||||
|
||||
/// Computes a post merge CI analysis report of test differences
|
||||
/// between the `parent` and `current` commits.
|
||||
pub fn output_test_diffs(job_metrics: HashMap<JobName, JobMetrics>) {
|
||||
let aggregated_test_diffs = aggregate_test_diffs(&job_metrics);
|
||||
report_test_diffs(aggregated_test_diffs);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestSuiteRecord {
|
||||
passed: u64,
|
||||
ignored: u64,
|
||||
failed: u64,
|
||||
}
|
||||
|
||||
fn test_metadata_name(metadata: &TestSuiteMetadata) -> String {
|
||||
match metadata {
|
||||
TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
|
||||
format!("{} (stage {stage})", crates.join(", "))
|
||||
}
|
||||
TestSuiteMetadata::Compiletest { suite, stage, .. } => {
|
||||
format!("{suite} (stage {stage})")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> {
|
||||
let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new();
|
||||
for suite in suites {
|
||||
let name = test_metadata_name(&suite.metadata);
|
||||
let record = records.entry(name).or_default();
|
||||
for test in &suite.tests {
|
||||
match test.outcome {
|
||||
TestOutcome::Passed => {
|
||||
record.passed += 1;
|
||||
}
|
||||
TestOutcome::Failed => {
|
||||
record.failed += 1;
|
||||
}
|
||||
TestOutcome::Ignored { .. } => {
|
||||
record.ignored += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
records
|
||||
}
|
||||
|
||||
/// Represents a difference in the outcome of tests between a base and a current commit.
|
||||
/// Maps test diffs to jobs that contained them.
|
||||
#[derive(Debug)]
|
||||
struct AggregatedTestDiffs {
|
||||
diffs: HashMap<TestDiff, Vec<JobName>>,
|
||||
}
|
||||
|
||||
fn aggregate_test_diffs(jobs: &HashMap<JobName, JobMetrics>) -> AggregatedTestDiffs {
|
||||
let mut diffs: HashMap<TestDiff, Vec<JobName>> = HashMap::new();
|
||||
|
||||
// Aggregate test suites
|
||||
for (name, metrics) in jobs {
|
||||
if let Some(parent) = &metrics.parent {
|
||||
let tests_parent = aggregate_tests(parent);
|
||||
let tests_current = aggregate_tests(&metrics.current);
|
||||
for diff in calculate_test_diffs(tests_parent, tests_current) {
|
||||
diffs.entry(diff).or_default().push(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AggregatedTestDiffs { diffs }
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
enum TestOutcomeDiff {
|
||||
ChangeOutcome { before: TestOutcome, after: TestOutcome },
|
||||
Missing { before: TestOutcome },
|
||||
Added(TestOutcome),
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
struct TestDiff {
|
||||
test: Test,
|
||||
diff: TestOutcomeDiff,
|
||||
}
|
||||
|
||||
fn calculate_test_diffs(parent: TestSuiteData, current: TestSuiteData) -> HashSet<TestDiff> {
|
||||
let mut diffs = HashSet::new();
|
||||
for (test, outcome) in ¤t.tests {
|
||||
match parent.tests.get(test) {
|
||||
Some(before) => {
|
||||
if before != outcome {
|
||||
diffs.insert(TestDiff {
|
||||
test: test.clone(),
|
||||
diff: TestOutcomeDiff::ChangeOutcome {
|
||||
before: before.clone(),
|
||||
after: outcome.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
diffs.insert(TestDiff {
|
||||
test: test.clone(),
|
||||
diff: TestOutcomeDiff::Added(outcome.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (test, outcome) in &parent.tests {
|
||||
if !current.tests.contains_key(test) {
|
||||
diffs.insert(TestDiff {
|
||||
test: test.clone(),
|
||||
diff: TestOutcomeDiff::Missing { before: outcome.clone() },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
diffs
|
||||
}
|
||||
|
||||
/// Aggregates test suite executions from all bootstrap invocations in a given CI job.
|
||||
#[derive(Default)]
|
||||
struct TestSuiteData {
|
||||
tests: HashMap<Test, TestOutcome>,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
|
||||
struct Test {
|
||||
name: String,
|
||||
is_doctest: bool,
|
||||
}
|
||||
|
||||
/// Extracts all tests from the passed metrics and map them to their outcomes.
|
||||
fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
|
||||
let mut tests = HashMap::new();
|
||||
let test_suites = get_test_suites(&metrics);
|
||||
for suite in test_suites {
|
||||
for test in &suite.tests {
|
||||
// Poor man's detection of doctests based on the "(line XYZ)" suffix
|
||||
let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. })
|
||||
&& test.name.contains("(line");
|
||||
let test_entry = Test { name: generate_test_name(&test.name, &suite), is_doctest };
|
||||
tests.insert(test_entry, test.outcome.clone());
|
||||
}
|
||||
}
|
||||
TestSuiteData { tests }
|
||||
}
|
||||
|
||||
/// Normalizes Windows-style path delimiters to Unix-style paths
|
||||
/// and adds suite metadata to the test name.
|
||||
fn generate_test_name(name: &str, suite: &TestSuite) -> String {
|
||||
let name = name.replace('\\', "/");
|
||||
let stage = match suite.metadata {
|
||||
TestSuiteMetadata::CargoPackage { stage, .. } => stage,
|
||||
TestSuiteMetadata::Compiletest { stage, .. } => stage,
|
||||
};
|
||||
|
||||
format!("{name} (stage {stage})")
|
||||
}
|
||||
|
||||
/// Prints test changes in Markdown format to stdout.
|
||||
fn report_test_diffs(diff: AggregatedTestDiffs) {
|
||||
println!("# Test differences");
|
||||
if diff.diffs.is_empty() {
|
||||
println!("No test diffs found");
|
||||
return;
|
||||
}
|
||||
|
||||
fn format_outcome(outcome: &TestOutcome) -> String {
|
||||
match outcome {
|
||||
TestOutcome::Passed => "pass".to_string(),
|
||||
TestOutcome::Failed => "fail".to_string(),
|
||||
TestOutcome::Ignored { ignore_reason } => {
|
||||
let reason = match ignore_reason {
|
||||
Some(reason) => format!(" ({reason})"),
|
||||
None => String::new(),
|
||||
};
|
||||
format!("ignore{reason}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_diff(diff: &TestOutcomeDiff) -> String {
|
||||
match diff {
|
||||
TestOutcomeDiff::ChangeOutcome { before, after } => {
|
||||
format!("{} -> {}", format_outcome(before), format_outcome(after))
|
||||
}
|
||||
TestOutcomeDiff::Missing { before } => {
|
||||
format!("{} -> [missing]", format_outcome(before))
|
||||
}
|
||||
TestOutcomeDiff::Added(outcome) => {
|
||||
format!("[missing] -> {}", format_outcome(outcome))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_job_group(group: u64) -> String {
|
||||
format!("**J{group}**")
|
||||
}
|
||||
|
||||
// It would be quite noisy to repeat the jobs that contained the test changes after/next to
|
||||
// every test diff. At the same time, grouping the test diffs by
|
||||
// [unique set of jobs that contained them] also doesn't work well, because the test diffs
|
||||
// would have to be duplicated several times.
|
||||
// Instead, we create a set of unique job groups, and then print a job group after each test.
|
||||
// We then print the job groups at the end, as a sort of index.
|
||||
let mut grouped_diffs: Vec<(&TestDiff, u64)> = vec![];
|
||||
let mut job_list_to_group: HashMap<&[JobName], u64> = HashMap::new();
|
||||
let mut job_index: Vec<&[JobName]> = vec![];
|
||||
|
||||
let original_diff_count = diff.diffs.len();
|
||||
let diffs = diff
|
||||
.diffs
|
||||
.into_iter()
|
||||
.filter(|(diff, _)| !diff.test.is_doctest)
|
||||
.map(|(diff, mut jobs)| {
|
||||
jobs.sort();
|
||||
(diff, jobs)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let doctest_count = original_diff_count.saturating_sub(diffs.len());
|
||||
|
||||
let max_diff_count = 100;
|
||||
for (diff, jobs) in diffs.iter().take(max_diff_count) {
|
||||
let jobs = &*jobs;
|
||||
let job_group = match job_list_to_group.get(jobs.as_slice()) {
|
||||
Some(id) => *id,
|
||||
None => {
|
||||
let id = job_index.len() as u64;
|
||||
job_index.push(jobs);
|
||||
job_list_to_group.insert(jobs, id);
|
||||
id
|
||||
}
|
||||
};
|
||||
grouped_diffs.push((diff, job_group));
|
||||
}
|
||||
|
||||
// Sort diffs by job group and test name
|
||||
grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name)));
|
||||
|
||||
output_details(
|
||||
&format!("Show {} test {}\n", original_diff_count, pluralize("diff", original_diff_count)),
|
||||
|| {
|
||||
for (diff, job_group) in grouped_diffs {
|
||||
println!(
|
||||
"- `{}`: {} ({})",
|
||||
diff.test.name,
|
||||
format_diff(&diff.diff),
|
||||
format_job_group(job_group)
|
||||
);
|
||||
}
|
||||
|
||||
let extra_diffs = diffs.len().saturating_sub(max_diff_count);
|
||||
if extra_diffs > 0 {
|
||||
println!(
|
||||
"\n(and {extra_diffs} additional {})",
|
||||
pluralize("test diff", extra_diffs)
|
||||
);
|
||||
}
|
||||
|
||||
if doctest_count > 0 {
|
||||
println!(
|
||||
"\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.",
|
||||
pluralize("diff", doctest_count)
|
||||
);
|
||||
}
|
||||
|
||||
// Now print the job group index
|
||||
println!("\n**Job group index**\n");
|
||||
for (group, jobs) in job_index.into_iter().enumerate() {
|
||||
println!(
|
||||
"- {}: {}",
|
||||
format_job_group(group as u64),
|
||||
jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ")
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
|
@ -185,6 +185,20 @@ fn calculate_jobs(
|
|||
env.extend(crate::yaml_map_to_json(&job.env));
|
||||
let full_name = format!("{prefix} - {}", job.name);
|
||||
|
||||
// When the default `@bors try` job is executed (which is usually done
|
||||
// for benchmarking performance, running crater or for downloading the
|
||||
// built toolchain using `rustup-toolchain-install-master`),
|
||||
// we inject the `DIST_TRY_BUILD` environment variable to the jobs
|
||||
// to tell `opt-dist` to make the build faster by skipping certain steps.
|
||||
if let RunType::TryJob { job_patterns } = run_type {
|
||||
if job_patterns.is_none() {
|
||||
env.insert(
|
||||
"DIST_TRY_BUILD".to_string(),
|
||||
serde_json::value::Value::Number(1.into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
GithubActionsJob {
|
||||
name: job.name,
|
||||
full_name,
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
mod analysis;
|
||||
mod cpu_usage;
|
||||
mod datadog;
|
||||
mod jobs;
|
||||
mod merge_report;
|
||||
mod metrics;
|
||||
mod utils;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use analysis::output_bootstrap_stats;
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
use jobs::JobDatabase;
|
||||
use serde_yaml::Value;
|
||||
|
||||
use crate::analysis::output_test_diffs;
|
||||
use crate::cpu_usage::load_cpu_usage;
|
||||
use crate::datadog::upload_datadog_metric;
|
||||
use crate::jobs::RunType;
|
||||
use crate::merge_report::post_merge_report;
|
||||
use crate::metrics::postprocess_metrics;
|
||||
use crate::utils::load_env_var;
|
||||
use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
|
||||
use crate::utils::{load_env_var, output_details};
|
||||
|
||||
const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
|
||||
const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
|
||||
|
@ -137,6 +138,56 @@ fn upload_ci_metrics(cpu_usage_csv: &Path) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn postprocess_metrics(
|
||||
metrics_path: PathBuf,
|
||||
parent: Option<String>,
|
||||
job_name: Option<String>,
|
||||
) -> anyhow::Result<()> {
|
||||
let metrics = load_metrics(&metrics_path)?;
|
||||
output_bootstrap_stats(&metrics);
|
||||
|
||||
let (Some(parent), Some(job_name)) = (parent, job_name) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// This command is executed also on PR builds, which might not have parent metrics
|
||||
// available, because some PR jobs don't run on auto builds, and PR jobs do not upload metrics
|
||||
// due to missing permissions.
|
||||
// To avoid having to detect if this is a PR job, and to avoid having failed steps in PR jobs,
|
||||
// we simply print an error if the parent metrics were not found, but otherwise exit
|
||||
// successfully.
|
||||
match download_job_metrics(&job_name, &parent).context("cannot download parent metrics") {
|
||||
Ok(parent_metrics) => {
|
||||
let job_metrics = HashMap::from([(
|
||||
job_name,
|
||||
JobMetrics { parent: Some(parent_metrics), current: metrics },
|
||||
)]);
|
||||
output_test_diffs(job_metrics);
|
||||
}
|
||||
Err(error) => {
|
||||
eprintln!("Metrics for job `{job_name}` and commit `{parent}` not found: {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow::Result<()> {
|
||||
let metrics = download_auto_job_metrics(&db, &parent, ¤t)?;
|
||||
|
||||
output_details("What is this?", || {
|
||||
println!(
|
||||
r#"This is an experimental post-merge analysis report that shows differences in
|
||||
test outcomes between the merged PR and its parent PR."#
|
||||
);
|
||||
});
|
||||
|
||||
println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
|
||||
output_test_diffs(metrics);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
enum Args {
|
||||
/// Calculate a list of jobs that should be executed on CI.
|
||||
|
@ -154,13 +205,19 @@ enum Args {
|
|||
#[clap(long = "type", default_value = "auto")]
|
||||
job_type: JobType,
|
||||
},
|
||||
/// Postprocess the metrics.json file generated by bootstrap.
|
||||
/// Postprocess the metrics.json file generated by bootstrap and output
|
||||
/// various statistics.
|
||||
/// If `--parent` and `--job-name` are provided, also display a diff
|
||||
/// against previous metrics that are downloaded from CI.
|
||||
PostprocessMetrics {
|
||||
/// Path to the metrics.json file
|
||||
metrics_path: PathBuf,
|
||||
/// Path to a file where the postprocessed metrics summary will be stored.
|
||||
/// Usually, this will be GITHUB_STEP_SUMMARY on CI.
|
||||
summary_path: PathBuf,
|
||||
/// A parent SHA against which to compare.
|
||||
#[clap(long, requires("job_name"))]
|
||||
parent: Option<String>,
|
||||
/// The name of the current job.
|
||||
#[clap(long, requires("parent"))]
|
||||
job_name: Option<String>,
|
||||
},
|
||||
/// Upload CI metrics to Datadog.
|
||||
UploadBuildMetrics {
|
||||
|
@ -211,11 +268,11 @@ fn main() -> anyhow::Result<()> {
|
|||
Args::UploadBuildMetrics { cpu_usage_csv } => {
|
||||
upload_ci_metrics(&cpu_usage_csv)?;
|
||||
}
|
||||
Args::PostprocessMetrics { metrics_path, summary_path } => {
|
||||
postprocess_metrics(&metrics_path, &summary_path)?;
|
||||
Args::PostprocessMetrics { metrics_path, parent, job_name } => {
|
||||
postprocess_metrics(metrics_path, parent, job_name)?;
|
||||
}
|
||||
Args::PostMergeReport { current: commit, parent } => {
|
||||
post_merge_report(load_db(default_jobs_file)?, parent, commit)?;
|
||||
Args::PostMergeReport { current, parent } => {
|
||||
post_merge_report(load_db(default_jobs_file)?, current, parent)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,318 +0,0 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Context;
|
||||
use build_helper::metrics::{JsonRoot, TestOutcome, TestSuiteMetadata};
|
||||
|
||||
use crate::jobs::JobDatabase;
|
||||
use crate::metrics::get_test_suites;
|
||||
|
||||
type Sha = String;
|
||||
type JobName = String;
|
||||
|
||||
/// Computes a post merge CI analysis report between the `parent` and `current` commits.
|
||||
pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> {
|
||||
let jobs = download_all_metrics(&job_db, &parent, ¤t)?;
|
||||
let aggregated_test_diffs = aggregate_test_diffs(&jobs)?;
|
||||
|
||||
println!("Comparing {parent} (base) -> {current} (this PR)\n");
|
||||
report_test_diffs(aggregated_test_diffs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct JobMetrics {
|
||||
parent: Option<JsonRoot>,
|
||||
current: JsonRoot,
|
||||
}
|
||||
|
||||
/// Download before/after metrics for all auto jobs in the job database.
|
||||
fn download_all_metrics(
|
||||
job_db: &JobDatabase,
|
||||
parent: &str,
|
||||
current: &str,
|
||||
) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
|
||||
let mut jobs = HashMap::default();
|
||||
|
||||
for job in &job_db.auto_jobs {
|
||||
eprintln!("Downloading metrics of job {}", job.name);
|
||||
let metrics_parent = match download_job_metrics(&job.name, parent) {
|
||||
Ok(metrics) => Some(metrics),
|
||||
Err(error) => {
|
||||
eprintln!(
|
||||
r#"Did not find metrics for job `{}` at `{}`: {error:?}.
|
||||
Maybe it was newly added?"#,
|
||||
job.name, parent
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
let metrics_current = download_job_metrics(&job.name, current)?;
|
||||
jobs.insert(
|
||||
job.name.clone(),
|
||||
JobMetrics { parent: metrics_parent, current: metrics_current },
|
||||
);
|
||||
}
|
||||
Ok(jobs)
|
||||
}
|
||||
|
||||
/// Downloads job metrics of the given job for the given commit.
|
||||
/// Caches the result on the local disk.
|
||||
fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
|
||||
let cache_path = PathBuf::from(".citool-cache").join(sha).join(job_name).join("metrics.json");
|
||||
if let Some(cache_entry) =
|
||||
std::fs::read_to_string(&cache_path).ok().and_then(|data| serde_json::from_str(&data).ok())
|
||||
{
|
||||
return Ok(cache_entry);
|
||||
}
|
||||
|
||||
let url = get_metrics_url(job_name, sha);
|
||||
let mut response = ureq::get(&url).call()?;
|
||||
if !response.status().is_success() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Cannot fetch metrics from {url}: {}\n{}",
|
||||
response.status(),
|
||||
response.body_mut().read_to_string()?
|
||||
));
|
||||
}
|
||||
let data: JsonRoot = response
|
||||
.body_mut()
|
||||
.read_json()
|
||||
.with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;
|
||||
|
||||
// Ignore errors if cache cannot be created
|
||||
if std::fs::create_dir_all(cache_path.parent().unwrap()).is_ok() {
|
||||
if let Ok(serialized) = serde_json::to_string(&data) {
|
||||
let _ = std::fs::write(&cache_path, &serialized);
|
||||
}
|
||||
}
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn get_metrics_url(job_name: &str, sha: &str) -> String {
|
||||
let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" };
|
||||
format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json")
|
||||
}
|
||||
|
||||
/// Represents a difference in the outcome of tests between a base and a current commit.
|
||||
/// Maps test diffs to jobs that contained them.
|
||||
#[derive(Debug)]
|
||||
struct AggregatedTestDiffs {
|
||||
diffs: HashMap<TestDiff, Vec<JobName>>,
|
||||
}
|
||||
|
||||
fn aggregate_test_diffs(
|
||||
jobs: &HashMap<JobName, JobMetrics>,
|
||||
) -> anyhow::Result<AggregatedTestDiffs> {
|
||||
let mut diffs: HashMap<TestDiff, Vec<JobName>> = HashMap::new();
|
||||
|
||||
// Aggregate test suites
|
||||
for (name, metrics) in jobs {
|
||||
if let Some(parent) = &metrics.parent {
|
||||
let tests_parent = aggregate_tests(parent);
|
||||
let tests_current = aggregate_tests(&metrics.current);
|
||||
for diff in calculate_test_diffs(tests_parent, tests_current) {
|
||||
diffs.entry(diff).or_default().push(name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(AggregatedTestDiffs { diffs })
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
enum TestOutcomeDiff {
|
||||
ChangeOutcome { before: TestOutcome, after: TestOutcome },
|
||||
Missing { before: TestOutcome },
|
||||
Added(TestOutcome),
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
struct TestDiff {
|
||||
test: Test,
|
||||
diff: TestOutcomeDiff,
|
||||
}
|
||||
|
||||
fn calculate_test_diffs(parent: TestSuiteData, current: TestSuiteData) -> HashSet<TestDiff> {
|
||||
let mut diffs = HashSet::new();
|
||||
for (test, outcome) in ¤t.tests {
|
||||
match parent.tests.get(test) {
|
||||
Some(before) => {
|
||||
if before != outcome {
|
||||
diffs.insert(TestDiff {
|
||||
test: test.clone(),
|
||||
diff: TestOutcomeDiff::ChangeOutcome {
|
||||
before: before.clone(),
|
||||
after: outcome.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
diffs.insert(TestDiff {
|
||||
test: test.clone(),
|
||||
diff: TestOutcomeDiff::Added(outcome.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (test, outcome) in &parent.tests {
|
||||
if !current.tests.contains_key(test) {
|
||||
diffs.insert(TestDiff {
|
||||
test: test.clone(),
|
||||
diff: TestOutcomeDiff::Missing { before: outcome.clone() },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
diffs
|
||||
}
|
||||
|
||||
/// Aggregates test suite executions from all bootstrap invocations in a given CI job.
|
||||
#[derive(Default)]
|
||||
struct TestSuiteData {
|
||||
tests: HashMap<Test, TestOutcome>,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug, Clone)]
|
||||
struct Test {
|
||||
name: String,
|
||||
is_doctest: bool,
|
||||
}
|
||||
|
||||
/// Extracts all tests from the passed metrics and map them to their outcomes.
|
||||
fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
|
||||
let mut tests = HashMap::new();
|
||||
let test_suites = get_test_suites(&metrics);
|
||||
for suite in test_suites {
|
||||
for test in &suite.tests {
|
||||
// Poor man's detection of doctests based on the "(line XYZ)" suffix
|
||||
let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. })
|
||||
&& test.name.contains("(line");
|
||||
let test_entry = Test { name: normalize_test_name(&test.name), is_doctest };
|
||||
tests.insert(test_entry, test.outcome.clone());
|
||||
}
|
||||
}
|
||||
TestSuiteData { tests }
|
||||
}
|
||||
|
||||
/// Normalizes Windows-style path delimiters to Unix-style paths.
|
||||
fn normalize_test_name(name: &str) -> String {
|
||||
name.replace('\\', "/")
|
||||
}
|
||||
|
||||
/// Prints test changes in Markdown format to stdout.
|
||||
fn report_test_diffs(diff: AggregatedTestDiffs) {
|
||||
println!("## Test differences");
|
||||
if diff.diffs.is_empty() {
|
||||
println!("No test diffs found");
|
||||
return;
|
||||
}
|
||||
|
||||
fn format_outcome(outcome: &TestOutcome) -> String {
|
||||
match outcome {
|
||||
TestOutcome::Passed => "pass".to_string(),
|
||||
TestOutcome::Failed => "fail".to_string(),
|
||||
TestOutcome::Ignored { ignore_reason } => {
|
||||
let reason = match ignore_reason {
|
||||
Some(reason) => format!(" ({reason})"),
|
||||
None => String::new(),
|
||||
};
|
||||
format!("ignore{reason}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_diff(diff: &TestOutcomeDiff) -> String {
|
||||
match diff {
|
||||
TestOutcomeDiff::ChangeOutcome { before, after } => {
|
||||
format!("{} -> {}", format_outcome(before), format_outcome(after))
|
||||
}
|
||||
TestOutcomeDiff::Missing { before } => {
|
||||
format!("{} -> [missing]", format_outcome(before))
|
||||
}
|
||||
TestOutcomeDiff::Added(outcome) => {
|
||||
format!("[missing] -> {}", format_outcome(outcome))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_job_group(group: u64) -> String {
|
||||
format!("**J{group}**")
|
||||
}
|
||||
|
||||
// It would be quite noisy to repeat the jobs that contained the test changes after/next to
|
||||
// every test diff. At the same time, grouping the test diffs by
|
||||
// [unique set of jobs that contained them] also doesn't work well, because the test diffs
|
||||
// would have to be duplicated several times.
|
||||
// Instead, we create a set of unique job groups, and then print a job group after each test.
|
||||
// We then print the job groups at the end, as a sort of index.
|
||||
let mut grouped_diffs: Vec<(&TestDiff, u64)> = vec![];
|
||||
let mut job_list_to_group: HashMap<&[JobName], u64> = HashMap::new();
|
||||
let mut job_index: Vec<&[JobName]> = vec![];
|
||||
|
||||
let original_diff_count = diff.diffs.len();
|
||||
let diffs = diff
|
||||
.diffs
|
||||
.into_iter()
|
||||
.filter(|(diff, _)| !diff.test.is_doctest)
|
||||
.map(|(diff, mut jobs)| {
|
||||
jobs.sort();
|
||||
(diff, jobs)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let doctest_count = original_diff_count.saturating_sub(diffs.len());
|
||||
|
||||
let max_diff_count = 100;
|
||||
for (diff, jobs) in diffs.iter().take(max_diff_count) {
|
||||
let jobs = &*jobs;
|
||||
let job_group = match job_list_to_group.get(jobs.as_slice()) {
|
||||
Some(id) => *id,
|
||||
None => {
|
||||
let id = job_index.len() as u64;
|
||||
job_index.push(jobs);
|
||||
job_list_to_group.insert(jobs, id);
|
||||
id
|
||||
}
|
||||
};
|
||||
grouped_diffs.push((diff, job_group));
|
||||
}
|
||||
|
||||
// Sort diffs by job group and test name
|
||||
grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name)));
|
||||
|
||||
for (diff, job_group) in grouped_diffs {
|
||||
println!(
|
||||
"- `{}`: {} ({})",
|
||||
diff.test.name,
|
||||
format_diff(&diff.diff),
|
||||
format_job_group(job_group)
|
||||
);
|
||||
}
|
||||
|
||||
let extra_diffs = diffs.len().saturating_sub(max_diff_count);
|
||||
if extra_diffs > 0 {
|
||||
println!("\n(and {extra_diffs} additional {})", pluralize("test diff", extra_diffs));
|
||||
}
|
||||
|
||||
if doctest_count > 0 {
|
||||
println!(
|
||||
"\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.",
|
||||
pluralize("diff", doctest_count)
|
||||
);
|
||||
}
|
||||
|
||||
// Now print the job group index
|
||||
println!("\n**Job group index**\n");
|
||||
for (group, jobs) in job_index.into_iter().enumerate() {
|
||||
println!(
|
||||
"- {}: {}",
|
||||
format_job_group(group as u64),
|
||||
jobs.iter().map(|j| format!("`{j}`")).collect::<Vec<_>>().join(", ")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn pluralize(text: &str, count: usize) -> String {
|
||||
if count == 1 { text.to_string() } else { format!("{text}s") }
|
||||
}
|
|
@ -1,146 +1,12 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Context;
|
||||
use build_helper::metrics::{
|
||||
BuildStep, JsonNode, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps,
|
||||
};
|
||||
use build_helper::metrics::{JsonNode, JsonRoot, TestSuite};
|
||||
|
||||
pub fn postprocess_metrics(metrics_path: &Path, summary_path: &Path) -> anyhow::Result<()> {
|
||||
let metrics = load_metrics(metrics_path)?;
|
||||
use crate::jobs::JobDatabase;
|
||||
|
||||
let mut file = File::options()
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(summary_path)
|
||||
.with_context(|| format!("Cannot open summary file at {summary_path:?}"))?;
|
||||
|
||||
if !metrics.invocations.is_empty() {
|
||||
writeln!(file, "# Bootstrap steps")?;
|
||||
record_bootstrap_step_durations(&metrics, &mut file)?;
|
||||
record_test_suites(&metrics, &mut file)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn record_bootstrap_step_durations(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> {
|
||||
for invocation in &metrics.invocations {
|
||||
let step = BuildStep::from_invocation(invocation);
|
||||
let table = format_build_steps(&step);
|
||||
eprintln!("Step `{}`\n{table}\n", invocation.cmdline);
|
||||
writeln!(
|
||||
file,
|
||||
r"<details>
|
||||
<summary>{}</summary>
|
||||
<pre><code>{table}</code></pre>
|
||||
</details>
|
||||
",
|
||||
invocation.cmdline
|
||||
)?;
|
||||
}
|
||||
eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn record_test_suites(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> {
|
||||
let suites = get_test_suites(&metrics);
|
||||
|
||||
if !suites.is_empty() {
|
||||
let aggregated = aggregate_test_suites(&suites);
|
||||
let table = render_table(aggregated);
|
||||
writeln!(file, "\n# Test results\n")?;
|
||||
writeln!(file, "{table}")?;
|
||||
} else {
|
||||
eprintln!("No test suites found in metrics");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_table(suites: BTreeMap<String, TestSuiteRecord>) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string();
|
||||
writeln!(table, "|:------|------:|------:|------:|").unwrap();
|
||||
|
||||
fn compute_pct(value: f64, total: f64) -> f64 {
|
||||
if total == 0.0 { 0.0 } else { value / total }
|
||||
}
|
||||
|
||||
fn write_row(
|
||||
buffer: &mut String,
|
||||
name: &str,
|
||||
record: &TestSuiteRecord,
|
||||
surround: &str,
|
||||
) -> std::fmt::Result {
|
||||
let TestSuiteRecord { passed, ignored, failed } = record;
|
||||
let total = (record.passed + record.ignored + record.failed) as f64;
|
||||
let passed_pct = compute_pct(*passed as f64, total) * 100.0;
|
||||
let ignored_pct = compute_pct(*ignored as f64, total) * 100.0;
|
||||
let failed_pct = compute_pct(*failed as f64, total) * 100.0;
|
||||
|
||||
write!(buffer, "| {surround}{name}{surround} |")?;
|
||||
write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?;
|
||||
write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?;
|
||||
writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mut total = TestSuiteRecord::default();
|
||||
for (name, record) in suites {
|
||||
write_row(&mut table, &name, &record, "").unwrap();
|
||||
total.passed += record.passed;
|
||||
total.ignored += record.ignored;
|
||||
total.failed += record.failed;
|
||||
}
|
||||
write_row(&mut table, "Total", &total, "**").unwrap();
|
||||
table
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestSuiteRecord {
|
||||
passed: u64,
|
||||
ignored: u64,
|
||||
failed: u64,
|
||||
}
|
||||
|
||||
fn test_metadata_name(metadata: &TestSuiteMetadata) -> String {
|
||||
match metadata {
|
||||
TestSuiteMetadata::CargoPackage { crates, stage, .. } => {
|
||||
format!("{} (stage {stage})", crates.join(", "))
|
||||
}
|
||||
TestSuiteMetadata::Compiletest { suite, stage, .. } => {
|
||||
format!("{suite} (stage {stage})")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap<String, TestSuiteRecord> {
|
||||
let mut records: BTreeMap<String, TestSuiteRecord> = BTreeMap::new();
|
||||
for suite in suites {
|
||||
let name = test_metadata_name(&suite.metadata);
|
||||
let record = records.entry(name).or_default();
|
||||
for test in &suite.tests {
|
||||
match test.outcome {
|
||||
TestOutcome::Passed => {
|
||||
record.passed += 1;
|
||||
}
|
||||
TestOutcome::Failed => {
|
||||
record.failed += 1;
|
||||
}
|
||||
TestOutcome::Ignored { .. } => {
|
||||
record.ignored += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
records
|
||||
}
|
||||
pub type JobName = String;
|
||||
|
||||
pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
|
||||
fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) {
|
||||
|
@ -163,10 +29,68 @@ pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> {
|
|||
suites
|
||||
}
|
||||
|
||||
fn load_metrics(path: &Path) -> anyhow::Result<JsonRoot> {
|
||||
pub fn load_metrics(path: &Path) -> anyhow::Result<JsonRoot> {
|
||||
let metrics = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("Cannot read JSON metrics from {path:?}"))?;
|
||||
let metrics: JsonRoot = serde_json::from_str(&metrics)
|
||||
.with_context(|| format!("Cannot deserialize JSON metrics from {path:?}"))?;
|
||||
Ok(metrics)
|
||||
}
|
||||
|
||||
pub struct JobMetrics {
|
||||
pub parent: Option<JsonRoot>,
|
||||
pub current: JsonRoot,
|
||||
}
|
||||
|
||||
/// Download before/after metrics for all auto jobs in the job database.
|
||||
/// `parent` and `current` should be commit SHAs.
|
||||
pub fn download_auto_job_metrics(
|
||||
job_db: &JobDatabase,
|
||||
parent: &str,
|
||||
current: &str,
|
||||
) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
|
||||
let mut jobs = HashMap::default();
|
||||
|
||||
for job in &job_db.auto_jobs {
|
||||
eprintln!("Downloading metrics of job {}", job.name);
|
||||
let metrics_parent = match download_job_metrics(&job.name, parent) {
|
||||
Ok(metrics) => Some(metrics),
|
||||
Err(error) => {
|
||||
eprintln!(
|
||||
r#"Did not find metrics for job `{}` at `{parent}`: {error:?}.
|
||||
Maybe it was newly added?"#,
|
||||
job.name
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
let metrics_current = download_job_metrics(&job.name, current)?;
|
||||
jobs.insert(
|
||||
job.name.clone(),
|
||||
JobMetrics { parent: metrics_parent, current: metrics_current },
|
||||
);
|
||||
}
|
||||
Ok(jobs)
|
||||
}
|
||||
|
||||
pub fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result<JsonRoot> {
|
||||
let url = get_metrics_url(job_name, sha);
|
||||
let mut response = ureq::get(&url).call()?;
|
||||
if !response.status().is_success() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Cannot fetch metrics from {url}: {}\n{}",
|
||||
response.status(),
|
||||
response.body_mut().read_to_string()?
|
||||
));
|
||||
}
|
||||
let data: JsonRoot = response
|
||||
.body_mut()
|
||||
.read_json()
|
||||
.with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn get_metrics_url(job_name: &str, sha: &str) -> String {
|
||||
let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" };
|
||||
format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json")
|
||||
}
|
||||
|
|
|
@ -9,3 +9,23 @@ pub fn load_env_var(name: &str) -> anyhow::Result<String> {
|
|||
pub fn read_to_string<P: AsRef<Path>>(path: P) -> anyhow::Result<String> {
|
||||
std::fs::read_to_string(&path).with_context(|| format!("Cannot read file {:?}", path.as_ref()))
|
||||
}
|
||||
|
||||
pub fn pluralize(text: &str, count: usize) -> String {
|
||||
if count == 1 { text.to_string() } else { format!("{text}s") }
|
||||
}
|
||||
|
||||
/// Outputs a HTML <details> section with the provided summary.
|
||||
/// Output printed by `func` will be contained within the section.
|
||||
pub fn output_details<F>(summary: &str, func: F)
|
||||
where
|
||||
F: FnOnce(),
|
||||
{
|
||||
println!(
|
||||
r"<details>
|
||||
<summary>{summary}</summary>
|
||||
|
||||
"
|
||||
);
|
||||
func();
|
||||
println!("</details>\n");
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ fn auto_jobs() {
|
|||
#[test]
|
||||
fn try_jobs() {
|
||||
let stdout = get_matrix("push", "commit", "refs/heads/try");
|
||||
insta::assert_snapshot!(stdout, @r#"
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
jobs=[{"name":"dist-x86_64-linux","full_name":"try - dist-x86_64-linux","os":"ubuntu-22.04-16core-64gb","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1}}]
|
||||
run_type=try
|
||||
"#);
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -30,10 +30,10 @@ try-job: aarch64-gnu
|
|||
try-job: dist-i686-msvc"#,
|
||||
"refs/heads/try",
|
||||
);
|
||||
insta::assert_snapshot!(stdout, @r#"
|
||||
jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"DIST_TRY_BUILD":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}]
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}]
|
||||
run_type=try
|
||||
"#);
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -53,13 +53,6 @@ envs:
|
|||
|
||||
try:
|
||||
<<: *production
|
||||
# The following env var activates faster `try` builds in `opt-dist` by, e.g.
|
||||
# - building only the more commonly useful components (we rarely need e.g. rust-docs in try
|
||||
# builds)
|
||||
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
|
||||
#
|
||||
# If you *want* these to happen however, temporarily comment it before triggering a try build.
|
||||
DIST_TRY_BUILD: 1
|
||||
|
||||
auto:
|
||||
<<: *production
|
||||
|
|
|
@ -82,15 +82,13 @@ envs:
|
|||
AWS_REGION: us-west-1
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
|
||||
# Try builds started through `@bors try` (without specifying custom jobs
|
||||
# in the PR description) will be passed the `DIST_TRY_BUILD` environment
|
||||
# variable by citool.
|
||||
# This tells the `opt-dist` tool to skip building certain components
|
||||
# and skip running tests, so that the try build finishes faster.
|
||||
try:
|
||||
<<: *production
|
||||
# The following env var activates faster `try` builds in `opt-dist` by, e.g.
|
||||
# - building only the more commonly useful components (we rarely need e.g. rust-docs in try
|
||||
# builds)
|
||||
# - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain
|
||||
#
|
||||
# If you *want* these to happen however, temporarily comment it before triggering a try build.
|
||||
DIST_TRY_BUILD: 1
|
||||
|
||||
auto:
|
||||
<<: *production
|
||||
|
|
|
@ -180,6 +180,8 @@ their results can be seen [here](https://github.com/rust-lang-ci/rust/actions),
|
|||
although usually you will be notified of the result by a comment made by bors on
|
||||
the corresponding PR.
|
||||
|
||||
Note that if you start the default try job using `@bors try`, it will skip building several `dist` components and running post-optimization tests, to make the build duration shorter. If you want to execute the full build as it would happen before a merge, add an explicit `try-job` pattern with the name of the default try job (currently `dist-x86_64-linux`).
|
||||
|
||||
Multiple try builds can execute concurrently across different PRs.
|
||||
|
||||
<div class="warning">
|
||||
|
|
|
@ -125,7 +125,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
|
|||
items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
|
||||
// Now we actually lower the imports, skipping everything else.
|
||||
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
|
||||
let name = renamed.unwrap_or_else(|| cx.tcx.hir_name(item.hir_id()));
|
||||
let name = renamed.unwrap_or(kw::Empty); // using kw::Empty is a bit of a hack
|
||||
clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
|
||||
} else {
|
||||
// skip everything else
|
||||
|
@ -1629,8 +1629,7 @@ fn first_non_private<'tcx>(
|
|||
if let Some(use_def_id) = reexp.id()
|
||||
&& let Some(local_use_def_id) = use_def_id.as_local()
|
||||
&& let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_use_def_id)
|
||||
&& !item.ident.name.is_empty()
|
||||
&& let hir::ItemKind::Use(path, _) = item.kind
|
||||
&& let hir::ItemKind::Use(path, hir::UseKind::Single(_)) = item.kind
|
||||
{
|
||||
for res in &path.res {
|
||||
if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
|
||||
|
@ -1775,7 +1774,7 @@ fn maybe_expand_private_type_alias<'tcx>(
|
|||
} else {
|
||||
return None;
|
||||
};
|
||||
let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
|
||||
let hir::ItemKind::TyAlias(_, ty, generics) = alias else { return None };
|
||||
|
||||
let final_seg = &path.segments.last().expect("segments were empty");
|
||||
let mut args = DefIdMap::default();
|
||||
|
@ -2794,20 +2793,24 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
use hir::ItemKind;
|
||||
|
||||
let def_id = item.owner_id.to_def_id();
|
||||
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir_name(item.hir_id()));
|
||||
let mut name = renamed.unwrap_or_else(|| {
|
||||
// FIXME: using kw::Empty is a bit of a hack
|
||||
cx.tcx.hir_opt_name(item.hir_id()).unwrap_or(kw::Empty)
|
||||
});
|
||||
|
||||
cx.with_param_env(def_id, |cx| {
|
||||
let kind = match item.kind {
|
||||
ItemKind::Static(ty, mutability, body_id) => StaticItem(Static {
|
||||
ItemKind::Static(_, ty, mutability, body_id) => StaticItem(Static {
|
||||
type_: Box::new(clean_ty(ty, cx)),
|
||||
mutability,
|
||||
expr: Some(body_id),
|
||||
}),
|
||||
ItemKind::Const(ty, generics, body_id) => ConstantItem(Box::new(Constant {
|
||||
ItemKind::Const(_, ty, generics, body_id) => ConstantItem(Box::new(Constant {
|
||||
generics: clean_generics(generics, cx),
|
||||
type_: clean_ty(ty, cx),
|
||||
kind: ConstantKind::Local { body: body_id, def_id },
|
||||
})),
|
||||
ItemKind::TyAlias(hir_ty, generics) => {
|
||||
ItemKind::TyAlias(_, hir_ty, generics) => {
|
||||
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
|
||||
let rustdoc_ty = clean_ty(hir_ty, cx);
|
||||
let type_ =
|
||||
|
@ -2840,34 +2843,34 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
));
|
||||
return ret;
|
||||
}
|
||||
ItemKind::Enum(ref def, generics) => EnumItem(Enum {
|
||||
ItemKind::Enum(_, ref def, generics) => EnumItem(Enum {
|
||||
variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
|
||||
generics: clean_generics(generics, cx),
|
||||
}),
|
||||
ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
|
||||
ItemKind::TraitAlias(_, generics, bounds) => TraitAliasItem(TraitAlias {
|
||||
generics: clean_generics(generics, cx),
|
||||
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
|
||||
}),
|
||||
ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
|
||||
ItemKind::Union(_, ref variant_data, generics) => UnionItem(Union {
|
||||
generics: clean_generics(generics, cx),
|
||||
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
|
||||
}),
|
||||
ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
|
||||
ItemKind::Struct(_, ref variant_data, generics) => StructItem(Struct {
|
||||
ctor_kind: variant_data.ctor_kind(),
|
||||
generics: clean_generics(generics, cx),
|
||||
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
|
||||
}),
|
||||
ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
|
||||
ItemKind::Macro(macro_def, MacroKind::Bang) => MacroItem(Macro {
|
||||
ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro {
|
||||
source: display_macro_source(cx, name, macro_def),
|
||||
macro_rules: macro_def.macro_rules,
|
||||
}),
|
||||
ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
|
||||
ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
|
||||
// proc macros can have a name set by attributes
|
||||
ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
|
||||
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
|
||||
}
|
||||
ItemKind::Trait(_, _, generics, bounds, item_ids) => {
|
||||
ItemKind::Trait(_, _, _, generics, bounds, item_ids) => {
|
||||
let items = item_ids
|
||||
.iter()
|
||||
.map(|ti| clean_trait_item(cx.tcx.hir_trait_item(ti.id), cx))
|
||||
|
@ -2880,7 +2883,7 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
|
||||
}))
|
||||
}
|
||||
ItemKind::ExternCrate(orig_name) => {
|
||||
ItemKind::ExternCrate(orig_name, _) => {
|
||||
return clean_extern_crate(item, name, orig_name, cx);
|
||||
}
|
||||
ItemKind::Use(path, kind) => {
|
||||
|
|
|
@ -4,8 +4,8 @@ use rustc_ast_pretty::pprust::PrintState;
|
|||
use rustc_ast_pretty::pprust::state::State as Printer;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw};
|
||||
use rustc_span::{FileName, Span};
|
||||
|
||||
/// Render a macro matcher in a format suitable for displaying to the user
|
||||
/// as part of an item declaration.
|
||||
|
@ -63,7 +63,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
|
|||
|
||||
// Create a Parser.
|
||||
let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec());
|
||||
let file_name = source_map.span_to_filename(span);
|
||||
let file_name = FileName::macro_expansion_source_code(&snippet);
|
||||
let mut parser =
|
||||
match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) {
|
||||
Ok(parser) => parser,
|
||||
|
|
|
@ -226,7 +226,7 @@ impl ExternalCrate {
|
|||
.filter_map(|&id| {
|
||||
let item = tcx.hir_item(id);
|
||||
match item.kind {
|
||||
hir::ItemKind::Mod(_) => {
|
||||
hir::ItemKind::Mod(..) => {
|
||||
as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
|
||||
}
|
||||
_ => None,
|
||||
|
@ -282,7 +282,7 @@ impl ExternalCrate {
|
|||
.filter_map(|&id| {
|
||||
let item = tcx.hir_item(id);
|
||||
match item.kind {
|
||||
hir::ItemKind::Mod(_) => {
|
||||
hir::ItemKind::Mod(..) => {
|
||||
as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
|
||||
}
|
||||
_ => None,
|
||||
|
|
|
@ -80,7 +80,7 @@ impl<'tcx> HirCollector<'tcx> {
|
|||
|
||||
pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> {
|
||||
let tcx = self.tcx;
|
||||
self.visit_testable("".to_string(), CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| {
|
||||
self.visit_testable(None, CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| {
|
||||
tcx.hir_walk_toplevel_module(this)
|
||||
});
|
||||
self.collector.tests
|
||||
|
@ -90,7 +90,7 @@ impl<'tcx> HirCollector<'tcx> {
|
|||
impl HirCollector<'_> {
|
||||
fn visit_testable<F: FnOnce(&mut Self)>(
|
||||
&mut self,
|
||||
name: String,
|
||||
name: Option<String>,
|
||||
def_id: LocalDefId,
|
||||
sp: Span,
|
||||
nested: F,
|
||||
|
@ -103,9 +103,10 @@ impl HirCollector<'_> {
|
|||
return;
|
||||
}
|
||||
|
||||
let has_name = !name.is_empty();
|
||||
if has_name {
|
||||
let mut has_name = false;
|
||||
if let Some(name) = name {
|
||||
self.collector.cur_path.push(name);
|
||||
has_name = true;
|
||||
}
|
||||
|
||||
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
|
||||
|
@ -153,9 +154,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
|
|||
fn visit_item(&mut self, item: &'tcx hir::Item<'_>) {
|
||||
let name = match &item.kind {
|
||||
hir::ItemKind::Impl(impl_) => {
|
||||
rustc_hir_pretty::id_to_string(&self.tcx, impl_.self_ty.hir_id)
|
||||
Some(rustc_hir_pretty::id_to_string(&self.tcx, impl_.self_ty.hir_id))
|
||||
}
|
||||
_ => item.ident.to_string(),
|
||||
_ => item.kind.ident().map(|ident| ident.to_string()),
|
||||
};
|
||||
|
||||
self.visit_testable(name, item.owner_id.def_id, item.span, |this| {
|
||||
|
@ -164,31 +165,46 @@ impl<'tcx> intravisit::Visitor<'tcx> for HirCollector<'tcx> {
|
|||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'_>) {
|
||||
self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
|
||||
intravisit::walk_trait_item(this, item);
|
||||
});
|
||||
self.visit_testable(
|
||||
Some(item.ident.to_string()),
|
||||
item.owner_id.def_id,
|
||||
item.span,
|
||||
|this| {
|
||||
intravisit::walk_trait_item(this, item);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'_>) {
|
||||
self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
|
||||
intravisit::walk_impl_item(this, item);
|
||||
});
|
||||
self.visit_testable(
|
||||
Some(item.ident.to_string()),
|
||||
item.owner_id.def_id,
|
||||
item.span,
|
||||
|this| {
|
||||
intravisit::walk_impl_item(this, item);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'_>) {
|
||||
self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
|
||||
intravisit::walk_foreign_item(this, item);
|
||||
});
|
||||
self.visit_testable(
|
||||
Some(item.ident.to_string()),
|
||||
item.owner_id.def_id,
|
||||
item.span,
|
||||
|this| {
|
||||
intravisit::walk_foreign_item(this, item);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'tcx hir::Variant<'_>) {
|
||||
self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| {
|
||||
self.visit_testable(Some(v.ident.to_string()), v.def_id, v.span, |this| {
|
||||
intravisit::walk_variant(this, v);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_field_def(&mut self, f: &'tcx hir::FieldDef<'_>) {
|
||||
self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| {
|
||||
self.visit_testable(Some(f.ident.to_string()), f.def_id, f.span, |this| {
|
||||
intravisit::walk_field_def(this, f);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -242,10 +242,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
|||
// Now that we confirmed it's a file import, we want to get the span for the module
|
||||
// name only and not all the "mod foo;".
|
||||
if let Node::Item(item) = self.tcx.hir_node(id) {
|
||||
self.matches.insert(
|
||||
item.ident.span,
|
||||
LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
|
||||
);
|
||||
let (ident, _) = item.expect_mod();
|
||||
self.matches
|
||||
.insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)));
|
||||
}
|
||||
} else {
|
||||
// If it's a "mod foo {}", we want to look to its documentation page.
|
||||
|
@ -273,22 +272,22 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
|||
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
||||
match item.kind {
|
||||
ItemKind::Static(..)
|
||||
| ItemKind::Const(_, _, _)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::Fn { .. }
|
||||
| ItemKind::Macro(_, _)
|
||||
| ItemKind::TyAlias(_, _)
|
||||
| ItemKind::Enum(_, _)
|
||||
| ItemKind::Struct(_, _)
|
||||
| ItemKind::Union(_, _)
|
||||
| ItemKind::Trait(_, _, _, _, _)
|
||||
| ItemKind::TraitAlias(_, _) => self.extract_info_from_hir_id(item.hir_id()),
|
||||
| ItemKind::Macro(..)
|
||||
| ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..)
|
||||
| ItemKind::Trait(..)
|
||||
| ItemKind::TraitAlias(..) => self.extract_info_from_hir_id(item.hir_id()),
|
||||
ItemKind::Impl(_)
|
||||
| ItemKind::Use(_, _)
|
||||
| ItemKind::ExternCrate(_)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::ExternCrate(..)
|
||||
| ItemKind::ForeignMod { .. }
|
||||
| ItemKind::GlobalAsm { .. }
|
||||
// We already have "visit_mod" above so no need to check it here.
|
||||
| ItemKind::Mod(_) => {}
|
||||
| ItemKind::Mod(..) => {}
|
||||
}
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
|
|||
data: hir::VariantData::Tuple(_, _, _),
|
||||
..
|
||||
}) | hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(hir::VariantData::Tuple(_, _, _), _),
|
||||
kind: hir::ItemKind::Struct(_, hir::VariantData::Tuple(_, _, _), _),
|
||||
..
|
||||
})
|
||||
)
|
||||
|
|
|
@ -144,9 +144,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
&& inserted.insert(def_id)
|
||||
{
|
||||
let item = self.cx.tcx.hir_expect_item(local_def_id);
|
||||
top_level_module
|
||||
.items
|
||||
.insert((local_def_id, Some(item.ident.name)), (item, None, None));
|
||||
let (ident, _, _) = item.expect_macro();
|
||||
top_level_module.items.insert((local_def_id, Some(ident.name)), (item, None, None));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,11 +223,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
def_id: LocalDefId,
|
||||
res: Res,
|
||||
renamed: Option<Symbol>,
|
||||
glob: bool,
|
||||
please_inline: bool,
|
||||
) -> bool {
|
||||
debug!("maybe_inline_local (renamed: {renamed:?}) res: {res:?}");
|
||||
|
||||
let glob = renamed.is_none();
|
||||
if renamed == Some(kw::Underscore) {
|
||||
// We never inline `_` reexports.
|
||||
return false;
|
||||
|
@ -286,7 +285,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
is_hidden &&
|
||||
// If it's a doc hidden module, we need to keep it in case some of its inner items
|
||||
// are re-exported.
|
||||
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. }))
|
||||
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(..), .. }))
|
||||
) ||
|
||||
// The imported item is public and not `doc(hidden)` so no need to inline it.
|
||||
self.reexport_public_and_not_hidden(def_id, res_did)
|
||||
|
@ -297,7 +296,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
|
||||
let is_bang_macro = matches!(
|
||||
item,
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, MacroKind::Bang), .. })
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, MacroKind::Bang), .. })
|
||||
);
|
||||
|
||||
if !self.view_item_stack.insert(res_did) && !is_bang_macro {
|
||||
|
@ -311,7 +310,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
Node::Item(_) if is_bang_macro && !please_inline && renamed.is_some() && is_hidden => {
|
||||
return false;
|
||||
}
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Mod(m), .. }) if glob => {
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_, m), .. }) if glob => {
|
||||
let prev = mem::replace(&mut self.inlining, true);
|
||||
for &i in m.item_ids {
|
||||
let i = tcx.hir_item(i);
|
||||
|
@ -378,7 +377,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
// attribute can still be visible.
|
||||
|| match item.kind {
|
||||
hir::ItemKind::Impl(..) => true,
|
||||
hir::ItemKind::Macro(_, MacroKind::Bang) => {
|
||||
hir::ItemKind::Macro(_, _, MacroKind::Bang) => {
|
||||
self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
|
||||
}
|
||||
_ => false,
|
||||
|
@ -419,7 +418,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
}
|
||||
return;
|
||||
}
|
||||
let name = renamed.unwrap_or(item.ident.name);
|
||||
let get_name = || renamed.unwrap_or(item.kind.ident().unwrap().name);
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
let def_id = item.owner_id.to_def_id();
|
||||
|
@ -459,15 +458,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
}
|
||||
_ => false,
|
||||
});
|
||||
let is_glob = kind == hir::UseKind::Glob;
|
||||
let ident = if is_glob { None } else { Some(name) };
|
||||
if self.maybe_inline_local(
|
||||
item.owner_id.def_id,
|
||||
res,
|
||||
ident,
|
||||
is_glob,
|
||||
please_inline,
|
||||
) {
|
||||
let ident = match kind {
|
||||
hir::UseKind::Single(ident) => Some(renamed.unwrap_or(ident.name)),
|
||||
hir::UseKind::Glob => None,
|
||||
hir::UseKind::ListStem => unreachable!(),
|
||||
};
|
||||
if self.maybe_inline_local(item.owner_id.def_id, res, ident, please_inline)
|
||||
{
|
||||
debug!("Inlining {:?}", item.owner_id.def_id);
|
||||
continue;
|
||||
}
|
||||
|
@ -475,7 +472,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
self.add_to_current_mod(item, renamed, import_id);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Macro(macro_def, _) => {
|
||||
hir::ItemKind::Macro(_, macro_def, _) => {
|
||||
// `#[macro_export] macro_rules!` items are handled separately in `visit()`,
|
||||
// above, since they need to be documented at the module top level. Accordingly,
|
||||
// we only want to handle macros if one of three conditions holds:
|
||||
|
@ -495,8 +492,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
self.add_to_current_mod(item, renamed, import_id);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Mod(m) => {
|
||||
self.enter_mod(item.owner_id.def_id, m, name, renamed, import_id);
|
||||
hir::ItemKind::Mod(_, m) => {
|
||||
self.enter_mod(item.owner_id.def_id, m, get_name(), renamed, import_id);
|
||||
}
|
||||
hir::ItemKind::Fn { .. }
|
||||
| hir::ItemKind::ExternCrate(..)
|
||||
|
@ -512,7 +509,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
hir::ItemKind::Const(..) => {
|
||||
// Underscore constants do not correspond to a nameable item and
|
||||
// so are never useful in documentation.
|
||||
if name != kw::Underscore {
|
||||
if get_name() != kw::Underscore {
|
||||
self.add_to_current_mod(item, renamed, import_id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use clippy_config::types::{
|
|||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use rustc_hir::{
|
||||
AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, UseKind,
|
||||
AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind,
|
||||
Variant, VariantData,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
@ -178,8 +178,8 @@ impl ArbitrarySourceItemOrdering {
|
|||
/// Produces a linting warning for incorrectly ordered item members.
|
||||
fn lint_member_name<T: LintContext>(
|
||||
cx: &T,
|
||||
ident: &rustc_span::symbol::Ident,
|
||||
before_ident: &rustc_span::symbol::Ident,
|
||||
ident: &rustc_span::Ident,
|
||||
before_ident: &rustc_span::Ident,
|
||||
) {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
|
@ -192,21 +192,21 @@ impl ArbitrarySourceItemOrdering {
|
|||
}
|
||||
|
||||
fn lint_member_item<T: LintContext>(cx: &T, item: &Item<'_>, before_item: &Item<'_>) {
|
||||
let span = if item.ident.as_str().is_empty() {
|
||||
&item.span
|
||||
let span = if let Some(ident) = item.kind.ident() {
|
||||
ident.span
|
||||
} else {
|
||||
&item.ident.span
|
||||
item.span
|
||||
};
|
||||
|
||||
let (before_span, note) = if before_item.ident.as_str().is_empty() {
|
||||
let (before_span, note) = if let Some(ident) = before_item.kind.ident() {
|
||||
(
|
||||
&before_item.span,
|
||||
"should be placed before the following item".to_owned(),
|
||||
ident.span,
|
||||
format!("should be placed before `{}`", ident.as_str(),),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
&before_item.ident.span,
|
||||
format!("should be placed before `{}`", before_item.ident.as_str(),),
|
||||
before_item.span,
|
||||
"should be placed before the following item".to_owned(),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -218,9 +218,9 @@ impl ArbitrarySourceItemOrdering {
|
|||
span_lint_and_note(
|
||||
cx,
|
||||
ARBITRARY_SOURCE_ITEM_ORDERING,
|
||||
*span,
|
||||
span,
|
||||
"incorrect ordering of items (must be alphabetically ordered)",
|
||||
Some(*before_span),
|
||||
Some(before_span),
|
||||
note,
|
||||
);
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ impl ArbitrarySourceItemOrdering {
|
|||
impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
match &item.kind {
|
||||
ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => {
|
||||
ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => {
|
||||
let mut cur_v: Option<&Variant<'_>> = None;
|
||||
for variant in enum_def.variants {
|
||||
if variant.span.in_external_macro(cx.sess().source_map()) {
|
||||
|
@ -259,7 +259,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
|
|||
cur_v = Some(variant);
|
||||
}
|
||||
},
|
||||
ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
|
||||
ItemKind::Struct(_, VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
|
||||
let mut cur_f: Option<&FieldDef<'_>> = None;
|
||||
for field in *fields {
|
||||
if field.span.in_external_macro(cx.sess().source_map()) {
|
||||
|
@ -274,7 +274,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
|
|||
cur_f = Some(field);
|
||||
}
|
||||
},
|
||||
ItemKind::Trait(is_auto, _safety, _generics, _generic_bounds, item_ref)
|
||||
ItemKind::Trait(is_auto, _safety, _ident, _generics, _generic_bounds, item_ref)
|
||||
if self.enable_ordering_for_trait && *is_auto == IsAuto::No =>
|
||||
{
|
||||
let mut cur_t: Option<&TraitItemRef> = None;
|
||||
|
@ -351,50 +351,24 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
|
|||
continue;
|
||||
}
|
||||
|
||||
// The following exceptions (skipping with `continue;`) may not be
|
||||
// complete, edge cases have not been explored further than what
|
||||
// appears in the existing code base.
|
||||
if item.ident.name == rustc_span::symbol::kw::Empty {
|
||||
if let ItemKind::Impl(_) = item.kind {
|
||||
// Sorting trait impls for unnamed types makes no sense.
|
||||
if get_item_name(item).is_empty() {
|
||||
continue;
|
||||
}
|
||||
} else if let ItemKind::ForeignMod { .. } = item.kind {
|
||||
continue;
|
||||
} else if let ItemKind::GlobalAsm { .. } = item.kind {
|
||||
continue;
|
||||
} else if let ItemKind::Use(path, use_kind) = item.kind {
|
||||
if path.segments.is_empty() {
|
||||
// Use statements that contain braces get caught here.
|
||||
// They will still be linted internally.
|
||||
continue;
|
||||
} else if path.segments.len() >= 2
|
||||
&& (path.segments[0].ident.name == rustc_span::sym::std
|
||||
|| path.segments[0].ident.name == rustc_span::sym::core)
|
||||
&& path.segments[1].ident.name == rustc_span::sym::prelude
|
||||
{
|
||||
// Filters the autogenerated prelude use statement.
|
||||
// e.g. `use std::prelude::rustc_2021`
|
||||
} else if use_kind == UseKind::Glob {
|
||||
// Filters glob kinds of uses.
|
||||
// e.g. `use std::sync::*`
|
||||
} else {
|
||||
// This can be used for debugging.
|
||||
// println!("Unknown autogenerated use statement: {:?}", item);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let ident = if let Some(ident) = item.kind.ident() {
|
||||
ident
|
||||
} else if let ItemKind::Impl(_) = item.kind
|
||||
&& !get_item_name(item).is_empty()
|
||||
{
|
||||
rustc_span::Ident::empty() // FIXME: a bit strange, is there a better way to do it?
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if item.ident.name.as_str().starts_with('_') {
|
||||
if ident.name.as_str().starts_with('_') {
|
||||
// Filters out unnamed macro-like impls for various derives,
|
||||
// e.g. serde::Serialize or num_derive::FromPrimitive.
|
||||
continue;
|
||||
}
|
||||
|
||||
if item.ident.name == rustc_span::sym::std && item.span.is_dummy() {
|
||||
if let ItemKind::ExternCrate(None) = item.kind {
|
||||
if ident.name == rustc_span::sym::std && item.span.is_dummy() {
|
||||
if let ItemKind::ExternCrate(None, _) = item.kind {
|
||||
// Filters the auto-included Rust standard library.
|
||||
continue;
|
||||
}
|
||||
|
@ -525,6 +499,8 @@ fn get_item_name(item: &Item<'_>) -> String {
|
|||
String::new()
|
||||
}
|
||||
},
|
||||
_ => item.ident.name.as_str().to_owned(),
|
||||
// FIXME: `Ident::empty` for anonymous items is a bit strange, is there
|
||||
// a better way to do it?
|
||||
_ => item.kind.ident().unwrap_or(rustc_span::Ident::empty()).name.as_str().to_owned(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ mod utils;
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::msrvs::{self, Msrv, MsrvStack};
|
||||
use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
|
||||
use rustc_hir::{ImplItem, Item, TraitItem};
|
||||
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::sym;
|
||||
|
@ -466,8 +466,8 @@ impl Attributes {
|
|||
impl<'tcx> LateLintPass<'tcx> for Attributes {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
let attrs = cx.tcx.hir_attrs(item.hir_id());
|
||||
if is_relevant_item(cx, item) {
|
||||
inline_always::check(cx, item.span, item.ident.name, attrs);
|
||||
if let ItemKind::Fn { ident, .. } = item.kind && is_relevant_item(cx, item) {
|
||||
inline_always::check(cx, item.span, ident.name, attrs);
|
||||
}
|
||||
repr_attributes::check(cx, item.span, attrs, self.msrv);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
|
|||
if let ItemKind::Fn { body: eid, .. } = item.kind {
|
||||
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir_body(eid).value)
|
||||
} else {
|
||||
true
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
|
||||
if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
|
||||
for res in &path.res {
|
||||
self.check_res_emit(cx, res, item.span);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
|||
if cx.tcx.data_layout.pointer_size.bits() != 64 {
|
||||
return;
|
||||
}
|
||||
if let ItemKind::Enum(def, _) = &item.kind {
|
||||
if let ItemKind::Enum(_, def, _) = &item.kind {
|
||||
for var in def.variants {
|
||||
if let Some(anon_const) = &var.disr_expr {
|
||||
let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body);
|
||||
|
|
|
@ -37,8 +37,8 @@ declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
|
|||
impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
match item.kind {
|
||||
ItemKind::TyAlias(..)
|
||||
if item.ident.name == sym::Error
|
||||
ItemKind::TyAlias(ident, ..)
|
||||
if ident.name == sym::Error
|
||||
&& is_visible_outside_module(cx, item.owner_id.def_id)
|
||||
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
|
||||
|
@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
|
|||
span_lint(
|
||||
cx,
|
||||
ERROR_IMPL_ERROR,
|
||||
item.ident.span,
|
||||
ident.span,
|
||||
"exported type alias named `Error` that implements `Error`",
|
||||
);
|
||||
},
|
||||
|
|
|
@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
}
|
||||
|
||||
// find `self` ty for this trait if relevant
|
||||
if let ItemKind::Trait(_, _, _, _, items) = item.kind {
|
||||
if let ItemKind::Trait(_, _, _, _, _, items) = item.kind {
|
||||
for trait_item in items {
|
||||
if trait_item.id.owner_id.def_id == fn_def_id {
|
||||
// be sure we have `self` parameter in this function
|
||||
|
|
|
@ -122,7 +122,7 @@ fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Struct(variant_data, _) = &item.kind
|
||||
if let ItemKind::Struct(_, variant_data, _) = &item.kind
|
||||
&& variant_data.fields().len() as u64 > self.max_struct_bools
|
||||
&& has_n_bools(
|
||||
variant_data.fields().iter().map(|field| field.ty),
|
||||
|
|
|
@ -76,7 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
|
|||
"exported enums should not be exhaustive",
|
||||
[].as_slice(),
|
||||
),
|
||||
ItemKind::Struct(v, ..) => (
|
||||
ItemKind::Struct(_, v, ..) => (
|
||||
EXHAUSTIVE_STRUCTS,
|
||||
"exported structs should not be exhaustive",
|
||||
v.fields(),
|
||||
|
|
|
@ -103,7 +103,7 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty
|
|||
.did()
|
||||
.as_local()
|
||||
&& let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id)
|
||||
&& let hir::ItemKind::Enum(ref def, _) = item.kind
|
||||
&& let hir::ItemKind::Enum(_, ref def, _) = item.kind
|
||||
{
|
||||
let variants_size = AdtVariantInfo::new(cx, *adt, subst);
|
||||
if let Some((first_variant, variants)) = variants_size.split_first()
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Ident, Span};
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -196,16 +196,16 @@ fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
|
|||
prefixes.iter().all(|p| p == &"" || p == &"_")
|
||||
}
|
||||
|
||||
fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) {
|
||||
fn check_fields(cx: &LateContext<'_>, threshold: u64, ident: Ident, span: Span, fields: &[FieldDef<'_>]) {
|
||||
if (fields.len() as u64) < threshold {
|
||||
return;
|
||||
}
|
||||
|
||||
check_struct_name_repetition(cx, item, fields);
|
||||
check_struct_name_repetition(cx, ident, fields);
|
||||
|
||||
// if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
|
||||
// this prevents linting in macros in which the location of the field identifier names differ
|
||||
if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) {
|
||||
if !fields.iter().all(|field| ident.span.eq_ctxt(field.ident.span)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
|
|||
span_lint_and_help(
|
||||
cx,
|
||||
STRUCT_FIELD_NAMES,
|
||||
item.span,
|
||||
span,
|
||||
format!("all fields have the same {what}fix: `{value}`"),
|
||||
None,
|
||||
format!("remove the {what}fixes"),
|
||||
|
@ -264,11 +264,11 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
|
|||
}
|
||||
}
|
||||
|
||||
fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
|
||||
let snake_name = to_snake_case(item.ident.name.as_str());
|
||||
fn check_struct_name_repetition(cx: &LateContext<'_>, ident: Ident, fields: &[FieldDef<'_>]) {
|
||||
let snake_name = to_snake_case(ident.name.as_str());
|
||||
let item_name_words: Vec<&str> = snake_name.split('_').collect();
|
||||
for field in fields {
|
||||
if field.ident.span.eq_ctxt(item.ident.span) {
|
||||
if field.ident.span.eq_ctxt(ident.span) {
|
||||
//consider linting only if the field identifier has the same SyntaxContext as the item(struct)
|
||||
let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect();
|
||||
if field_words.len() >= item_name_words.len() {
|
||||
|
@ -397,19 +397,23 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
|
|||
}
|
||||
|
||||
impl LateLintPass<'_> for ItemNameRepetitions {
|
||||
fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
|
||||
fn check_item_post(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
let Some(_ident) = item.kind.ident() else { return };
|
||||
|
||||
let last = self.modules.pop();
|
||||
assert!(last.is_some());
|
||||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
let item_name = item.ident.name.as_str();
|
||||
let Some(ident) = item.kind.ident() else { return };
|
||||
|
||||
let item_name = ident.name.as_str();
|
||||
let item_camel = to_camel_case(item_name);
|
||||
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
|
||||
if let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules {
|
||||
// constants don't have surrounding modules
|
||||
if !mod_camel.is_empty() {
|
||||
if mod_name == &item.ident.name
|
||||
if mod_name == &ident.name
|
||||
&& let ItemKind::Mod(..) = item.kind
|
||||
&& (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public())
|
||||
{
|
||||
|
@ -438,7 +442,7 @@ impl LateLintPass<'_> for ItemNameRepetitions {
|
|||
Some(c) if is_word_beginning(c) => span_lint(
|
||||
cx,
|
||||
MODULE_NAME_REPETITIONS,
|
||||
item.ident.span,
|
||||
ident.span,
|
||||
"item name starts with its containing module's name",
|
||||
),
|
||||
_ => (),
|
||||
|
@ -450,7 +454,7 @@ impl LateLintPass<'_> for ItemNameRepetitions {
|
|||
span_lint(
|
||||
cx,
|
||||
MODULE_NAME_REPETITIONS,
|
||||
item.ident.span,
|
||||
ident.span,
|
||||
"item name ends with its containing module's name",
|
||||
);
|
||||
}
|
||||
|
@ -462,13 +466,13 @@ impl LateLintPass<'_> for ItemNameRepetitions {
|
|||
&& span_is_local(item.span)
|
||||
{
|
||||
match item.kind {
|
||||
ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
|
||||
ItemKind::Struct(VariantData::Struct { fields, .. }, _) => {
|
||||
check_fields(cx, self.struct_threshold, item, fields);
|
||||
ItemKind::Enum(_, def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
|
||||
ItemKind::Struct(_, VariantData::Struct { fields, .. }, _) => {
|
||||
check_fields(cx, self.struct_threshold, ident, item.span, fields);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
self.modules.push((item.ident.name, item_camel, item.owner_id));
|
||||
self.modules.push((ident.name, item_camel, item.owner_id));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ declare_clippy_lint! {
|
|||
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]);
|
||||
|
||||
fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
|
||||
if let ItemKind::Mod(test_mod) = item.kind
|
||||
if let ItemKind::Mod(_, test_mod) = item.kind
|
||||
&& item.span.hi() == test_mod.spans.inner_span.hi()
|
||||
&& is_cfg_test(cx.tcx, item.hir_id())
|
||||
&& !item.span.from_expansion()
|
||||
|
@ -67,14 +67,20 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
|
|||
let after: Vec<_> = items
|
||||
.filter(|item| {
|
||||
// Ignore the generated test main function
|
||||
!(item.ident.name == sym::main
|
||||
&& item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness))
|
||||
if let ItemKind::Fn { ident, .. } = item.kind
|
||||
&& ident.name == sym::main
|
||||
&& item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness)
|
||||
{
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Some(last) = after.last()
|
||||
&& after.iter().all(|&item| {
|
||||
!matches!(item.kind, ItemKind::Mod(_)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item)
|
||||
!matches!(item.kind, ItemKind::Mod(..)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item)
|
||||
})
|
||||
&& !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id()))
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Const(_, generics, _) = &item.kind
|
||||
if let ItemKind::Const(ident, _, generics, _) = &item.kind
|
||||
// Since static items may not have generics, skip generic const items.
|
||||
// FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
|
||||
// doesn't account for empty where-clauses that only consist of keyword `where` IINM.
|
||||
|
@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
|||
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
|
||||
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
|
||||
{
|
||||
let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
|
||||
let hi_pos = ident.span.lo() - BytePos::from_usize(1);
|
||||
let sugg_span = Span::new(
|
||||
hi_pos - BytePos::from_usize("const".len()),
|
||||
hi_pos,
|
||||
|
|
|
@ -73,7 +73,7 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
|
||||
if let ItemKind::Enum(ref def, _) = item.kind
|
||||
if let ItemKind::Enum(ident, ref def, _) = item.kind
|
||||
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let ty::Adt(adt, subst) = ty.kind()
|
||||
&& adt.variants().len() > 1
|
||||
|
@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
|
|||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
if is_copy(cx, ty) || maybe_copy(cx, ty) {
|
||||
diag.span_note(
|
||||
item.ident.span,
|
||||
ident.span,
|
||||
"boxing a variant would require the type no longer be `Copy`",
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
|||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
// Integer modules are "TBD" deprecated, and the contents are too,
|
||||
// so lint on the `use` statement directly.
|
||||
if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
|
||||
if let ItemKind::Use(path, kind @ (UseKind::Single(_) | UseKind::Glob)) = item.kind
|
||||
&& !item.span.in_external_macro(cx.sess().source_map())
|
||||
&& let Some(def_id) = path.res[0].opt_def_id()
|
||||
&& self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
|
||||
|
@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
|||
"importing a legacy numeric constant"
|
||||
},
|
||||
|diag| {
|
||||
if item.ident.name == kw::Underscore {
|
||||
if let UseKind::Single(ident) = kind && ident.name == kw::Underscore {
|
||||
diag.help("remove this import");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
|||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use rustc_trait_selection::traits::supertrait_def_ids;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -123,10 +123,10 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for LenZero {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind
|
||||
if let ItemKind::Trait(_, _, ident, _, _, trait_items) = item.kind
|
||||
&& !item.span.from_expansion()
|
||||
{
|
||||
check_trait_items(cx, item, trait_items);
|
||||
check_trait_items(cx, item, ident, trait_items);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,10 +150,10 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
|||
let (name, kind) = match cx.tcx.hir_node(ty_hir_id) {
|
||||
Node::ForeignItem(x) => (x.ident.name, "extern type"),
|
||||
Node::Item(x) => match x.kind {
|
||||
ItemKind::Struct(..) => (x.ident.name, "struct"),
|
||||
ItemKind::Enum(..) => (x.ident.name, "enum"),
|
||||
ItemKind::Union(..) => (x.ident.name, "union"),
|
||||
_ => (x.ident.name, "type"),
|
||||
ItemKind::Struct(ident, ..) => (ident.name, "struct"),
|
||||
ItemKind::Enum(ident, ..) => (ident.name, "enum"),
|
||||
ItemKind::Union(ident, ..) => (ident.name, "union"),
|
||||
_ => (x.kind.ident().unwrap().name, "type"),
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
@ -250,7 +250,7 @@ fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items: &[TraitItemRef]) {
|
||||
fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Ident, trait_items: &[TraitItemRef]) {
|
||||
fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
|
||||
item.ident.name == name
|
||||
&& if let AssocItemKind::Fn { has_self } = item.kind {
|
||||
|
@ -300,7 +300,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
|
|||
visited_trait.span,
|
||||
format!(
|
||||
"trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
|
||||
visited_trait.ident.name
|
||||
ident.name
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
|
|||
}
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Enum(def, _) if def.variants.len() > 1 => {
|
||||
ItemKind::Enum(_, def, _) if def.variants.len() > 1 => {
|
||||
let iter = def.variants.iter().filter_map(|v| {
|
||||
(matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id)))
|
||||
.then_some((v.def_id, v.span))
|
||||
|
@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
|
|||
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
|
||||
}
|
||||
},
|
||||
ItemKind::Struct(variant_data, _) => {
|
||||
ItemKind::Struct(_, variant_data, _) => {
|
||||
let fields = variant_data.fields();
|
||||
let private_fields = fields
|
||||
.iter()
|
||||
|
|
|
@ -192,17 +192,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
|||
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
||||
match it.kind {
|
||||
hir::ItemKind::Fn { .. } => {
|
||||
hir::ItemKind::Fn { ident, .. } => {
|
||||
// ignore main()
|
||||
if it.ident.name == sym::main {
|
||||
if ident.name == sym::main {
|
||||
let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
|
||||
if at_root {
|
||||
note_prev_span_then_ret!(self.prev_span, it.span);
|
||||
}
|
||||
}
|
||||
},
|
||||
hir::ItemKind::Const(..) => {
|
||||
if it.ident.name == kw::Underscore {
|
||||
hir::ItemKind::Const(ident, ..) => {
|
||||
if ident.name == kw::Underscore {
|
||||
note_prev_span_then_ret!(self.prev_span, it.span);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -67,7 +67,7 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
|
|||
|
||||
impl LateLintPass<'_> for ImportRename {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
|
||||
if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
|
||||
for &res in &path.res {
|
||||
if let Res::Def(_, id) = res
|
||||
&& let Some(name) = self.renames.get(&id)
|
||||
|
|
|
@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
|
|||
&& should_lint(cx, typeck_results, block)
|
||||
{
|
||||
// we intentionally only lint structs, see lint description
|
||||
if let ItemKind::Struct(data, _) = &self_item.kind {
|
||||
if let ItemKind::Struct(_, data, _) = &self_item.kind {
|
||||
check_struct(cx, typeck_results, block, self_ty, item, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
|
|||
let attrs = cx.tcx.hir_attrs(it.hir_id());
|
||||
check_missing_inline_attrs(cx, attrs, it.span, desc);
|
||||
},
|
||||
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _generics, _bounds, trait_items) => {
|
||||
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => {
|
||||
// note: we need to check if the trait is exported so we can't use
|
||||
// `LateLintPass::check_trait_item` here.
|
||||
for tit in trait_items {
|
||||
|
|
|
@ -37,12 +37,12 @@ declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Fn { sig: fn_sig, .. } = &item.kind
|
||||
if let ItemKind::Fn { ident, sig: fn_sig, .. } = &item.kind
|
||||
&& !item.span.from_expansion()
|
||||
{
|
||||
let attrs = cx.tcx.hir_attrs(item.hir_id());
|
||||
let mut app = Applicability::MaybeIncorrect;
|
||||
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(item.ident.span.lo()), "..", &mut app);
|
||||
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app);
|
||||
for attr in attrs {
|
||||
if let Some(ident) = attr.ident()
|
||||
&& ident.name == rustc_span::sym::no_mangle
|
||||
|
|
|
@ -192,7 +192,7 @@ struct LazyInfo {
|
|||
impl LazyInfo {
|
||||
fn from_item(state: &NonStdLazyStatic, cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
|
||||
// Check if item is a `once_cell:sync::Lazy` static.
|
||||
if let ItemKind::Static(ty, _, body_id) = item.kind
|
||||
if let ItemKind::Static(_, ty, _, body_id) = item.kind
|
||||
&& let Some(path_def_id) = path_def_id(cx, ty)
|
||||
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
|
||||
&& state.once_cell_sync_lazy.contains(&path_def_id)
|
||||
|
|
|
@ -58,7 +58,7 @@ impl PubUnderscoreFields {
|
|||
impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
// This lint only pertains to structs.
|
||||
let ItemKind::Struct(variant_data, _) = &item.kind else {
|
||||
let ItemKind::Struct(_, variant_data, _) = &item.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
|
|||
&& is_not_macro_export(item)
|
||||
&& !item.span.in_external_macro(cx.sess().source_map())
|
||||
{
|
||||
let span = item.span.with_hi(item.ident.span.hi());
|
||||
// FIXME: `DUMMY_SP` isn't right here, because it causes the
|
||||
// resulting span to begin at the start of the file.
|
||||
let span = item.span.with_hi(
|
||||
item.kind.ident().map(|ident| ident.span.hi()).unwrap_or(rustc_span::DUMMY_SP.hi())
|
||||
);
|
||||
let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
|
@ -73,7 +73,8 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
|
|||
if let Some(self_def) = self_ty.ty_adt_def()
|
||||
&& let Some(self_local_did) = self_def.did().as_local()
|
||||
&& let Node::Item(x) = cx.tcx.hir_node_by_def_id(self_local_did)
|
||||
&& let type_name = x.ident.name.as_str().to_lowercase()
|
||||
&& let Some(type_ident) = x.kind.ident()
|
||||
&& let type_name = type_ident.name.as_str().to_lowercase()
|
||||
&& (impl_item.ident.name.as_str() == type_name
|
||||
|| impl_item.ident.name.as_str().replace('_', "") == type_name)
|
||||
{
|
||||
|
|
|
@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
|
|||
}
|
||||
|
||||
fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
|
||||
if let ItemKind::Struct(data, _) = &item.kind
|
||||
if let ItemKind::Struct(_, data, _) = &item.kind
|
||||
&& let Some(last_field) = data.fields().last()
|
||||
&& let field_ty = cx.tcx.normalize_erasing_regions(
|
||||
cx.typing_env(),
|
||||
|
|
|
@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
|
|||
// special handling for self trait bounds as these are not considered generics
|
||||
// ie. trait Foo: Display {}
|
||||
if let Item {
|
||||
kind: ItemKind::Trait(_, _, _, bounds, ..),
|
||||
kind: ItemKind::Trait(_, _, _, _, bounds, ..),
|
||||
..
|
||||
} = item
|
||||
{
|
||||
|
@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
|
|||
..
|
||||
}) = segments.first()
|
||||
&& let Some(Node::Item(Item {
|
||||
kind: ItemKind::Trait(_, _, _, self_bounds, _),
|
||||
kind: ItemKind::Trait(_, _, _, _, self_bounds, _),
|
||||
..
|
||||
})) = cx.tcx.hir_get_if_local(*def_id)
|
||||
{
|
||||
|
|
|
@ -451,7 +451,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
|||
let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
|
||||
ItemKind::Static(_, ty, _, _) | ItemKind::Const(_, ty, _, _) => self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
|
|
|
@ -454,7 +454,7 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
|
|||
let comment_start = match cx.tcx.parent_hir_node(item.hir_id()) {
|
||||
Node::Crate(parent_mod) => comment_start_before_item_in_mod(cx, parent_mod, parent_mod.spans.inner_span, item),
|
||||
Node::Item(parent_item) => {
|
||||
if let ItemKind::Mod(parent_mod) = &parent_item.kind {
|
||||
if let ItemKind::Mod(_, parent_mod) = &parent_item.kind {
|
||||
comment_start_before_item_in_mod(cx, parent_mod, parent_item.span, item)
|
||||
} else {
|
||||
// Doesn't support impls in this position. Pretend a comment was found.
|
||||
|
@ -614,7 +614,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
|
|||
..
|
||||
}) => maybe_global_var = true,
|
||||
Node::Item(hir::Item {
|
||||
kind: ItemKind::Mod(_),
|
||||
kind: ItemKind::Mod(..),
|
||||
span: item_span,
|
||||
..
|
||||
}) => {
|
||||
|
|
|
@ -130,9 +130,9 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
|
|||
}
|
||||
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
let ItemKind::Fn { sig, .. } = &item.kind else {
|
||||
let ItemKind::Fn { ident, sig, .. } = &item.kind else {
|
||||
return;
|
||||
};
|
||||
self.check_fn_item(cx, sig.decl, item.owner_id.def_id, item.ident.name);
|
||||
self.check_fn_item(cx, sig.decl, item.owner_id.def_id, ident.name);
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue