From 121e65f14186c67c51e3ddf669f8dc82322d51b8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 23 Oct 2020 18:17:00 -0400 Subject: [PATCH 1/2] Fix inconsistencies in handling of inert attributes on statements When the 'early' and 'late' visitors visit an attribute target, they activate any lint attributes (e.g. `#[allow]`) that apply to it. This can affect warnings emitted on sibiling attributes. For example, the following code does not produce an `unused_attributes` for `#[inline]`, since the sibiling `#[allow(unused_attributes)]` suppressed the warning. ```rust trait Foo { #[allow(unused_attributes)] #[inline] fn first(); #[inline] #[allow(unused_attributes)] fn second(); } ``` However, we do not do this for statements - instead, the lint attributes only become active when we visit the struct nested inside `StmtKind` (e.g. `Item`). Currently, this is difficult to observe due to another issue - the `HasAttrs` impl for `StmtKind` ignores attributes for `StmtKind::Item`. As a result, the `unused_doc_comments` lint will never see attributes on item statements. This commit makes two interrelated fixes to the handling of inert (non-proc-macro) attributes on statements: * The `HasAttr` impl for `StmtKind` now returns attributes for `StmtKind::Item`, treating it just like every other `StmtKind` variant. The only place relying on the old behavior was macro which has been updated to explicitly ignore attributes on item statements. This allows the `unused_doc_comments` lint to fire for item statements. * The `early` and `late` lint visitors now activate lint attributes when invoking the callback for `Stmt`. This ensures that a lint attribute (e.g. `#[allow(unused_doc_comments)]`) can be applied to sibiling attributes on an item statement. The `unused_doc_comments` lint now fires on a number of items in the stnadard library. I've added `#[allow(unused_doc_comments)]` to these items. --- compiler/rustc_ast/src/attr/mod.rs | 6 ++- compiler/rustc_expand/src/expand.rs | 3 +- compiler/rustc_hir/src/hir.rs | 6 +-- compiler/rustc_lint/src/early.rs | 19 ++++++++- compiler/rustc_lint/src/late.rs | 13 +++--- compiler/rustc_lint/src/levels.rs | 7 ++++ compiler/rustc_middle/src/hir/map/mod.rs | 2 +- src/test/ui/allow-doc-comments.rs | 12 ++++++ src/test/ui/lint/reasons-forbidden.rs | 12 ++++++ src/test/ui/lint/reasons-forbidden.stderr | 41 +++++++++++++++++-- src/test/ui/macros/macro-literal.rs | 1 + src/test/ui/macros/macro-nested_expr.rs | 1 + src/test/ui/useless-comment.rs | 9 ++++ src/test/ui/useless-comment.stderr | 26 +++++++++++- .../clippy/clippy_lints/src/utils/author.rs | 2 +- .../clippy_lints/src/utils/inspector.rs | 2 +- 16 files changed, 140 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/allow-doc-comments.rs diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 8351be222f6bd..146948ed25d2f 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -623,7 +623,8 @@ impl HasAttrs for StmtKind { match *self { StmtKind::Local(ref local) => local.attrs(), StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), - StmtKind::Empty | StmtKind::Item(..) => &[], + StmtKind::Item(ref item) => item.attrs(), + StmtKind::Empty => &[], StmtKind::MacCall(ref mac) => mac.attrs.attrs(), } } @@ -632,7 +633,8 @@ impl HasAttrs for StmtKind { match self { StmtKind::Local(local) => local.visit_attrs(f), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), - StmtKind::Empty | StmtKind::Item(..) => {} + StmtKind::Item(item) => item.visit_attrs(f), + StmtKind::Empty => {} StmtKind::MacCall(mac) => { mac.attrs.visit_attrs(f); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0b43225a242f7..a4154b12751fe 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1357,7 +1357,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // we'll expand attributes on expressions separately if !stmt.is_expr() { let (attr, derives, after_derive) = if stmt.is_item() { - self.classify_item(&mut stmt) + // FIXME: Handle custom attributes on statements (#15701) + (None, vec![], false) } else { // ignore derives on non-item statements so it falls through // to the unused-attributes lint diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 65b96da95e972..56b5b5a1030c1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1099,11 +1099,11 @@ pub enum StmtKind<'hir> { Semi(&'hir Expr<'hir>), } -impl StmtKind<'hir> { - pub fn attrs(&self) -> &'hir [Attribute] { +impl<'hir> StmtKind<'hir> { + pub fn attrs(&self, get_item: impl FnOnce(ItemId) -> &'hir Item<'hir>) -> &'hir [Attribute] { match *self { StmtKind::Local(ref l) => &l.attrs, - StmtKind::Item(_) => &[], + StmtKind::Item(ref item_id) => &get_item(*item_id).attrs, StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => &e.attrs, } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 4c8baa49edf61..9aeeb6277924e 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -18,6 +18,7 @@ use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use rustc_ast as ast; use rustc_ast::visit as ast_visit; +use rustc_attr::HasAttrs; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -119,8 +120,22 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_stmt(&mut self, s: &'a ast::Stmt) { - run_early_pass!(self, check_stmt, s); - self.check_id(s.id); + // Add the statement's lint attributes to our + // current state when checking the statement itself. + // This allows us to handle attributes like + // `#[allow(unused_doc_comments)]`, which apply to + // sibling attributes on the same target + // + // Note that statements get their attributes from + // the AST struct that they wrap (e.g. an item) + self.with_lint_attrs(s.id, s.attrs(), |cx| { + run_early_pass!(cx, check_stmt, s); + cx.check_id(s.id); + }); + // The visitor for the AST struct wrapped + // by the statement (e.g. `Item`) will call + // `with_lint_attrs`, so do this walk + // outside of the above `with_lint_attrs` call ast_visit::walk_stmt(self, s); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index a6c04fb0b4c84..015e109871182 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -174,12 +174,13 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { - // statement attributes are actually just attributes on one of - // - item - // - local - // - expression - // so we keep track of lint levels there - lint_callback!(self, check_stmt, s); + let get_item = |id: hir::ItemId| self.context.tcx.hir().item(id.id); + let attrs = &s.kind.attrs(get_item); + // See `EarlyContextAndPass::visit_stmt` for an explanation + // of why we call `walk_stmt` outside of `with_lint_attrs` + self.with_lint_attrs(s.hir_id, attrs, |cx| { + lint_callback!(cx, check_stmt, s); + }); hir_visit::walk_stmt(self, s); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 222333a578b7d..f36f598ade2de 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -562,6 +562,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { }) } + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + // We will call `with_lint_attrs` when we walk + // the `StmtKind`. The outer statement itself doesn't + // define the lint levels. + intravisit::walk_stmt(self, e); + } + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { self.with_lint_attrs(e.hir_id, &e.attrs, |builder| { intravisit::walk_expr(builder, e); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 57f03c2a5cf54..106fa8c78fa28 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -816,7 +816,7 @@ impl<'hir> Map<'hir> { Some(Node::Variant(ref v)) => Some(&v.attrs[..]), Some(Node::Field(ref f)) => Some(&f.attrs[..]), Some(Node::Expr(ref e)) => Some(&*e.attrs), - Some(Node::Stmt(ref s)) => Some(s.kind.attrs()), + Some(Node::Stmt(ref s)) => Some(s.kind.attrs(|id| self.item(id.id))), Some(Node::Arm(ref a)) => Some(&*a.attrs), Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), // Unit/tuple structs/variants take the attributes straight from diff --git a/src/test/ui/allow-doc-comments.rs b/src/test/ui/allow-doc-comments.rs new file mode 100644 index 0000000000000..8f7ef7fc587ac --- /dev/null +++ b/src/test/ui/allow-doc-comments.rs @@ -0,0 +1,12 @@ +// check-pass + +fn main() { + + #[allow(unused_doc_comments)] + /// A doc comment + fn bar() {} + + /// Another doc comment + #[allow(unused_doc_comments)] + struct Foo {} +} diff --git a/src/test/ui/lint/reasons-forbidden.rs b/src/test/ui/lint/reasons-forbidden.rs index 6a71176aabb15..5f6764c789d00 100644 --- a/src/test/ui/lint/reasons-forbidden.rs +++ b/src/test/ui/lint/reasons-forbidden.rs @@ -5,6 +5,9 @@ //~^ NOTE `forbid` level set here //~| NOTE `forbid` level set here //~| NOTE `forbid` level set here + //~| NOTE `forbid` level set here + //~| NOTE `forbid` level set here + //~| NOTE `forbid` level set here reason = "our errors & omissions insurance policy doesn't cover unsafe Rust" )] @@ -17,9 +20,18 @@ fn main() { //~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) //~| NOTE overruled by previous forbid //~| NOTE overruled by previous forbid //~| NOTE overruled by previous forbid + //~| NOTE overruled by previous forbid + //~| NOTE overruled by previous forbid + //~| NOTE overruled by previous forbid + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust diff --git a/src/test/ui/lint/reasons-forbidden.stderr b/src/test/ui/lint/reasons-forbidden.stderr index 0954edea7378c..eed9c8d566ecd 100644 --- a/src/test/ui/lint/reasons-forbidden.stderr +++ b/src/test/ui/lint/reasons-forbidden.stderr @@ -1,5 +1,5 @@ error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:16:13 + --> $DIR/reasons-forbidden.rs:19:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -10,7 +10,7 @@ LL | #[allow(unsafe_code)] = note: our errors & omissions insurance policy doesn't cover unsafe Rust error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:16:13 + --> $DIR/reasons-forbidden.rs:19:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -21,7 +21,7 @@ LL | #[allow(unsafe_code)] = note: our errors & omissions insurance policy doesn't cover unsafe Rust error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:16:13 + --> $DIR/reasons-forbidden.rs:19:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -31,6 +31,39 @@ LL | #[allow(unsafe_code)] | = note: our errors & omissions insurance policy doesn't cover unsafe Rust -error: aborting due to 3 previous errors +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:19:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:19:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:19:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/macros/macro-literal.rs b/src/test/ui/macros/macro-literal.rs index e08d0a67b4345..92d9699796fe9 100644 --- a/src/test/ui/macros/macro-literal.rs +++ b/src/test/ui/macros/macro-literal.rs @@ -67,6 +67,7 @@ macro_rules! match_produced_attr { ($lit: literal) => { // Struct with doc comment passed via $literal #[doc = $lit] + #[allow(unused_doc_comments)] struct LiteralProduced; }; ($expr: expr) => { diff --git a/src/test/ui/macros/macro-nested_expr.rs b/src/test/ui/macros/macro-nested_expr.rs index f1433cbf4f910..dedd5bff8a502 100644 --- a/src/test/ui/macros/macro-nested_expr.rs +++ b/src/test/ui/macros/macro-nested_expr.rs @@ -6,6 +6,7 @@ pub macro m($inner_str:expr) { #[doc = $inner_str] + #[allow(unused_doc_comments)] struct S; } diff --git a/src/test/ui/useless-comment.rs b/src/test/ui/useless-comment.rs index 7d2e5ab6f2b7f..87ebaafee4c8c 100644 --- a/src/test/ui/useless-comment.rs +++ b/src/test/ui/useless-comment.rs @@ -38,6 +38,15 @@ fn foo() { { } + + /// foo //~ ERROR unused doc comment + struct Foo {} + + /// bar //~ ERROR unused doc comment + struct Bar {}; + + /// my_fn //~ ERROR unused_doc_comment + fn my_fn() {} } fn main() { diff --git a/src/test/ui/useless-comment.stderr b/src/test/ui/useless-comment.stderr index 5a0af8db7c504..2e83d6d312afc 100644 --- a/src/test/ui/useless-comment.stderr +++ b/src/test/ui/useless-comment.stderr @@ -90,5 +90,29 @@ LL | | LL | | } | |_____- rustdoc does not generate documentation for expressions -error: aborting due to 10 previous errors +error: unused doc comment + --> $DIR/useless-comment.rs:42:5 + | +LL | /// foo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Foo {} + | ------------- rustdoc does not generate documentation for inner items + +error: unused doc comment + --> $DIR/useless-comment.rs:45:5 + | +LL | /// bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Bar {}; + | -------------- rustdoc does not generate documentation for inner items + +error: unused doc comment + --> $DIR/useless-comment.rs:48:5 + | +LL | /// my_fn + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn my_fn() {} + | ------------- rustdoc does not generate documentation for inner items + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 89425437eeead..7250de3a41c04 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for Author { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { - if !has_attr(cx.sess(), stmt.kind.attrs()) { + if !has_attr(cx.sess(), stmt.kind.attrs(|id| cx.tcx.hir().item(id.id))) { return; } prelude(); diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 93bd82994466a..4fbfb3be32cbf 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { - if !has_attr(cx.sess(), stmt.kind.attrs()) { + if !has_attr(cx.sess(), stmt.kind.attrs(|id| cx.tcx.hir().item(id.id))) { return; } match stmt.kind { From 23f4e640a26f0e8f423e919249ea9d9bd10a2808 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 23 Oct 2020 18:33:59 -0400 Subject: [PATCH 2/2] Convert unused doc comments to regular comments --- compiler/rustc_ast/src/util/comments.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 10 +-- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_index/src/bit_set.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 20 ++--- compiler/rustc_middle/src/mir/query.rs | 6 +- compiler/rustc_mir/src/interpret/operand.rs | 2 +- .../rustc_mir/src/transform/simplify_try.rs | 10 +-- .../src/thir/pattern/_match.rs | 6 +- .../rustc_parse/src/parser/nonterminal.rs | 2 +- compiler/rustc_passes/src/region.rs | 80 +++++++++---------- compiler/rustc_resolve/src/imports.rs | 2 +- .../src/traits/error_reporting/mod.rs | 4 +- library/alloc/src/collections/vec_deque.rs | 8 +- library/alloc/src/vec.rs | 4 +- library/alloc/tests/vec.rs | 4 +- library/core/src/intrinsics.rs | 3 +- library/core/src/iter/mod.rs | 2 +- library/core/src/mem/maybe_uninit.rs | 2 +- library/core/src/panic.rs | 4 +- library/core/src/ptr/mod.rs | 28 +++---- library/core/src/time.rs | 20 ++--- library/proc_macro/src/bridge/scoped_cell.rs | 6 +- library/std/src/io/buffered/bufwriter.rs | 6 +- library/std/src/keyword_docs.rs | 14 ++-- library/std/src/net/ip.rs | 2 +- library/std/src/net/parser.rs | 10 +-- src/librustdoc/clean/types.rs | 20 ++--- src/librustdoc/html/render/mod.rs | 2 +- 29 files changed, 143 insertions(+), 142 deletions(-) diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index e97c8cc4562f6..7b47cc5a6982f 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -26,7 +26,7 @@ pub struct Comment { /// Makes a doc string more presentable to users. /// Used by rustdoc and perhaps other tools, but not by rustc. pub fn beautify_doc_string(data: Symbol) -> String { - /// remove whitespace-only lines from the start/end of lines + // remove whitespace-only lines from the start/end of lines fn vertical_trim(lines: Vec) -> Vec { let mut i = 0; let mut j = lines.len(); @@ -50,7 +50,7 @@ pub fn beautify_doc_string(data: Symbol) -> String { lines[i..j].to_vec() } - /// remove a "[ \t]*\*" block from each line, if possible + // remove a "[ \t]*\*" block from each line, if possible fn horizontal_trim(lines: Vec) -> Vec { let mut i = usize::MAX; let mut can_trim = true; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a28d022c66139..24a423f2c7b26 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -419,11 +419,11 @@ impl Visitor<'_> for ImplTraitTypeIdVisitor<'_> { impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_crate(mut self, c: &Crate) -> hir::Crate<'hir> { - /// Full-crate AST visitor that inserts into a fresh - /// `LoweringContext` any information that may be - /// needed from arbitrary locations in the crate, - /// e.g., the number of lifetime generic parameters - /// declared for every type and trait definition. + // Full-crate AST visitor that inserts into a fresh + // `LoweringContext` any information that may be + // needed from arbitrary locations in the crate, + // e.g., the number of lifetime generic parameters + // declared for every type and trait definition. struct MiscCollector<'tcx, 'lowering, 'hir> { lctx: &'tcx mut LoweringContext<'lowering, 'hir>, hir_id_owner: Option, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index b5155f8e910d7..feff25cbf1bae 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1160,7 +1160,7 @@ impl EmitterWriter { // `max_line_num_len` let padding = " ".repeat(padding + label.len() + 5); - /// Returns `override` if it is present and `style` is `NoStyle` or `style` otherwise + // Returns `override` if it is present and `style` is `NoStyle` or `style` otherwise fn style_or_override(style: Style, override_: Option