Skip to content

Commit

Permalink
Fix hidden variant suggestion on single variant
Browse files Browse the repository at this point in the history
Fixes #6984
  • Loading branch information
Michael Wright committed Mar 31, 2021
1 parent 0b76719 commit 8abab55
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 23 deletions.
1 change: 0 additions & 1 deletion clippy_lints/src/lib.rs
Expand Up @@ -21,7 +21,6 @@
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_attr;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_errors;
Expand Down
14 changes: 3 additions & 11 deletions clippy_lints/src/manual_non_exhaustive.rs
@@ -1,9 +1,9 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::meets_msrv;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_ast::ast::{Attribute, FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
use rustc_attr as attr;
use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_semver::RustcVersion;
Expand Down Expand Up @@ -102,15 +102,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
fn is_non_exhaustive_marker(variant: &Variant) -> bool {
matches!(variant.data, VariantData::Unit(_))
&& variant.ident.as_str().starts_with('_')
&& variant.attrs.iter().any(|a| is_doc_hidden(a))
}

fn is_doc_hidden(attr: &Attribute) -> bool {
attr.has_name(sym::doc)
&& match attr.meta_item_list() {
Some(l) => attr::list_contains_name(&l, sym::hidden),
None => false,
}
&& is_doc_hidden(&variant.attrs)
}

if_chain! {
Expand Down
7 changes: 6 additions & 1 deletion clippy_lints/src/matches.rs
Expand Up @@ -983,6 +983,11 @@ impl CommonPrefixSearcher<'a> {
}
}

fn is_doc_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
let attrs = cx.tcx.get_attrs(variant_def.def_id);
clippy_utils::attrs::is_doc_hidden(attrs)
}

#[allow(clippy::too_many_lines)]
fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let ty = cx.typeck_results().expr_ty(ex).peel_refs();
Expand Down Expand Up @@ -1102,7 +1107,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])

match missing_variants.as_slice() {
[] => (),
[x] if !adt_def.is_variant_list_non_exhaustive() => span_lint_and_sugg(
[x] if !adt_def.is_variant_list_non_exhaustive() && !is_doc_hidden(cx, x) => span_lint_and_sugg(
cx,
MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
wildcard_span,
Expand Down
11 changes: 2 additions & 9 deletions clippy_lints/src/missing_doc.rs
Expand Up @@ -5,10 +5,10 @@
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
//

use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use if_chain::if_chain;
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_ast::attr;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
Expand Down Expand Up @@ -111,14 +111,7 @@ impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);

impl<'tcx> LateLintPass<'tcx> for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
let doc_hidden = self.doc_hidden()
|| attrs.iter().any(|attr| {
attr.has_name(sym::doc)
&& match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l[..], sym::hidden),
}
});
let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
self.doc_hidden_stack.push(doc_hidden);
}

Expand Down
12 changes: 11 additions & 1 deletion clippy_utils/src/attrs.rs
@@ -1,4 +1,4 @@
use rustc_ast::ast;
use rustc_ast::{ast, attr};
use rustc_errors::Applicability;
use rustc_session::Session;
use rustc_span::sym;
Expand Down Expand Up @@ -148,3 +148,13 @@ pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'s
pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
}

/// Return true if the attributes contain `#[doc(hidden)]`
pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
#[allow(clippy::filter_map)]
attrs
.iter()
.filter(|attr| attr.has_name(sym::doc))
.flat_map(ast::Attribute::meta_item_list)
.any(|l| attr::list_contains_name(&l, sym::hidden))
}
16 changes: 16 additions & 0 deletions tests/ui/match_wildcard_for_single_variants.fixed
Expand Up @@ -108,4 +108,20 @@ fn main() {
Bar::B => (),
_ => (),
};

//#6984
{
#![allow(clippy::manual_non_exhaustive)]
pub enum Enum {
A,
B,
#[doc(hidden)]
__Private,
}
match Enum::A {
Enum::A => (),
Enum::B => (),
_ => (),
}
}
}
16 changes: 16 additions & 0 deletions tests/ui/match_wildcard_for_single_variants.rs
Expand Up @@ -108,4 +108,20 @@ fn main() {
Bar::B => (),
_ => (),
};

//#6984
{
#![allow(clippy::manual_non_exhaustive)]
pub enum Enum {
A,
B,
#[doc(hidden)]
__Private,
}
match Enum::A {
Enum::A => (),
Enum::B => (),
_ => (),
}
}
}

0 comments on commit 8abab55

Please sign in to comment.