Skip to content

Commit edfd45c

Browse files
Eesha Shekharfacebook-github-bot
authored andcommitted
Adding a lint for branches returning the same value
Summary: This produces a lint advice when all the return statements in a block return the same value. The lint prompts the user to write a single return statement. "Returning the same value" refers to the following: 1) Returning the same literal, i.e same boolean, same integer, same float, same string 2) Returning the same global constant 3) Returning the same enum constant This lint also ignores the return statements that are within lambda statement. Reviewed By: Wilfred Differential Revision: D37937568 fbshipit-source-id: cf7d3643b624787afe9b48102d2d7279e674ec1f
1 parent 32a5c16 commit edfd45c

File tree

6 files changed

+526
-0
lines changed

6 files changed

+526
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
(*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the "hack" directory of this source tree.
6+
*
7+
*)
8+
open Aast
9+
open Hh_prelude
10+
11+
let is_expr_same ((_, _, expr1) : Tast.expr) ((_, _, expr2) : Tast.expr) : bool
12+
=
13+
match (expr1, expr2) with
14+
| (Aast.True, Aast.True)
15+
| (Aast.False, Aast.False) ->
16+
true
17+
| (Aast.Int s1, Aast.Int s2)
18+
| (Aast.Float s1, Aast.Float s2)
19+
| (Aast.String s1, Aast.String s2)
20+
| (Aast.Id (_, s1), Aast.Id (_, s2))
21+
when String.equal s1 s2 ->
22+
true
23+
| ( Aast.Class_const ((_, _, Aast.CI (_, enum1)), (_, name1)),
24+
Aast.Class_const ((_, _, Aast.CI (_, enum2)), (_, name2)) )
25+
when String.equal enum1 enum2 && String.equal name1 name2 ->
26+
true
27+
| _ -> false
28+
29+
let rec are_return_expressions_same (ret_list : Tast.expr list) : bool =
30+
match ret_list with
31+
| expr1 :: expr2 :: tail ->
32+
if is_expr_same expr1 expr2 then
33+
are_return_expressions_same (expr2 :: tail)
34+
else
35+
false
36+
| [_] -> true
37+
| [] -> true
38+
39+
(* This function returns a list of all the expressions that follow each of the return statements in a block *)
40+
let get_return_expr_visitor =
41+
object
42+
inherit [_] Aast.reduce as super
43+
44+
method zero = []
45+
46+
method plus = ( @ )
47+
48+
method! on_stmt env s =
49+
match snd s with
50+
| Aast.Return (Some expr) -> [expr]
51+
| _ -> super#on_stmt env s
52+
53+
(* we ignore the return expressions within lambda statements *)
54+
method! on_expr_ env e =
55+
match e with
56+
| Aast.Efun _ -> []
57+
| Aast.Lfun _ -> []
58+
| _ -> super#on_expr_ env e
59+
end
60+
61+
let get_return_exprs (stmts : Tast.stmt list) : Tast.expr list =
62+
get_return_expr_visitor#on_block () stmts
63+
64+
let handler =
65+
object
66+
inherit Tast_visitor.handler_base
67+
68+
method! at_fun_def _env f =
69+
let ret_list = get_return_exprs f.fd_fun.f_body.fb_ast in
70+
if List.length ret_list > 1 then (
71+
if are_return_expressions_same ret_list then
72+
List.iter ret_list ~f:(fun (_, pos, _) ->
73+
Lints_errors.branches_return_same_value pos)
74+
) else
75+
()
76+
77+
method! at_method_ _env m =
78+
let ret_list = get_return_exprs m.m_body.fb_ast in
79+
if List.length ret_list > 1 then (
80+
if are_return_expressions_same ret_list then
81+
List.iter ret_list ~f:(fun (_, pos, _) ->
82+
Lints_errors.branches_return_same_value pos)
83+
) else
84+
()
85+
end

hphp/hack/src/lints/linting_main.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ let typed_linters =
3939
Linter_pointless_booleans.handler;
4040
Linter_comparing_booleans.handler;
4141
Linter_unconditional_recursion.handler;
42+
Linter_branches_return_same_value.handler;
4243
]
4344
@ Linting_service.typed_linters
4445

hphp/hack/src/lints/lints_codes.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,6 @@ module Codes = struct
102102
let pointless_booleans_expression = 5644
103103

104104
let unconditional_recursion = 5645
105+
106+
let branch_return_same_value = 5646
105107
end

hphp/hack/src/lints/lints_errors.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,3 +441,10 @@ let unconditional_recursion p =
441441
p
442442
("This is a recursive function with no base case to terminate. This will result in a Stack Overflow error."
443443
^ " Consider adding a base case.")
444+
445+
let branches_return_same_value p =
446+
Lints.add
447+
Codes.branch_return_same_value
448+
Lint_warning
449+
p
450+
"All of these statements are returning the same value. Consider keeping a single return statement outside of the branches."

0 commit comments

Comments
 (0)