Merge commit '3e4179766b' into sync-from-clippy
This commit is contained in:
parent
b56b751055
commit
c8cb90abbd
35 changed files with 526 additions and 134 deletions
|
|
@ -1,4 +1,7 @@
|
|||
use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint};
|
||||
use crate::utils::{
|
||||
implements_trait, is_entrypoint_fn, is_type_diagnostic_item, match_panic_def_id, method_chain_args, return_ty,
|
||||
span_lint, span_lint_and_note,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind};
|
||||
|
|
@ -8,7 +11,10 @@ use rustc_data_structures::sync::Lrc;
|
|||
use rustc_errors::emitter::EmitterWriter;
|
||||
use rustc_errors::Handler;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
use rustc_parse::maybe_new_parser_from_source_str;
|
||||
|
|
@ -122,6 +128,37 @@ declare_clippy_lint! {
|
|||
"`pub fn` returns `Result` without `# Errors` in doc comment"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks the doc comments of publicly visible functions that
|
||||
/// may panic and warns if there is no `# Panics` section.
|
||||
///
|
||||
/// **Why is this bad?** Documenting the scenarios in which panicking occurs
|
||||
/// can help callers who do not want to panic to avoid those situations.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Examples:**
|
||||
///
|
||||
/// Since the following function may panic it has a `# Panics` section in
|
||||
/// its doc comment:
|
||||
///
|
||||
/// ```rust
|
||||
/// /// # Panics
|
||||
/// ///
|
||||
/// /// Will panic if y is 0
|
||||
/// pub fn divide_by(x: i32, y: i32) -> i32 {
|
||||
/// if y == 0 {
|
||||
/// panic!("Cannot divide by 0")
|
||||
/// } else {
|
||||
/// x / y
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub MISSING_PANICS_DOC,
|
||||
pedantic,
|
||||
"`pub fn` may panic without `# Panics` in doc comment"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for `fn main() { .. }` in doctests
|
||||
///
|
||||
|
|
@ -166,7 +203,9 @@ impl DocMarkdown {
|
|||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, NEEDLESS_DOCTEST_MAIN]);
|
||||
impl_lint_pass!(DocMarkdown =>
|
||||
[DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN]
|
||||
);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||
fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
|
||||
|
|
@ -180,7 +219,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id).to_def_id())
|
||||
|| in_external_macro(cx.tcx.sess, item.span))
|
||||
{
|
||||
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let impl_item_def_id = cx.tcx.hir().local_def_id(item.hir_id);
|
||||
let mut fpu = FindPanicUnwrap {
|
||||
cx,
|
||||
typeck_results: cx.tcx.typeck(impl_item_def_id),
|
||||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(&body.value);
|
||||
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
},
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
|
|
@ -200,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
|
||||
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
|
||||
if !in_external_macro(cx.tcx.sess, item.span) {
|
||||
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None);
|
||||
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -211,7 +258,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
|||
return;
|
||||
}
|
||||
if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
|
||||
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id));
|
||||
let body = cx.tcx.hir().body(body_id);
|
||||
let impl_item_def_id = cx.tcx.hir().local_def_id(item.hir_id);
|
||||
let mut fpu = FindPanicUnwrap {
|
||||
cx,
|
||||
typeck_results: cx.tcx.typeck(impl_item_def_id),
|
||||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(&body.value);
|
||||
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -223,6 +278,7 @@ fn lint_for_missing_headers<'tcx>(
|
|||
sig: &hir::FnSig<'_>,
|
||||
headers: DocHeaders,
|
||||
body_id: Option<hir::BodyId>,
|
||||
panic_span: Option<Span>,
|
||||
) {
|
||||
if !cx.access_levels.is_exported(hir_id) {
|
||||
return; // Private functions do not require doc comments
|
||||
|
|
@ -235,6 +291,16 @@ fn lint_for_missing_headers<'tcx>(
|
|||
"unsafe function's docs miss `# Safety` section",
|
||||
);
|
||||
}
|
||||
if !headers.panics && panic_span.is_some() {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
MISSING_PANICS_DOC,
|
||||
span,
|
||||
"docs for function which may panic missing `# Panics` section",
|
||||
panic_span,
|
||||
"first possible panic found here",
|
||||
);
|
||||
}
|
||||
if !headers.errors {
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
|
||||
span_lint(
|
||||
|
|
@ -321,6 +387,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span:
|
|||
struct DocHeaders {
|
||||
safety: bool,
|
||||
errors: bool,
|
||||
panics: bool,
|
||||
}
|
||||
|
||||
fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
|
||||
|
|
@ -338,6 +405,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
|
|||
return DocHeaders {
|
||||
safety: true,
|
||||
errors: true,
|
||||
panics: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -353,6 +421,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
|
|||
return DocHeaders {
|
||||
safety: false,
|
||||
errors: false,
|
||||
panics: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -394,6 +463,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
|||
let mut headers = DocHeaders {
|
||||
safety: false,
|
||||
errors: false,
|
||||
panics: false,
|
||||
};
|
||||
let mut in_code = false;
|
||||
let mut in_link = None;
|
||||
|
|
@ -439,6 +509,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
|||
}
|
||||
headers.safety |= in_heading && text.trim() == "Safety";
|
||||
headers.errors |= in_heading && text.trim() == "Errors";
|
||||
headers.panics |= in_heading && text.trim() == "Panics";
|
||||
let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) {
|
||||
Ok(o) => o,
|
||||
Err(e) => e - 1,
|
||||
|
|
@ -609,3 +680,47 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct FindPanicUnwrap<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
panic_span: Option<Span>,
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if self.panic_span.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for `begin_panic`
|
||||
if_chain! {
|
||||
if let ExprKind::Call(ref func_expr, _) = expr.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind;
|
||||
if let Some(path_def_id) = path.res.opt_def_id();
|
||||
if match_panic_def_id(self.cx, path_def_id);
|
||||
then {
|
||||
self.panic_span = Some(expr.span);
|
||||
}
|
||||
}
|
||||
|
||||
// check for `unwrap`
|
||||
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
|
||||
let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
|
||||
if is_type_diagnostic_item(self.cx, reciever_ty, sym::option_type)
|
||||
|| is_type_diagnostic_item(self.cx, reciever_ty, sym::result_type)
|
||||
{
|
||||
self.panic_span = Some(expr.span);
|
||||
}
|
||||
}
|
||||
|
||||
// and check sub-expressions
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,15 +160,17 @@ impl EarlyLintPass for ExcessiveBools {
|
|||
"consider using a state machine or refactoring bools into two-variant enums",
|
||||
);
|
||||
}
|
||||
}
|
||||
ItemKind::Impl(box ImplKind { of_trait: None, items, .. })
|
||||
},
|
||||
ItemKind::Impl(box ImplKind {
|
||||
of_trait: None, items, ..
|
||||
})
|
||||
| ItemKind::Trait(box TraitKind(.., items)) => {
|
||||
for item in items {
|
||||
if let AssocItemKind::Fn(box FnKind(_, fn_sig, _, _)) = &item.kind {
|
||||
self.check_fn_sig(cx, fn_sig, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ItemKind::Fn(box FnKind(_, fn_sig, _, _)) => self.check_fn_sig(cx, fn_sig, item.span),
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,10 +75,14 @@ impl LateLintPass<'_> for ExhaustiveItems {
|
|||
if cx.access_levels.is_exported(item.hir_id);
|
||||
if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
|
||||
then {
|
||||
let (lint, msg) = if let ItemKind::Enum(..) = item.kind {
|
||||
(EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
|
||||
} else {
|
||||
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
|
||||
if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
|
||||
// skip structs with private fields
|
||||
return;
|
||||
}
|
||||
(EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
|
||||
} else {
|
||||
(EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
|
||||
};
|
||||
let suggestion_span = item.span.shrink_to_lo();
|
||||
let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
|
||||
|
|
|
|||
|
|
@ -592,6 +592,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&disallowed_method::DISALLOWED_METHOD,
|
||||
&doc::DOC_MARKDOWN,
|
||||
&doc::MISSING_ERRORS_DOC,
|
||||
&doc::MISSING_PANICS_DOC,
|
||||
&doc::MISSING_SAFETY_DOC,
|
||||
&doc::NEEDLESS_DOCTEST_MAIN,
|
||||
&double_comparison::DOUBLE_COMPARISONS,
|
||||
|
|
@ -1317,6 +1318,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE),
|
||||
LintId::of(&doc::DOC_MARKDOWN),
|
||||
LintId::of(&doc::MISSING_ERRORS_DOC),
|
||||
LintId::of(&doc::MISSING_PANICS_DOC),
|
||||
LintId::of(&empty_enum::EMPTY_ENUM),
|
||||
LintId::of(&enum_variants::MODULE_NAME_REPETITIONS),
|
||||
LintId::of(&enum_variants::PUB_ENUM_VARIANT_NAMES),
|
||||
|
|
|
|||
|
|
@ -1592,7 +1592,17 @@ where
|
|||
}
|
||||
},
|
||||
(&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
|
||||
_ => return Some((a.range(), b.range())),
|
||||
_ => {
|
||||
// skip if the range `a` is completely included into the range `b`
|
||||
if let Ordering::Equal | Ordering::Less = a.cmp(&b) {
|
||||
let kind_a = Kind::End(a.range().node.1, a.range());
|
||||
let kind_b = Kind::End(b.range().node.1, b.range());
|
||||
if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
return Some((a.range(), b.range()));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
(ForeignMod(l), ForeignMod(r)) => {
|
||||
both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
|
||||
&& over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
|
||||
}
|
||||
},
|
||||
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
|
|
@ -259,7 +259,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
},
|
||||
(Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
|
||||
eq_variant_data(lv, rv) && eq_generics(lg, rg)
|
||||
}
|
||||
},
|
||||
(Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => {
|
||||
la == ra
|
||||
&& matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
|
||||
|
|
@ -331,15 +331,10 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
|||
pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
||||
use AssocItemKind::*;
|
||||
match (l, r) {
|
||||
(Const(ld, lt, le), Const(rd, rt, re)) => {
|
||||
eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re)
|
||||
}
|
||||
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
(Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_fn_sig(lf, rf)
|
||||
&& eq_generics(lg, rg)
|
||||
&& both(lb, rb, |l, r| eq_block(l, r))
|
||||
}
|
||||
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
|
||||
},
|
||||
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ pub fn span_lint_and_help<'a, T: LintContext>(
|
|||
pub fn span_lint_and_note<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
note_span: Option<Span>,
|
||||
note: &str,
|
||||
|
|
|
|||
|
|
@ -760,7 +760,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
|
|||
// Extract the path to the matched type
|
||||
if let Some(segments) = path_to_matched_type(cx, ty_path);
|
||||
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
|
||||
if let Some(ty_did) = path_to_res(cx, &segments[..]).and_then(|res| res.opt_def_id());
|
||||
if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
|
||||
// Check if the matched type is a diagnostic item
|
||||
let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
|
||||
if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
|
||||
|
|
@ -833,7 +833,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
|
|||
// This is not a complete resolver for paths. It works on all the paths currently used in the paths
|
||||
// module. That's all it does and all it needs to do.
|
||||
pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
|
||||
if path_to_res(cx, path).is_some() {
|
||||
if path_to_res(cx, path) != Res::Err {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -906,7 +906,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
|
|||
}
|
||||
|
||||
for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
|
||||
if let Some(Res::Def(_, def_id)) = path_to_res(cx, module) {
|
||||
if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
|
||||
for item in cx.tcx.item_children(def_id).iter() {
|
||||
if_chain! {
|
||||
if let Res::Def(DefKind::Const, item_def_id) = item.res;
|
||||
|
|
|
|||
|
|
@ -309,7 +309,15 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
|
|||
|
||||
/// Gets the definition associated to a path.
|
||||
#[allow(clippy::shadow_unrelated)] // false positive #6563
|
||||
pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<Res> {
|
||||
pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
|
||||
macro_rules! try_res {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Some(e) => e,
|
||||
None => return Res::Err,
|
||||
}
|
||||
};
|
||||
}
|
||||
fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export<HirId>> {
|
||||
tcx.item_children(def_id)
|
||||
.iter()
|
||||
|
|
@ -318,12 +326,12 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<Res> {
|
|||
|
||||
let (krate, first, path) = match *path {
|
||||
[krate, first, ref path @ ..] => (krate, first, path),
|
||||
_ => return None,
|
||||
_ => return Res::Err,
|
||||
};
|
||||
let tcx = cx.tcx;
|
||||
let crates = tcx.crates();
|
||||
let krate = crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate)?;
|
||||
let first = item_child_by_name(tcx, krate.as_def_id(), first)?;
|
||||
let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
|
||||
let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
|
||||
let last = path
|
||||
.iter()
|
||||
.copied()
|
||||
|
|
@ -343,21 +351,15 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<Res> {
|
|||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
Some(last.res)
|
||||
});
|
||||
try_res!(last).res
|
||||
}
|
||||
|
||||
/// Convenience function to get the `DefId` of a trait by path.
|
||||
/// It could be a trait or trait alias.
|
||||
pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
|
||||
let res = match path_to_res(cx, path) {
|
||||
Some(res) => res,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
match res {
|
||||
match path_to_res(cx, path) {
|
||||
Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
|
||||
Res::Err => unreachable!("this trait resolution is impossible: {:?}", &path),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -1532,10 +1534,11 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
|
|||
ExprKind::Call(
|
||||
Expr {
|
||||
kind: ExprKind::Path(qpath),
|
||||
hir_id: path_hir_id,
|
||||
..
|
||||
},
|
||||
..,
|
||||
) => cx.typeck_results().qpath_res(qpath, expr.hir_id).opt_def_id(),
|
||||
) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,11 @@ impl_lint_pass!(Write => [
|
|||
|
||||
impl EarlyLintPass for Write {
|
||||
fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
|
||||
if let ItemKind::Impl(box ImplKind { of_trait: Some(trait_ref), .. }) = &item.kind {
|
||||
if let ItemKind::Impl(box ImplKind {
|
||||
of_trait: Some(trait_ref),
|
||||
..
|
||||
}) = &item.kind
|
||||
{
|
||||
let trait_name = trait_ref
|
||||
.path
|
||||
.segments
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue