Merge commit 'f712eb5cdc' into clippy-subtree-update
This commit is contained in:
parent
4847c40c8b
commit
6ced8c33c0
248 changed files with 5023 additions and 900 deletions
|
|
@ -21,7 +21,7 @@ use rustc_hir::{
|
|||
ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
|
||||
TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
|
||||
};
|
||||
use rustc_lint::{LateContext, LintContext, EarlyContext};
|
||||
use rustc_lint::{EarlyContext, LateContext, LintContext};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{Ident, kw};
|
||||
|
|
@ -63,8 +63,8 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
|
|||
Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
|
||||
} && match end_pat {
|
||||
Pat::Str(text) => end_str.ends_with(text),
|
||||
Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
|
||||
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
|
||||
Pat::MultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)),
|
||||
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)),
|
||||
Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
|
||||
Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
|
||||
})
|
||||
|
|
@ -333,26 +333,32 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
|
|||
match attr.kind {
|
||||
AttrKind::Normal(..) => {
|
||||
if let Some(ident) = attr.ident() {
|
||||
// TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of
|
||||
// refactoring
|
||||
// NOTE: This will likely have false positives, like `allow = 1`
|
||||
(
|
||||
Pat::OwnedMultiStr(vec![ident.to_string(), "#".to_owned()]),
|
||||
Pat::Str(""),
|
||||
)
|
||||
let ident_string = ident.to_string();
|
||||
if attr.style == AttrStyle::Outer {
|
||||
(
|
||||
Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]),
|
||||
Pat::Str(""),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Pat::OwnedMultiStr(vec!["#![".to_owned() + &ident_string, ident_string]),
|
||||
Pat::Str(""),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(Pat::Str("#"), Pat::Str("]"))
|
||||
}
|
||||
},
|
||||
AttrKind::DocComment(_kind @ CommentKind::Line, ..) => {
|
||||
if matches!(attr.style, AttrStyle::Outer) {
|
||||
if attr.style == AttrStyle::Outer {
|
||||
(Pat::Str("///"), Pat::Str(""))
|
||||
} else {
|
||||
(Pat::Str("//!"), Pat::Str(""))
|
||||
}
|
||||
},
|
||||
AttrKind::DocComment(_kind @ CommentKind::Block, ..) => {
|
||||
if matches!(attr.style, AttrStyle::Outer) {
|
||||
if attr.style == AttrStyle::Outer {
|
||||
(Pat::Str("/**"), Pat::Str("*/"))
|
||||
} else {
|
||||
(Pat::Str("/*!"), Pat::Str("*/"))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
//! A simple const eval API, for use on arbitrary HIR expressions.
|
||||
//!
|
||||
//! This cannot use rustc's const eval, aka miri, as arbitrary HIR expressions cannot be lowered to
|
||||
//! executable MIR bodies, so we have to do this instead.
|
||||
#![allow(clippy::float_cmp)]
|
||||
|
||||
use crate::macros::HirNode;
|
||||
|
|
@ -379,6 +383,8 @@ impl Ord for FullInt {
|
|||
/// The context required to evaluate a constant expression.
|
||||
///
|
||||
/// This is currently limited to constant folding and reading the value of named constants.
|
||||
///
|
||||
/// See the module level documentation for some context.
|
||||
pub struct ConstEvalCtxt<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
//! Thank you!
|
||||
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
|
||||
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, SubdiagMessage};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, SubdiagMessage, SubstitutionPart, Suggestions,
|
||||
};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_lint::{LateContext, Lint, LintContext};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -28,6 +30,42 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Makes sure that a diagnostic is well formed.
|
||||
///
|
||||
/// rustc debug asserts a few properties about spans,
|
||||
/// but the clippy repo uses a distributed rustc build with debug assertions disabled,
|
||||
/// so this has historically led to problems during subtree syncs where those debug assertions
|
||||
/// only started triggered there.
|
||||
///
|
||||
/// This function makes sure we also validate them in debug clippy builds.
|
||||
fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) {
|
||||
let suggestions = match &diag.suggestions {
|
||||
Suggestions::Enabled(suggs) => &**suggs,
|
||||
Suggestions::Sealed(suggs) => &**suggs,
|
||||
Suggestions::Disabled => return,
|
||||
};
|
||||
|
||||
for substitution in suggestions.iter().flat_map(|s| &s.substitutions) {
|
||||
assert_eq!(
|
||||
substitution
|
||||
.parts
|
||||
.iter()
|
||||
.find(|SubstitutionPart { snippet, span }| snippet.is_empty() && span.is_empty()),
|
||||
None,
|
||||
"span must not be empty and have no suggestion"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
substitution
|
||||
.parts
|
||||
.array_windows()
|
||||
.find(|[a, b]| a.span.overlaps(b.span)),
|
||||
None,
|
||||
"suggestion must not have overlapping parts"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a basic lint message with a `msg` and a `span`.
|
||||
///
|
||||
/// This is the most primitive of our lint emission methods and can
|
||||
|
|
@ -64,6 +102,9 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
|
|||
cx.span_lint(lint, sp, |diag| {
|
||||
diag.primary_message(msg);
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +159,9 @@ pub fn span_lint_and_help<T: LintContext>(
|
|||
diag.help(help.into());
|
||||
}
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -175,6 +219,9 @@ pub fn span_lint_and_note<T: LintContext>(
|
|||
diag.note(note.into());
|
||||
}
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -208,6 +255,9 @@ where
|
|||
diag.primary_message(msg);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -240,6 +290,9 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s
|
|||
cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
|
||||
diag.primary_message(msg);
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -280,6 +333,9 @@ pub fn span_lint_hir_and_then(
|
|||
diag.primary_message(msg);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +372,7 @@ pub fn span_lint_hir_and_then(
|
|||
/// |
|
||||
/// = note: `-D fold-any` implied by `-D warnings`
|
||||
/// ```
|
||||
#[expect(clippy::collapsible_span_lint_calls)]
|
||||
#[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))]
|
||||
pub fn span_lint_and_sugg<T: LintContext>(
|
||||
cx: &T,
|
||||
lint: &'static Lint,
|
||||
|
|
@ -328,5 +384,8 @@ pub fn span_lint_and_sugg<T: LintContext>(
|
|||
) {
|
||||
span_lint_and_then(cx, lint, sp, msg.into(), |diag| {
|
||||
diag.span_suggestion(sp, help.into(), sugg, applicability);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ impl<'hir> IfLet<'hir> {
|
|||
/// Parses an `if let` expression
|
||||
pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
|
||||
if let ExprKind::If(
|
||||
Expr {
|
||||
&Expr {
|
||||
kind:
|
||||
ExprKind::Let(&hir::LetExpr {
|
||||
pat: let_pat,
|
||||
|
|
@ -381,12 +381,12 @@ impl<'hir> WhileLet<'hir> {
|
|||
/// Parses a desugared `while let` loop
|
||||
pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
|
||||
if let ExprKind::Loop(
|
||||
Block {
|
||||
&Block {
|
||||
expr:
|
||||
Some(Expr {
|
||||
Some(&Expr {
|
||||
kind:
|
||||
ExprKind::If(
|
||||
Expr {
|
||||
&Expr {
|
||||
kind:
|
||||
ExprKind::Let(&hir::LetExpr {
|
||||
pat: let_pat,
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
|||
self.inter_expr().eq_path_segments(left, right)
|
||||
}
|
||||
|
||||
pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool {
|
||||
pub fn eq_modifiers(left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool {
|
||||
std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness)
|
||||
&& std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity)
|
||||
}
|
||||
|
|
@ -1201,11 +1201,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
self.hash_ty(ty);
|
||||
self.hash_pat(pat);
|
||||
},
|
||||
TyKind::Ptr(ref mut_ty) => {
|
||||
TyKind::Ptr(mut_ty) => {
|
||||
self.hash_ty(mut_ty.ty);
|
||||
mut_ty.mutbl.hash(&mut self.s);
|
||||
},
|
||||
TyKind::Ref(lifetime, ref mut_ty) => {
|
||||
TyKind::Ref(lifetime, mut_ty) => {
|
||||
self.hash_lifetime(lifetime);
|
||||
self.hash_ty(mut_ty.ty);
|
||||
mut_ty.mutbl.hash(&mut self.s);
|
||||
|
|
@ -1230,14 +1230,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
self.hash_ty(ty);
|
||||
}
|
||||
},
|
||||
TyKind::Path(ref qpath) => self.hash_qpath(qpath),
|
||||
TyKind::Path(qpath) => self.hash_qpath(qpath),
|
||||
TyKind::TraitObject(_, lifetime, _) => {
|
||||
self.hash_lifetime(lifetime);
|
||||
},
|
||||
TyKind::Typeof(anon_const) => {
|
||||
self.hash_body(anon_const.body);
|
||||
},
|
||||
TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::OpaqueDef(_) | TyKind::AnonAdt(_) => {},
|
||||
TyKind::Err(_)
|
||||
| TyKind::Infer
|
||||
| TyKind::Never
|
||||
| TyKind::InferDelegation(..)
|
||||
| TyKind::OpaqueDef(_)
|
||||
| TyKind::AnonAdt(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#![feature(rustc_private)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![feature(array_windows)]
|
||||
#![recursion_limit = "512"]
|
||||
#![allow(
|
||||
clippy::missing_errors_doc,
|
||||
|
|
@ -688,11 +689,11 @@ pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> Vec<Res> {
|
|||
///
|
||||
/// This function is expensive and should be used sparingly.
|
||||
pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec<Res> {
|
||||
let (base, path) = match *path {
|
||||
let (base, path) = match path {
|
||||
[primitive] => {
|
||||
return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
|
||||
},
|
||||
[base, ref path @ ..] => (base, path),
|
||||
[base, path @ ..] => (base, path),
|
||||
_ => return Vec::new(),
|
||||
};
|
||||
|
||||
|
|
@ -744,7 +745,7 @@ pub fn def_path_res_with_base(tcx: TyCtxt<'_>, mut base: Vec<Res>, mut path: &[&
|
|||
}
|
||||
|
||||
/// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`].
|
||||
pub fn def_path_def_ids(tcx: TyCtxt<'_>, path: &[&str]) -> impl Iterator<Item = DefId> {
|
||||
pub fn def_path_def_ids(tcx: TyCtxt<'_>, path: &[&str]) -> impl Iterator<Item = DefId> + use<> {
|
||||
def_path_res(tcx, path).into_iter().filter_map(|res| res.opt_def_id())
|
||||
}
|
||||
|
||||
|
|
@ -934,7 +935,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||
}
|
||||
},
|
||||
ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func),
|
||||
ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg),
|
||||
ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg),
|
||||
ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
|
||||
ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
|
||||
_ => false,
|
||||
|
|
@ -947,7 +948,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
|
|||
{
|
||||
match arg.kind {
|
||||
ExprKind::Lit(hir::Lit {
|
||||
node: LitKind::Str(ref sym, _),
|
||||
node: LitKind::Str(sym, _),
|
||||
..
|
||||
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
|
||||
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
|
||||
|
|
@ -1337,15 +1338,17 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
|
|||
pub struct ContainsName<'a, 'tcx> {
|
||||
pub cx: &'a LateContext<'tcx>,
|
||||
pub name: Symbol,
|
||||
pub result: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_name(&mut self, name: Symbol) {
|
||||
fn visit_name(&mut self, name: Symbol) -> Self::Result {
|
||||
if self.name == name {
|
||||
self.result = true;
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1356,13 +1359,8 @@ impl<'tcx> Visitor<'tcx> for ContainsName<'_, 'tcx> {
|
|||
|
||||
/// Checks if an `Expr` contains a certain name.
|
||||
pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool {
|
||||
let mut cn = ContainsName {
|
||||
name,
|
||||
result: false,
|
||||
cx,
|
||||
};
|
||||
cn.visit_expr(expr);
|
||||
cn.result
|
||||
let mut cn = ContainsName { cx, name };
|
||||
cn.visit_expr(expr).is_break()
|
||||
}
|
||||
|
||||
/// Returns `true` if `expr` contains a return expression
|
||||
|
|
@ -3459,7 +3457,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St
|
|||
pub fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
|
||||
matches!(
|
||||
cx.tcx.parent_hir_node(id),
|
||||
Node::Stmt(..) | Node::Block(Block { stmts: &[], .. })
|
||||
Node::Stmt(..) | Node::Block(Block { stmts: [], .. })
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement;
|
|||
use rustc_middle::ty::{
|
||||
self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
|
||||
GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, TypingMode,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, UintTy, Upcast, VariantDef, VariantDiscr,
|
||||
};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
|
@ -274,11 +274,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
|
|||
.map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let trait_ref = TraitRef::new(
|
||||
tcx,
|
||||
trait_id,
|
||||
[GenericArg::from(ty)].into_iter().chain(args),
|
||||
);
|
||||
let trait_ref = TraitRef::new(tcx, trait_id, [GenericArg::from(ty)].into_iter().chain(args));
|
||||
|
||||
debug_assert_matches!(
|
||||
tcx.def_kind(trait_id),
|
||||
|
|
@ -975,9 +971,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
|
|||
match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) {
|
||||
(Ok(size), _) => size,
|
||||
(Err(_), ty::Tuple(list)) => list.iter().map(|t| approx_ty_size(cx, t)).sum(),
|
||||
(Err(_), ty::Array(t, n)) => {
|
||||
n.try_to_target_usize(cx.tcx).unwrap_or_default() * approx_ty_size(cx, *t)
|
||||
},
|
||||
(Err(_), ty::Array(t, n)) => n.try_to_target_usize(cx.tcx).unwrap_or_default() * approx_ty_size(cx, *t),
|
||||
(Err(_), ty::Adt(def, subst)) if def.is_struct() => def
|
||||
.variants()
|
||||
.iter()
|
||||
|
|
@ -1284,7 +1278,12 @@ pub fn make_normalized_projection_with_regions<'tcx>(
|
|||
|
||||
pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let cause = ObligationCause::dummy();
|
||||
match tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)).at(&cause, param_env).query_normalize(ty) {
|
||||
match tcx
|
||||
.infer_ctxt()
|
||||
.build(TypingMode::from_param_env(param_env))
|
||||
.at(&cause, param_env)
|
||||
.query_normalize(ty)
|
||||
{
|
||||
Ok(ty) => ty.value,
|
||||
Err(_) => ty,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,9 +302,9 @@ fn type_is_inferable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bo
|
|||
// Check that all type parameters appear in the functions input types.
|
||||
(0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| {
|
||||
fn_sig
|
||||
.inputs()
|
||||
.iter()
|
||||
.any(|input_ty| contains_param(*input_ty.skip_binder(), index))
|
||||
.inputs()
|
||||
.iter()
|
||||
.any(|input_ty| contains_param(*input_ty.skip_binder(), index))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,34 +109,28 @@ impl<'tcx> Visitor<'tcx> for ParamBindingIdCollector {
|
|||
pub struct BindingUsageFinder<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
binding_ids: Vec<HirId>,
|
||||
usage_found: bool,
|
||||
}
|
||||
impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> {
|
||||
pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool {
|
||||
let mut finder = BindingUsageFinder {
|
||||
cx,
|
||||
binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body),
|
||||
usage_found: false,
|
||||
};
|
||||
finder.visit_body(body);
|
||||
finder.usage_found
|
||||
finder.visit_body(body).is_break()
|
||||
}
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
if !self.usage_found {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) {
|
||||
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) -> Self::Result {
|
||||
if let Res::Local(id) = path.res {
|
||||
if self.binding_ids.contains(&id) {
|
||||
self.usage_found = true;
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
|
|||
|
|
@ -324,17 +324,15 @@ pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tc
|
|||
pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
|
||||
struct V<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
is_const: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
type NestedFilter = intravisit::nested_filter::None;
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if !self.is_const {
|
||||
return;
|
||||
}
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(_) => return,
|
||||
ExprKind::ConstBlock(_) => return ControlFlow::Continue(()),
|
||||
ExprKind::Call(
|
||||
&Expr {
|
||||
kind: ExprKind::Path(ref p),
|
||||
|
|
@ -394,37 +392,34 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
|
|||
| ExprKind::Type(..) => (),
|
||||
|
||||
_ => {
|
||||
self.is_const = false;
|
||||
return;
|
||||
return ControlFlow::Break(());
|
||||
},
|
||||
}
|
||||
walk_expr(self, e);
|
||||
|
||||
walk_expr(self, e)
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = V { cx, is_const: true };
|
||||
v.visit_expr(e);
|
||||
v.is_const
|
||||
let mut v = V { cx };
|
||||
v.visit_expr(e).is_continue()
|
||||
}
|
||||
|
||||
/// Checks if the given expression performs an unsafe operation outside of an unsafe block.
|
||||
pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
|
||||
struct V<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
is_unsafe: bool,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
}
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if self.is_unsafe {
|
||||
return;
|
||||
}
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
|
||||
match e.kind {
|
||||
ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => {
|
||||
self.is_unsafe = true;
|
||||
ControlFlow::Break(())
|
||||
},
|
||||
ExprKind::MethodCall(..)
|
||||
if self
|
||||
|
|
@ -435,13 +430,13 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
|
|||
self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe
|
||||
}) =>
|
||||
{
|
||||
self.is_unsafe = true;
|
||||
ControlFlow::Break(())
|
||||
},
|
||||
ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
|
||||
ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe => {
|
||||
self.is_unsafe = true;
|
||||
ControlFlow::Break(())
|
||||
},
|
||||
ty::FnPtr(_, hdr) if hdr.safety == Safety::Unsafe => self.is_unsafe = true,
|
||||
ty::FnPtr(_, hdr) if hdr.safety == Safety::Unsafe => ControlFlow::Break(()),
|
||||
_ => walk_expr(self, e),
|
||||
},
|
||||
ExprKind::Path(ref p)
|
||||
|
|
@ -451,56 +446,54 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
|
|||
.opt_def_id()
|
||||
.map_or(false, |id| self.cx.tcx.is_mutable_static(id)) =>
|
||||
{
|
||||
self.is_unsafe = true;
|
||||
ControlFlow::Break(())
|
||||
},
|
||||
_ => walk_expr(self, e),
|
||||
}
|
||||
}
|
||||
fn visit_block(&mut self, b: &'tcx Block<'_>) {
|
||||
if !matches!(b.rules, BlockCheckMode::UnsafeBlock(_)) {
|
||||
walk_block(self, b);
|
||||
fn visit_block(&mut self, b: &'tcx Block<'_>) -> Self::Result {
|
||||
if matches!(b.rules, BlockCheckMode::UnsafeBlock(_)) {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
walk_block(self, b)
|
||||
}
|
||||
}
|
||||
fn visit_nested_item(&mut self, id: ItemId) {
|
||||
if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind {
|
||||
self.is_unsafe = i.safety == Safety::Unsafe;
|
||||
fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
|
||||
if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind
|
||||
&& i.safety == Safety::Unsafe
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut v = V { cx, is_unsafe: false };
|
||||
v.visit_expr(e);
|
||||
v.is_unsafe
|
||||
let mut v = V { cx };
|
||||
v.visit_expr(e).is_break()
|
||||
}
|
||||
|
||||
/// Checks if the given expression contains an unsafe block
|
||||
pub fn contains_unsafe_block<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
|
||||
struct V<'cx, 'tcx> {
|
||||
cx: &'cx LateContext<'tcx>,
|
||||
found_unsafe: bool,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, b: &'tcx Block<'_>) {
|
||||
if self.found_unsafe {
|
||||
return;
|
||||
}
|
||||
fn visit_block(&mut self, b: &'tcx Block<'_>) -> Self::Result {
|
||||
if b.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) {
|
||||
self.found_unsafe = true;
|
||||
return;
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
walk_block(self, b)
|
||||
}
|
||||
walk_block(self, b);
|
||||
}
|
||||
}
|
||||
let mut v = V {
|
||||
cx,
|
||||
found_unsafe: false,
|
||||
};
|
||||
v.visit_expr(e);
|
||||
v.found_unsafe
|
||||
let mut v = V { cx };
|
||||
v.visit_expr(e).is_break()
|
||||
}
|
||||
|
||||
/// Runs the given function for each sub-expression producing the final value consumed by the parent
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue