From a076fef2b647399f2fb0575830fb07320fb3b6f5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 30 Sep 2013 17:44:58 +0200 Subject: [PATCH 1/9] Add new lint: non_uppercase_pattern_statics, for #7526. This tries to warn about code like: ```rust match (0,0) { (0, aha) => { ... }, ... } ``` where `aha` is actually a static constant, not a binding. --- src/librustc/lib/llvm.rs | 1 + src/librustc/middle/check_match.rs | 20 ++++++++ src/librustc/middle/lint.rs | 8 ++++ src/librustc/middle/trans/cabi_arm.rs | 2 + src/librustc/middle/trans/cabi_mips.rs | 1 + src/librustc/middle/trans/cabi_x86_64.rs | 2 + src/librustc/middle/trans/intrinsic.rs | 2 + src/librustc/middle/trans/type_.rs | 1 + src/libstd/num/f32.rs | 1 + src/libstd/num/f64.rs | 1 + .../compile-fail/match-static-const-lc.rs | 43 +++++++++++++++++ .../run-pass/match-static-const-rename.rs | 47 +++++++++++++++++++ 12 files changed, 129 insertions(+) create mode 100644 src/test/compile-fail/match-static-const-lc.rs create mode 100644 src/test/run-pass/match-static-const-rename.rs diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 49798288d40d0..0ce21bdf18ef9 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -11,6 +11,7 @@ // LLVM wrappers are intended to be called from trans, // which already runs in a #[fixed_stack_segment] #[allow(cstack)]; +#[allow(non_uppercase_pattern_statics)]; use std::c_str::ToCStr; use std::hashmap::HashMap; diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c9eded645fa2d..573d2a529d4b2 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -11,6 +11,7 @@ use middle::const_eval::{compare_const_vals, lookup_const_by_id}; use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float}; +use middle::lint::non_uppercase_pattern_statics; use middle::pat_util::*; use middle::ty::*; use middle::ty; @@ -133,11 +134,30 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) { _ => false } }; + + // Lint for constants that look like binding identifiers (#7526) + let pat_matches_non_uppercase_static: &fn(@Pat) = |p| { + let msg = "static constant in pattern should have an uppercase identifier"; + match (&p.node, cx.tcx.def_map.find(&p.id)) { + (&PatIdent(_, ref path, _), Some(&DefStatic(_, false))) => { + // last identifier alone is right choice for this lint. + let ident = path.segments.last().identifier; + let s = cx.tcx.sess.str_of(ident); + if s.iter().any(|c| c.is_lowercase()) { + cx.tcx.sess.add_lint(non_uppercase_pattern_statics, + p.id, path.span, msg.to_owned()); + } + } + _ => {} + } + }; + do walk_pat(*pat) |p| { if pat_matches_nan(p) { cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \ use the is_nan method in a guard instead"); } + pat_matches_non_uppercase_static(p); true }; diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 3c6ebc9311db5..340cf361a08d4 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -83,6 +83,7 @@ pub enum lint { unrecognized_lint, non_camel_case_types, non_uppercase_statics, + non_uppercase_pattern_statics, type_limits, unused_unsafe, @@ -209,6 +210,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ default: allow }), + ("non_uppercase_pattern_statics", + LintSpec { + lint: non_uppercase_pattern_statics, + desc: "static constants in match patterns should be uppercased", + default: warn + }), + ("managed_heap_memory", LintSpec { lint: managed_heap_memory, diff --git a/src/librustc/middle/trans/cabi_arm.rs b/src/librustc/middle/trans/cabi_arm.rs index 19f0b9b78eb35..2ffff5b58381b 100644 --- a/src/librustc/middle/trans/cabi_arm.rs +++ b/src/librustc/middle/trans/cabi_arm.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(non_uppercase_pattern_statics)]; + use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array}; use lib::llvm::{Attribute, StructRetAttribute}; use middle::trans::cabi::{FnType, LLVMType}; diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs index 4577bf11b84de..be4a6a6ec18f1 100644 --- a/src/librustc/middle/trans/cabi_mips.rs +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(non_uppercase_pattern_statics)]; use std::libc::c_uint; use std::num; diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 179366878418f..7b666ea2448b4 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -11,6 +11,8 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp +#[allow(non_uppercase_pattern_statics)]; + use lib::llvm::{llvm, Integer, Pointer, Float, Double}; use lib::llvm::{Struct, Array, Attribute}; use lib::llvm::{StructRetAttribute, ByValAttribute}; diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index d17773d3302f1..0364251f520b1 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(non_uppercase_pattern_statics)]; + use back::{abi}; use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; use lib::llvm::{ValueRef, Pointer}; diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 0954302ba81f4..6ccfd85712607 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(non_uppercase_pattern_statics)]; use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind}; use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index afa1acd08970a..be8aa369b4bed 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -11,6 +11,7 @@ //! Operations and constants for `f32` #[allow(missing_doc)]; #[allow(non_uppercase_statics)]; +#[allow(non_uppercase_pattern_statics)]; use default::Default; use libc::c_int; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 5dbeb6c298f8f..18d0037469d20 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -12,6 +12,7 @@ #[allow(missing_doc)]; #[allow(non_uppercase_statics)]; +#[allow(non_uppercase_pattern_statics)]; use default::Default; use libc::c_int; diff --git a/src/test/compile-fail/match-static-const-lc.rs b/src/test/compile-fail/match-static-const-lc.rs new file mode 100644 index 0000000000000..02be27b7ce283 --- /dev/null +++ b/src/test/compile-fail/match-static-const-lc.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #7526: lowercase static constants in patterns look like bindings + +#[deny(non_uppercase_pattern_statics)]; + +pub static a : int = 97; + +fn f() { + let r = match (0,0) { + (0, a) => 0, + //~^ ERROR static constant in pattern should have an uppercase id + (x, y) => 1 + x + y, + }; + assert!(r == 1); +} + +mod m { + pub static aha : int = 7; +} + +fn g() { + use m::aha; + let r = match (0,0) { + (0, aha) => 0, + //~^ ERROR static constant in pattern should have an uppercase id + (x, y) => 1 + x + y, + }; + assert!(r == 1); +} + +fn main () { + f(); + g(); +} diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs new file mode 100644 index 0000000000000..305a20b6642e2 --- /dev/null +++ b/src/test/run-pass/match-static-const-rename.rs @@ -0,0 +1,47 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #7526: lowercase static constants in patterns look like bindings + +// This is similar to compile-fail/match-static-const-lc, except it +// shows the expected usual workaround (choosing a different name for +// the static definition) and also demonstrates that one can work +// around this problem locally by reanming the constant in the `use` +// form to an uppercase identifier that placates the lint. + +#[deny(non_uppercase_pattern_statics)]; + +pub static A : int = 97; + +fn f() { + let r = match (0,0) { + (0, A) => 0, + (x, y) => 1 + x + y, + }; + assert!(r == 1); +} + +mod m { + pub static aha : int = 7; +} + +fn g() { + use AHA = m::aha; + let r = match (0,0) { + (0, AHA) => 0, + (x, y) => 1 + x + y, + }; + assert!(r == 1); +} + +fn main () { + f(); + g(); +} From 924674202ed7677e58ab01d75668d633b068f8dd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 01:51:21 +0200 Subject: [PATCH 2/9] Throwing in another interesting test case: There is no need to warn about constants that are (non-trivial) paths rather than just identifiers, regardless of what case their characters are. --- src/test/run-pass/match-static-const-rename.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index 305a20b6642e2..2bf16791b42cb 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -41,7 +41,16 @@ fn g() { assert!(r == 1); } +fn h() { + let r = match (0,0) { + (0, m::aha) => 0, + (x, y) => 1 + x + y, + }; + assert!(r == 1); +} + fn main () { f(); g(); + h(); } From c0599b1bbbf9e4dcfb05a06aa2eef900aa9e4965 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 01:55:37 +0200 Subject: [PATCH 3/9] Fix typo in comment. --- src/test/run-pass/match-static-const-rename.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index 2bf16791b42cb..0d3dd25ef9c98 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -13,7 +13,7 @@ // This is similar to compile-fail/match-static-const-lc, except it // shows the expected usual workaround (choosing a different name for // the static definition) and also demonstrates that one can work -// around this problem locally by reanming the constant in the `use` +// around this problem locally by renaming the constant in the `use` // form to an uppercase identifier that placates the lint. #[deny(non_uppercase_pattern_statics)]; From e2be7aca08f5eac1c0a0eae589c916fc39d57193 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 02:03:43 +0200 Subject: [PATCH 4/9] Expanded test to clarify that the constants *are* matching when they should. --- src/test/run-pass/match-static-const-rename.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index 0d3dd25ef9c98..3da4e0505bb07 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -26,6 +26,11 @@ fn f() { (x, y) => 1 + x + y, }; assert!(r == 1); + let r = match (0,97) { + (0, A) => 0, + (x, y) => 1 + x + y, + }; + assert!(r == 0); } mod m { @@ -39,6 +44,11 @@ fn g() { (x, y) => 1 + x + y, }; assert!(r == 1); + let r = match (0,7) { + (0, AHA) => 0, + (x, y) => 1 + x + y, + }; + assert!(r == 0); } fn h() { @@ -47,6 +57,11 @@ fn h() { (x, y) => 1 + x + y, }; assert!(r == 1); + let r = match (0,7) { + (0, m::aha) => 0, + (x, y) => 1 + x + y, + }; + assert!(r == 0); } fn main () { From 8d6f4c207a5a9cf8721d4cd2c884390eb3d5e61f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 02:55:51 +0200 Subject: [PATCH 5/9] Workaround conflict between all-uppercase static and NaN definition. --- src/test/compile-fail/issue-6804.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs index db72740f483c2..e239385fa5867 100644 --- a/src/test/compile-fail/issue-6804.rs +++ b/src/test/compile-fail/issue-6804.rs @@ -1,3 +1,5 @@ +#[allow(non_uppercase_pattern_statics)]; + // Matching against NaN should result in a warning use std::float::NaN; From 155857f5488f2b6ca04c3abe6ac22833028c1497 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 03:10:19 +0200 Subject: [PATCH 6/9] Revise error message to use phrase "all caps" instead of "uppercase". This is to clarify that the lint is checking for THIS_THING and not This. --- src/librustc/middle/check_match.rs | 2 +- src/librustc/middle/lint.rs | 2 +- src/test/compile-fail/match-static-const-lc.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 573d2a529d4b2..4856bb6c7fc09 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -137,7 +137,7 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) { // Lint for constants that look like binding identifiers (#7526) let pat_matches_non_uppercase_static: &fn(@Pat) = |p| { - let msg = "static constant in pattern should have an uppercase identifier"; + let msg = "static constant in pattern should be all caps"; match (&p.node, cx.tcx.def_map.find(&p.id)) { (&PatIdent(_, ref path, _), Some(&DefStatic(_, false))) => { // last identifier alone is right choice for this lint. diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 340cf361a08d4..6f022aa31bd71 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -213,7 +213,7 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ ("non_uppercase_pattern_statics", LintSpec { lint: non_uppercase_pattern_statics, - desc: "static constants in match patterns should be uppercased", + desc: "static constants in match patterns should be all caps", default: warn }), diff --git a/src/test/compile-fail/match-static-const-lc.rs b/src/test/compile-fail/match-static-const-lc.rs index 02be27b7ce283..4e9203496de3e 100644 --- a/src/test/compile-fail/match-static-const-lc.rs +++ b/src/test/compile-fail/match-static-const-lc.rs @@ -17,7 +17,7 @@ pub static a : int = 97; fn f() { let r = match (0,0) { (0, a) => 0, - //~^ ERROR static constant in pattern should have an uppercase id + //~^ ERROR static constant in pattern should be all caps (x, y) => 1 + x + y, }; assert!(r == 1); @@ -31,7 +31,7 @@ fn g() { use m::aha; let r = match (0,0) { (0, aha) => 0, - //~^ ERROR static constant in pattern should have an uppercase id + //~^ ERROR static constant in pattern should be all caps (x, y) => 1 + x + y, }; assert!(r == 1); From 06f46902caf4a98132229237820d482f99e147ea Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 18:02:11 +0200 Subject: [PATCH 7/9] fix tests for check-fast. --- src/test/compile-fail/match-static-const-lc.rs | 17 ++++++++++++++++- src/test/run-pass/match-static-const-rename.rs | 6 +++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/match-static-const-lc.rs b/src/test/compile-fail/match-static-const-lc.rs index 4e9203496de3e..1cdceaca6b4b5 100644 --- a/src/test/compile-fail/match-static-const-lc.rs +++ b/src/test/compile-fail/match-static-const-lc.rs @@ -28,7 +28,7 @@ mod m { } fn g() { - use m::aha; + use self::m::aha; let r = match (0,0) { (0, aha) => 0, //~^ ERROR static constant in pattern should be all caps @@ -37,7 +37,22 @@ fn g() { assert!(r == 1); } +mod n { + pub static OKAY : int = 8; +} + +fn h() { + use not_okay = self::n::OKAY; + let r = match (0,0) { + (0, not_okay) => 0, + //~^ ERROR static constant in pattern should be all caps + (x, y) => 1 + x + y, + }; + assert!(r == 1); +} + fn main () { f(); g(); + h(); } diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index 3da4e0505bb07..b1c0525e95c62 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -38,7 +38,7 @@ mod m { } fn g() { - use AHA = m::aha; + use AHA = self::m::aha; let r = match (0,0) { (0, AHA) => 0, (x, y) => 1 + x + y, @@ -53,12 +53,12 @@ fn g() { fn h() { let r = match (0,0) { - (0, m::aha) => 0, + (0, self::m::aha) => 0, (x, y) => 1 + x + y, }; assert!(r == 1); let r = match (0,7) { - (0, m::aha) => 0, + (0, self::m::aha) => 0, (x, y) => 1 + x + y, }; assert!(r == 0); From 88d34ff2498e3ca8020c79c63d4501f749831f2f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 18:02:39 +0200 Subject: [PATCH 8/9] fix tests for check-fast. --- src/test/run-pass/match-static-const-rename.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index b1c0525e95c62..df62ba7298d29 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -64,7 +64,7 @@ fn h() { assert!(r == 0); } -fn main () { +pub fn main () { f(); g(); h(); From 2461b3102607c1cb4469c94bbe95d67db6c5e54d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 1 Oct 2013 18:03:26 +0200 Subject: [PATCH 9/9] incoporate suggestion from huonw to move code into lint.rs --- src/librustc/middle/check_match.rs | 19 ------------------- src/librustc/middle/lint.rs | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 4856bb6c7fc09..c891e57ff39aa 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -11,7 +11,6 @@ use middle::const_eval::{compare_const_vals, lookup_const_by_id}; use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float}; -use middle::lint::non_uppercase_pattern_statics; use middle::pat_util::*; use middle::ty::*; use middle::ty; @@ -135,29 +134,11 @@ pub fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) { } }; - // Lint for constants that look like binding identifiers (#7526) - let pat_matches_non_uppercase_static: &fn(@Pat) = |p| { - let msg = "static constant in pattern should be all caps"; - match (&p.node, cx.tcx.def_map.find(&p.id)) { - (&PatIdent(_, ref path, _), Some(&DefStatic(_, false))) => { - // last identifier alone is right choice for this lint. - let ident = path.segments.last().identifier; - let s = cx.tcx.sess.str_of(ident); - if s.iter().any(|c| c.is_lowercase()) { - cx.tcx.sess.add_lint(non_uppercase_pattern_statics, - p.id, path.span, msg.to_owned()); - } - } - _ => {} - } - }; - do walk_pat(*pat) |p| { if pat_matches_nan(p) { cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \ use the is_nan method in a guard instead"); } - pat_matches_non_uppercase_static(p); true }; diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 6f022aa31bd71..b3d595c6efb72 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -1118,6 +1118,22 @@ fn check_item_non_uppercase_statics(cx: &Context, it: &ast::item) { } } +fn check_pat_non_uppercase_statics(cx: &Context, p: &ast::Pat) { + // Lint for constants that look like binding identifiers (#7526) + match (&p.node, cx.tcx.def_map.find(&p.id)) { + (&ast::PatIdent(_, ref path, _), Some(&ast::DefStatic(_, false))) => { + // last identifier alone is right choice for this lint. + let ident = path.segments.last().identifier; + let s = cx.tcx.sess.str_of(ident); + if s.iter().any(|c| c.is_lowercase()) { + cx.span_lint(non_uppercase_pattern_statics, path.span, + "static constant in pattern should be all caps"); + } + } + _ => {} + } +} + struct UnusedUnsafeLintVisitor { stopping_on_items: bool } impl SubitemStoppableVisitor for UnusedUnsafeLintVisitor { @@ -1524,6 +1540,11 @@ struct LintCheckVisitor; impl Visitor<@mut Context> for LintCheckVisitor { + fn visit_pat(&mut self, p:@ast::Pat, cx: @mut Context) { + check_pat_non_uppercase_statics(cx, p); + visit::walk_pat(self, p, cx); + } + fn visit_item(&mut self, it:@ast::item, cx: @mut Context) { do cx.with_lint_attrs(it.attrs) {