@@ -975,14 +975,52 @@ declare_lint!(UNNECESSARY_PARENS, Warn,
975
975
pub struct UnnecessaryParens ;
976
976
977
977
impl UnnecessaryParens {
978
- fn check_unnecessary_parens_core ( & self , cx : & Context , value : & ast:: Expr , msg : & str ) {
978
+ fn check_unnecessary_parens_core ( & self , cx : & Context , value : & ast:: Expr , msg : & str ,
979
+ struct_lit_needs_parens : bool ) {
979
980
match value. node {
980
- ast:: ExprParen ( _) => {
981
- cx. span_lint ( UNNECESSARY_PARENS , value. span ,
982
- format ! ( "unnecessary parentheses around {}" , msg) . as_slice ( ) )
981
+ ast:: ExprParen ( ref inner) => {
982
+ let necessary = struct_lit_needs_parens && contains_exterior_struct_lit ( & * * inner) ;
983
+ if !necessary {
984
+ cx. span_lint ( UNNECESSARY_PARENS , value. span ,
985
+ format ! ( "unnecessary parentheses around {}" ,
986
+ msg) . as_slice ( ) )
987
+ }
983
988
}
984
989
_ => { }
985
990
}
991
+
992
+ /// Expressions that syntatically contain an "exterior" struct
993
+ /// literal i.e. not surrounded by any parens or other
994
+ /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
995
+ /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
996
+ /// y: 1 }) == foo` does not.
997
+ fn contains_exterior_struct_lit ( value : & ast:: Expr ) -> bool {
998
+ match value. node {
999
+ ast:: ExprStruct ( ..) => true ,
1000
+
1001
+ ast:: ExprAssign ( ref lhs, ref rhs) |
1002
+ ast:: ExprAssignOp ( _, ref lhs, ref rhs) |
1003
+ ast:: ExprBinary ( _, ref lhs, ref rhs) => {
1004
+ // X { y: 1 } + X { y: 2 }
1005
+ contains_exterior_struct_lit ( & * * lhs) ||
1006
+ contains_exterior_struct_lit ( & * * rhs)
1007
+ }
1008
+ ast:: ExprUnary ( _, ref x) |
1009
+ ast:: ExprCast ( ref x, _) |
1010
+ ast:: ExprField ( ref x, _, _) |
1011
+ ast:: ExprIndex ( ref x, _) => {
1012
+ // &X { y: 1 }, X { y: 1 }.y
1013
+ contains_exterior_struct_lit ( & * * x)
1014
+ }
1015
+
1016
+ ast:: ExprMethodCall ( _, _, ref exprs) => {
1017
+ // X { y: 1 }.bar(...)
1018
+ contains_exterior_struct_lit ( & * * exprs. get ( 0 ) )
1019
+ }
1020
+
1021
+ _ => false
1022
+ }
1023
+ }
986
1024
}
987
1025
}
988
1026
@@ -992,16 +1030,16 @@ impl LintPass for UnnecessaryParens {
992
1030
}
993
1031
994
1032
fn check_expr ( & mut self , cx : & Context , e : & ast:: Expr ) {
995
- let ( value, msg) = match e. node {
996
- ast:: ExprIf ( cond, _, _) => ( cond, "`if` condition" ) ,
997
- ast:: ExprWhile ( cond, _) => ( cond, "`while` condition" ) ,
998
- ast:: ExprMatch ( head, _) => ( head, "`match` head expression" ) ,
999
- ast:: ExprRet ( Some ( value) ) => ( value, "`return` value" ) ,
1000
- ast:: ExprAssign ( _, value) => ( value, "assigned value" ) ,
1001
- ast:: ExprAssignOp ( _, _, value) => ( value, "assigned value" ) ,
1033
+ let ( value, msg, struct_lit_needs_parens ) = match e. node {
1034
+ ast:: ExprIf ( cond, _, _) => ( cond, "`if` condition" , true ) ,
1035
+ ast:: ExprWhile ( cond, _) => ( cond, "`while` condition" , true ) ,
1036
+ ast:: ExprMatch ( head, _) => ( head, "`match` head expression" , true ) ,
1037
+ ast:: ExprRet ( Some ( value) ) => ( value, "`return` value" , false ) ,
1038
+ ast:: ExprAssign ( _, value) => ( value, "assigned value" , false ) ,
1039
+ ast:: ExprAssignOp ( _, _, value) => ( value, "assigned value" , false ) ,
1002
1040
_ => return
1003
1041
} ;
1004
- self . check_unnecessary_parens_core ( cx, & * value, msg) ;
1042
+ self . check_unnecessary_parens_core ( cx, & * value, msg, struct_lit_needs_parens ) ;
1005
1043
}
1006
1044
1007
1045
fn check_stmt ( & mut self , cx : & Context , s : & ast:: Stmt ) {
@@ -1015,7 +1053,7 @@ impl LintPass for UnnecessaryParens {
1015
1053
} ,
1016
1054
_ => return
1017
1055
} ;
1018
- self . check_unnecessary_parens_core ( cx, & * value, msg) ;
1056
+ self . check_unnecessary_parens_core ( cx, & * value, msg, false ) ;
1019
1057
}
1020
1058
}
1021
1059
0 commit comments