-use crate::utils::{match_type, paths, return_ty, span_lint};
+use crate::utils::{get_trait_def_id, implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint};
use itertools::Itertools;
-use rustc::hir;
-use rustc::impl_lint_pass;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::lint::in_external_macro;
+use rustc::ty::TyKind;
use rustc_data_structures::fx::FxHashSet;
-use rustc_session::declare_tool_lint;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::source_map::{BytePos, MultiSpan, Span};
+use rustc_span::Pos;
use std::ops::Range;
use syntax::ast::{AttrKind, Attribute};
-use syntax::source_map::{BytePos, MultiSpan, Span};
-use syntax_pos::Pos;
use url::Url;
declare_clippy_lint! {
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
match item.kind {
hir::ItemKind::Fn(ref sig, ..) => {
- lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+ if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id))
+ || in_external_macro(cx.tcx.sess, item.span))
+ {
+ lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+ }
},
- hir::ItemKind::Impl(_, _, _, _, ref trait_ref, ..) => {
+ hir::ItemKind::Impl {
+ of_trait: ref trait_ref,
+ ..
+ } => {
self.in_trait_impl = trait_ref.is_some();
},
_ => {},
}
fn check_item_post(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
- if let hir::ItemKind::Impl(..) = item.kind {
+ if let hir::ItemKind::Impl { .. } = item.kind {
self.in_trait_impl = false;
}
}
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem<'_>) {
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
if let hir::TraitItemKind::Method(ref sig, ..) = item.kind {
- lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+ if !in_external_macro(cx.tcx.sess, item.span) {
+ lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
+ }
}
}
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem<'_>) {
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
- if self.in_trait_impl {
+ if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
return;
}
if let hir::ImplItemKind::Method(ref sig, ..) = item.kind {
cx: &LateContext<'a, 'tcx>,
hir_id: hir::HirId,
span: impl Into<MultiSpan> + Copy,
- sig: &hir::FnSig,
+ sig: &hir::FnSig<'_>,
headers: DocHeaders,
) {
if !cx.access_levels.is_exported(hir_id) {
"unsafe function's docs miss `# Safety` section",
);
}
- if !headers.errors && match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
- span_lint(
- cx,
- MISSING_ERRORS_DOC,
- span,
- "docs for function returning `Result` missing `# Errors` section",
- );
+ if !headers.errors {
+ if match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
+ span_lint(
+ cx,
+ MISSING_ERRORS_DOC,
+ span,
+ "docs for function returning `Result` missing `# Errors` section",
+ );
+ } else {
+ let def_id = cx.tcx.hir().local_def_id(hir_id);
+ let mir = cx.tcx.optimized_mir(def_id);
+ if let Some(future) = get_trait_def_id(cx, &paths::FUTURE) {
+ if implements_trait(cx, mir.return_ty(), future, &[]) {
+ use TyKind::*;
+
+ if let Opaque(_, subs) = mir.return_ty().kind {
+ if let Some(ty) = subs.types().next() {
+ if let Generator(_, subs, _) = ty.kind {
+ if match_type(cx, subs.as_generator().return_ty(def_id, cx.tcx), &paths::RESULT) {
+ span_lint(
+ cx,
+ MISSING_ERRORS_DOC,
+ span,
+ "docs for function returning `Result` missing `# Errors` section",
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
}
headers
}
+static LEAVE_MAIN_PATTERNS: &[&str] = &["static", "fn main() {}", "extern crate"];
+
fn check_code(cx: &LateContext<'_, '_>, text: &str, span: Span) {
- if text.contains("fn main() {") && !(text.contains("static") || text.contains("fn main() {}")) {
+ if text.contains("fn main() {") && !LEAVE_MAIN_PATTERNS.iter().any(|p| text.contains(p)) {
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
}
}