Skip to content

Commit 16f15ce

Browse files
committed
rustc: Add lint for snake_case functions & methods.
1 parent 874b56d commit 16f15ce

File tree

2 files changed

+118
-14
lines changed

2 files changed

+118
-14
lines changed

src/librustc/middle/lint.rs

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub enum Lint {
8383
NonCamelCaseTypes,
8484
NonUppercaseStatics,
8585
NonUppercasePatternStatics,
86+
NonSnakeCaseFunctions,
8687
UppercaseVariables,
8788
UnnecessaryParens,
8889
TypeLimits,
@@ -220,6 +221,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
220221
default: Warn
221222
}),
222223

224+
("non_snake_case_functions",
225+
LintSpec {
226+
lint: NonSnakeCaseFunctions,
227+
desc: "methods and functions should have snake case names",
228+
default: Warn
229+
}),
230+
223231
("uppercase_variables",
224232
LintSpec {
225233
lint: UppercaseVariables,
@@ -1342,6 +1350,30 @@ fn check_item_non_camel_case_types(cx: &Context, it: &ast::Item) {
13421350
}
13431351
}
13441352

1353+
fn check_snake_case(cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
1354+
fn is_snake_case(ident: ast::Ident) -> bool {
1355+
let ident = token::get_ident(ident);
1356+
assert!(!ident.get().is_empty());
1357+
let ident = ident.get().trim_chars('_');
1358+
1359+
let mut allow_underscore = true;
1360+
ident.chars().all(|c| {
1361+
allow_underscore = match c {
1362+
c if c.is_lowercase() || c.is_digit() => true,
1363+
'_' if allow_underscore => false,
1364+
_ => return false,
1365+
};
1366+
true
1367+
})
1368+
}
1369+
1370+
if !is_snake_case(ident) {
1371+
cx.span_lint(NonSnakeCaseFunctions, span,
1372+
format!("{} `{}` should have a snake case identifier",
1373+
sort, token::get_ident(ident)).as_slice());
1374+
}
1375+
}
1376+
13451377
fn check_item_non_uppercase_statics(cx: &Context, it: &ast::Item) {
13461378
match it.node {
13471379
// only check static constants
@@ -1618,7 +1650,27 @@ fn check_missing_doc_item(cx: &Context, it: &ast::Item) {
16181650
desc);
16191651
}
16201652

1653+
#[deriving(Eq)]
1654+
enum MethodContext {
1655+
TraitDefaultImpl,
1656+
TraitImpl,
1657+
PlainImpl
1658+
}
1659+
16211660
fn check_missing_doc_method(cx: &Context, m: &ast::Method) {
1661+
// If the method is an impl for a trait, don't doc.
1662+
if method_context(cx, m) == TraitImpl { return; }
1663+
1664+
// Otherwise, doc according to privacy. This will also check
1665+
// doc for default methods defined on traits.
1666+
check_missing_doc_attrs(cx,
1667+
Some(m.id),
1668+
m.attrs.as_slice(),
1669+
m.span,
1670+
"a method");
1671+
}
1672+
1673+
fn method_context(cx: &Context, m: &ast::Method) -> MethodContext {
16221674
let did = ast::DefId {
16231675
krate: ast::LOCAL_CRATE,
16241676
node: m.id
@@ -1628,25 +1680,16 @@ fn check_missing_doc_method(cx: &Context, m: &ast::Method) {
16281680
None => cx.tcx.sess.span_bug(m.span, "missing method descriptor?!"),
16291681
Some(md) => {
16301682
match md.container {
1631-
// Always check default methods defined on traits.
1632-
ty::TraitContainer(..) => {}
1633-
// For methods defined on impls, it depends on whether
1634-
// it is an implementation for a trait or is a plain
1635-
// impl.
1683+
ty::TraitContainer(..) => TraitDefaultImpl,
16361684
ty::ImplContainer(cid) => {
16371685
match ty::impl_trait_ref(cx.tcx, cid) {
1638-
Some(..) => return, // impl for trait: don't doc
1639-
None => {} // plain impl: doc according to privacy
1686+
Some(..) => TraitImpl,
1687+
None => PlainImpl
16401688
}
16411689
}
16421690
}
16431691
}
16441692
}
1645-
check_missing_doc_attrs(cx,
1646-
Some(m.id),
1647-
m.attrs.as_slice(),
1648-
m.span,
1649-
"a method");
16501693
}
16511694

16521695
fn check_missing_doc_ty_method(cx: &Context, tm: &ast::TypeMethod) {
@@ -1889,26 +1932,36 @@ impl<'a> Visitor<()> for Context<'a> {
18891932
}
18901933

18911934
match *fk {
1892-
visit::FkMethod(_, _, m) => {
1935+
visit::FkMethod(ident, _, m) => {
18931936
self.with_lint_attrs(m.attrs.as_slice(), |cx| {
18941937
check_missing_doc_method(cx, m);
18951938
check_attrs_usage(cx, m.attrs.as_slice());
18961939

1940+
match method_context(cx, m) {
1941+
PlainImpl => check_snake_case(cx, "method", ident, span),
1942+
TraitDefaultImpl => check_snake_case(cx, "trait method", ident, span),
1943+
_ => (),
1944+
}
1945+
18971946
cx.visit_ids(|v| {
18981947
v.visit_fn(fk, decl, body, span, id, ());
18991948
});
19001949
recurse(cx);
19011950
})
1951+
},
1952+
visit::FkItemFn(ident, _, _, _) => {
1953+
check_snake_case(self, "function", ident, span);
1954+
recurse(self);
19021955
}
19031956
_ => recurse(self),
19041957
}
19051958
}
19061959

1907-
19081960
fn visit_ty_method(&mut self, t: &ast::TypeMethod, _: ()) {
19091961
self.with_lint_attrs(t.attrs.as_slice(), |cx| {
19101962
check_missing_doc_ty_method(cx, t);
19111963
check_attrs_usage(cx, t.attrs.as_slice());
1964+
check_snake_case(cx, "trait method", t.ident, t.span);
19121965

19131966
visit::walk_ty_method(cx, t, ());
19141967
})
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![deny(non_snake_case_functions)]
12+
#![allow(dead_code)]
13+
14+
struct Foo;
15+
16+
impl Foo {
17+
fn Foo_Method() {}
18+
//~^ ERROR method `Foo_Method` should have a snake case identifier
19+
20+
// Don't allow two underscores in a row
21+
fn foo__method(&self) {}
22+
//~^ ERROR method `foo__method` should have a snake case identifier
23+
24+
pub fn xyZ(&mut self) {}
25+
//~^ ERROR method `xyZ` should have a snake case identifier
26+
}
27+
28+
trait X {
29+
fn ABC();
30+
//~^ ERROR trait method `ABC` should have a snake case identifier
31+
32+
fn a_b_C(&self) {}
33+
//~^ ERROR trait method `a_b_C` should have a snake case identifier
34+
35+
fn something__else(&mut self);
36+
//~^ ERROR trait method `something__else` should have a snake case identifier
37+
}
38+
39+
impl X for Foo {
40+
// These errors should be caught at the trait definition not the impl
41+
fn ABC() {}
42+
fn something__else(&mut self) {}
43+
}
44+
45+
fn Cookie() {}
46+
//~^ ERROR function `Cookie` should have a snake case identifier
47+
48+
pub fn bi_S_Cuit() {}
49+
//~^ ERROR function `bi_S_Cuit` should have a snake case identifier
50+
51+
fn main() { }

0 commit comments

Comments
 (0)