@@ -47,8 +47,32 @@ declare_lint! {
4747 "type names prefixed/postfixed with their containing module's name"
4848}
4949
50+ /// **What it does:** Checks for modules that have the same name as their parent module
51+ ///
52+ /// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and again `mod foo { .. }` in `foo.rs`.
53+ /// The expectation is that items inside the inner `mod foo { .. }` are then available
54+ /// through `foo::x`, but they are only available through `foo::foo::x`.
55+ /// If this is done on purpose, it would be better to choose a more representative module name.
56+ ///
57+ /// **Known problems:** None.
58+ ///
59+ /// **Example:**
60+ /// ```rust
61+ /// // lib.rs
62+ /// mod foo;
63+ /// // foo.rs
64+ /// mod foo {
65+ /// ...
66+ /// }
67+ /// ```
68+ declare_lint ! {
69+ pub MODULE_INCEPTION ,
70+ Warn ,
71+ "modules that have the same name as their parent module"
72+ }
73+
5074pub struct EnumVariantNames {
51- modules : Vec < String > ,
75+ modules : Vec < ( InternedString , String ) > ,
5276 threshold : u64 ,
5377}
5478
@@ -60,7 +84,7 @@ impl EnumVariantNames {
6084
6185impl LintPass for EnumVariantNames {
6286 fn get_lints ( & self ) -> LintArray {
63- lint_array ! ( ENUM_VARIANT_NAMES , STUTTER )
87+ lint_array ! ( ENUM_VARIANT_NAMES , STUTTER , MODULE_INCEPTION )
6488 }
6589}
6690
@@ -170,25 +194,32 @@ impl EarlyLintPass for EnumVariantNames {
170194 let item_name = item. ident . name . as_str ( ) ;
171195 let item_name_chars = item_name. chars ( ) . count ( ) ;
172196 let item_camel = to_camel_case ( & item_name) ;
173- if item . vis == Visibility :: Public && !in_macro ( cx, item. span ) {
174- if let Some ( mod_camel) = self . modules . last ( ) {
197+ if !in_macro ( cx, item. span ) {
198+ if let Some ( & ( ref mod_name , ref mod_camel) ) = self . modules . last ( ) {
175199 // constants don't have surrounding modules
176200 if !mod_camel. is_empty ( ) {
177- let matching = partial_match ( mod_camel, & item_camel) ;
178- let rmatching = partial_rmatch ( mod_camel, & item_camel) ;
179- let nchars = mod_camel. chars ( ) . count ( ) ;
180- if matching == nchars {
181- span_lint ( cx, STUTTER , item. span , & format ! ( "Item name ({}) starts with its containing module's name ({})" , item_camel, mod_camel) ) ;
201+ if mod_name == & item_name {
202+ if let ItemKind :: Mod ( ..) = item. node {
203+ span_lint ( cx, MODULE_INCEPTION , item. span , "module has the same name as its containing module" ) ;
204+ }
182205 }
183- if rmatching == nchars {
184- span_lint ( cx, STUTTER , item. span , & format ! ( "Item name ({}) ends with its containing module's name ({})" , item_camel, mod_camel) ) ;
206+ if item. vis == Visibility :: Public {
207+ let matching = partial_match ( mod_camel, & item_camel) ;
208+ let rmatching = partial_rmatch ( mod_camel, & item_camel) ;
209+ let nchars = mod_camel. chars ( ) . count ( ) ;
210+ if matching == nchars {
211+ span_lint ( cx, STUTTER , item. span , "item name starts with its containing module's name" ) ;
212+ }
213+ if rmatching == nchars {
214+ span_lint ( cx, STUTTER , item. span , "item name ends with its containing module's name" ) ;
215+ }
185216 }
186217 }
187218 }
188219 }
189220 if let ItemKind :: Enum ( ref def, _) = item. node {
190221 check_variant ( cx, self . threshold , def, & item_name, item_name_chars, item. span ) ;
191222 }
192- self . modules . push ( item_camel) ;
223+ self . modules . push ( ( item_name , item_camel) ) ;
193224 }
194225}
0 commit comments