@@ -7,6 +7,7 @@ use rustc::middle::def_id::DefId;
77use rustc:: middle:: ty;
88use std:: borrow:: Cow ;
99use syntax:: ast:: Lit_ :: * ;
10+ use syntax:: ast;
1011
1112// module DefPaths for certain structs/enums we check for
1213pub const OPTION_PATH : [ & ' static str ; 3 ] = [ "core" , "option" , "Option" ] ;
@@ -15,15 +16,56 @@ pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
1516pub const VEC_PATH : [ & ' static str ; 3 ] = [ "collections" , "vec" , "Vec" ] ;
1617pub const LL_PATH : [ & ' static str ; 3 ] = [ "collections" , "linked_list" , "LinkedList" ] ;
1718
19+ /// Produce a nested chain of if-lets and ifs from the patterns:
20+ ///
21+ /// if_let_chain! {
22+ /// [
23+ /// Some(y) = x,
24+ /// y.len() == 2,
25+ /// Some(z) = y,
26+ /// ],
27+ /// {
28+ /// block
29+ /// }
30+ /// }
31+ ///
32+ /// becomes
33+ ///
34+ /// if let Some(y) = x {
35+ /// if y.len() == 2 {
36+ /// if let Some(z) = y {
37+ /// block
38+ /// }
39+ /// }
40+ /// }
41+ #[ macro_export]
42+ macro_rules! if_let_chain {
43+ ( [ let $pat: pat = $expr: expr, $( $tt: tt) +] , $block: block) => {
44+ if let $pat = $expr {
45+ if_let_chain!{ [ $( $tt) +] , $block }
46+ }
47+ } ;
48+ ( [ let $pat: pat = $expr: expr] , $block: block) => {
49+ if let $pat = $expr {
50+ $block
51+ }
52+ } ;
53+ ( [ $expr: expr, $( $tt: tt) +] , $block: block) => {
54+ if $expr {
55+ if_let_chain!{ [ $( $tt) +] , $block }
56+ }
57+ } ;
58+ ( [ $expr: expr] , $block: block) => {
59+ if $expr {
60+ $block
61+ }
62+ } ;
63+ }
64+
1865/// returns true this expn_info was expanded by any macro
1966pub fn in_macro ( cx : & LateContext , span : Span ) -> bool {
2067 cx. sess ( ) . codemap ( ) . with_expn_info ( span. expn_id ,
21- |info| info. map_or ( false , |i| {
22- match i. callee . format {
23- ExpnFormat :: CompilerExpansion ( ..) => false ,
24- _ => true ,
25- }
26- } ) )
68+ |info| info. is_some ( ) )
2769}
2870
2971/// returns true if the macro that expanded the crate was outside of
@@ -34,17 +76,9 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool {
3476 fn in_macro_ext < T : LintContext > ( cx : & T , opt_info : Option < & ExpnInfo > ) -> bool {
3577 // no ExpnInfo = no macro
3678 opt_info. map_or ( false , |info| {
37- match info. callee . format {
38- ExpnFormat :: CompilerExpansion ( ..) => {
39- if info. callee . name ( ) . as_str ( ) == "closure expansion" {
40- return false ;
41- }
42- } ,
43- ExpnFormat :: MacroAttribute ( ..) => {
44- // these are all plugins
45- return true ;
46- } ,
47- _ => ( ) ,
79+ if let ExpnFormat :: MacroAttribute ( ..) = info. callee . format {
80+ // these are all plugins
81+ return true ;
4882 }
4983 // no span for the callee = external macro
5084 info. callee . span . map_or ( true , |span| {
@@ -102,6 +136,13 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool {
102136 |( a, b) | a. identifier . name . as_str ( ) == * b)
103137}
104138
139+ /// match a Path against a slice of segment string literals, e.g.
140+ /// `match_path(path, &["std", "rt", "begin_unwind"])`
141+ pub fn match_path_ast ( path : & ast:: Path , segments : & [ & str ] ) -> bool {
142+ path. segments . iter ( ) . rev ( ) . zip ( segments. iter ( ) . rev ( ) ) . all (
143+ |( a, b) | a. identifier . name . as_str ( ) == * b)
144+ }
145+
105146/// get the name of the item the expression is in, if available
106147pub fn get_item_name ( cx : & LateContext , expr : & Expr ) -> Option < Name > {
107148 let parent_id = cx. tcx . map . get_parent ( expr. id ) ;
@@ -115,6 +156,24 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option<Name> {
115156 }
116157}
117158
159+ /// checks if a `let` decl is from a for loop desugaring
160+ pub fn is_from_for_desugar ( decl : & Decl ) -> bool {
161+ if_let_chain ! {
162+ [
163+ let DeclLocal ( ref loc) = decl. node,
164+ let Some ( ref expr) = loc. init,
165+ // FIXME: This should check for MatchSource::ForLoop
166+ // but right now there's a bug where the match source isn't
167+ // set during lowering
168+ // https://github.com/rust-lang/rust/pull/28973
169+ let ExprMatch ( _, _, _) = expr. node
170+ ] ,
171+ { return true ; }
172+ } ;
173+ false
174+ }
175+
176+
118177/// convert a span to a code snippet if available, otherwise use default, e.g.
119178/// `snippet(cx, expr.span, "..")`
120179pub fn snippet < ' a , T : LintContext > ( cx : & T , span : Span , default : & ' a str ) -> Cow < ' a , str > {
@@ -262,49 +321,3 @@ pub fn is_integer_literal(expr: &Expr, value: u64) -> bool
262321 }
263322 false
264323}
265-
266- /// Produce a nested chain of if-lets and ifs from the patterns:
267- ///
268- /// if_let_chain! {
269- /// [
270- /// Some(y) = x,
271- /// y.len() == 2,
272- /// Some(z) = y,
273- /// ],
274- /// {
275- /// block
276- /// }
277- /// }
278- ///
279- /// becomes
280- ///
281- /// if let Some(y) = x {
282- /// if y.len() == 2 {
283- /// if let Some(z) = y {
284- /// block
285- /// }
286- /// }
287- /// }
288- #[ macro_export]
289- macro_rules! if_let_chain {
290- ( [ let $pat: pat = $expr: expr, $( $tt: tt) +] , $block: block) => {
291- if let $pat = $expr {
292- if_let_chain!{ [ $( $tt) +] , $block }
293- }
294- } ;
295- ( [ let $pat: pat = $expr: expr] , $block: block) => {
296- if let $pat = $expr {
297- $block
298- }
299- } ;
300- ( [ $expr: expr, $( $tt: tt) +] , $block: block) => {
301- if $expr {
302- if_let_chain!{ [ $( $tt) +] , $block }
303- }
304- } ;
305- ( [ $expr: expr] , $block: block) => {
306- if $expr {
307- $block
308- }
309- } ;
310- }
0 commit comments