pub mod higher;
mod hir_utils;
pub mod inspector;
+#[cfg(feature = "internal-lints")]
pub mod internal_lints;
pub mod numeric_literal;
pub mod paths;
pub mod qualify_min_const_fn;
pub mod sugg;
pub mod usage;
+pub mod visitors;
pub use self::attrs::*;
pub use self::diagnostics::*;
use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
+use rustc_semver::RustcVersion;
+use rustc_session::Session;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::original_sp;
use rustc_span::sym as rustc_sym;
use crate::consts::{constant, Constant};
+pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
+ if let Ok(version) = RustcVersion::parse(msrv) {
+ return Some(version);
+ } else if let Some(sess) = sess {
+ if let Some(span) = span {
+ sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv));
+ }
+ }
+ None
+}
+
+pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
+ msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
+}
+
+macro_rules! extract_msrv_attr {
+ (LateContext) => {
+ extract_msrv_attr!(@LateContext, ());
+ };
+ (EarlyContext) => {
+ extract_msrv_attr!(@EarlyContext);
+ };
+ (@$context:ident$(, $call:tt)?) => {
+ fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
+ use $crate::utils::get_unique_inner_attr;
+ match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
+ Some(msrv_attr) => {
+ if let Some(msrv) = msrv_attr.value_str() {
+ self.msrv = $crate::utils::parse_msrv(
+ &msrv.to_string(),
+ Some(cx.sess$($call)?),
+ Some(msrv_attr.span),
+ );
+ } else {
+ cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
+ }
+ },
+ _ => (),
+ }
+ }
+ };
+}
+
/// Returns `true` if the two spans come from differing expansions (i.e., one is
/// from a macro and one isn't).
#[must_use]
return false;
}
let ty = cx.tcx.erase_regions(ty);
+ if ty.has_escaping_bound_vars() {
+ return false;
+ }
let ty_params = cx.tcx.mk_substs(ty_params.iter());
cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
}
.map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
}
+/// Returns `true` if the expression is in the program's `#[panic_handler]`.
+pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+ let parent = cx.tcx.hir().get_parent_item(e.hir_id);
+ let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
+ Some(def_id) == cx.tcx.lang_items().panic_impl()
+}
+
/// Gets the name of the item the expression is in, if available.
pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
cn.result
}
+/// Returns `true` if `expr` contains a return expression
+pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
+ struct RetCallFinder {
+ found: bool,
+ }
+
+ impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
+ type Map = Map<'tcx>;
+
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
+ if self.found {
+ return;
+ }
+ if let hir::ExprKind::Ret(..) = &expr.kind {
+ self.found = true;
+ } else {
+ hir::intravisit::walk_expr(self, expr);
+ }
+ }
+
+ fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+ hir::intravisit::NestedVisitorMap::None
+ }
+ }
+
+ let mut visitor = RetCallFinder { found: false };
+ visitor.visit_expr(expr);
+ visitor.found
+}
+
/// Converts a span to a code snippet if available, otherwise use default.
///
/// This is useful if you want to provide suggestions for your lint or more generally, if you want
snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace()))
}
+/// Returns the positon just before rarrow
+///
+/// ```rust,ignore
+/// fn into(self) -> () {}
+/// ^
+/// // in case of unformatted code
+/// fn into2(self)-> () {}
+/// ^
+/// fn into3(self) -> () {}
+/// ^
+/// ```
+#[allow(clippy::needless_pass_by_value)]
+pub fn position_before_rarrow(s: String) -> Option<usize> {
+ s.rfind("->").map(|rpos| {
+ let mut rpos = rpos;
+ let chars: Vec<char> = s.chars().collect();
+ while rpos > 1 {
+ if let Some(c) = chars.get(rpos - 1) {
+ if c.is_whitespace() {
+ rpos -= 1;
+ continue;
+ }
+ }
+ break;
+ }
+ rpos
+ })
+}
+
/// Extends the span to the beginning of the spans line, incl. whitespaces.
///
/// ```rust,ignore