Re: [cocci] [PATCH 01/36] coccinelle: misc: add cond_return_no_effect.cocci
Sang-Heon Jeon <[email protected]> Sat, 25 Jul 2026 01:48:14 +0900
| Newsgroups | fr.inria.cocci,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CABFDxMHOt2pAb913+uH3LFnv=W-af286NycwzJSe7hbK+V_H0A@mail.gmail.com> |
On Fri, Jul 24, 2026 at 11:55=E2=80=AFPM Julia Lawall <[email protected]= r> wrote: > > > > On Fri, 24 Jul 2026, Sang-Heon Jeon wrote: > > > On Fri, Jul 24, 2026 at 3:45=E2=80=AFAM Sang-Heon Jeon <ekffu200098@gma= il.com> wrote: > > > > > > Add a new Coccinelle script which removes a conditional return that > > > has no effect: > > > > > > if (ret) > > > return ret; > > > return ret; > > > > > > Both branches return the same value, so the check can be removed. > > > The condition can also be a negation or a comparison with a > > > constant. Such code is usually a leftover from removing a > > > statement between the two returns. > > > > > > When a local variable is assigned right before the check, the > > > assignment and the two returns turn into a single return of the > > > assigned expression, and the declaration is dropped if nothing > > > else uses the variable. Otherwise only the check is removed. > > > > > > The fold can delete comments between the check and the final > > > return, so the generated patch should be reviewed. > > > > > > Signed-off-by: Sang-Heon Jeon <[email protected]> > > > --- > > > .../misc/cond_return_no_effect.cocci | 121 ++++++++++++++++= ++ > > > 1 file changed, 121 insertions(+) > > > create mode 100644 scripts/coccinelle/misc/cond_return_no_effect.coc= ci > > > > > > diff --git a/scripts/coccinelle/misc/cond_return_no_effect.cocci b/sc= ripts/coccinelle/misc/cond_return_no_effect.cocci > > > new file mode 100644 > > > index 000000000000..541aafdc32c6 > > > --- /dev/null > > > +++ b/scripts/coccinelle/misc/cond_return_no_effect.cocci > > > @@ -0,0 +1,121 @@ > > > +// SPDX-License-Identifier: GPL-2.0-only > > > +/// > > > +/// Remove a conditional return that has no effect: > > > +/// > > > +/// if (ret) > > > +/// return ret; > > > +/// return ret; > > > +/// > > > +/// Both branches return the same variable, so the check has no > > > +/// effect. It can also be a negation or a comparison with a > > > +/// constant. > > > +/// > > > +/// When a local variable is assigned right before the check, the > > > +/// assignment and the two returns turn into a single return of the > > > +/// assigned expression, and the declaration is dropped if nothing > > > +/// else uses the variable. Otherwise only the check is removed. > > > +/// > > > +// Such code is usually a leftover from removing a statement between > > > +// the two returns. > > > +// > > > +// Confidence: High > > > +// Copyright: (C) 2026 Sang-Heon Jeon > > > +// Comments: The fold can delete comments between the check and the > > > +// final return, so review the generated patch. > > > +// Options: --no-includes --include-headers > > > + > > > +virtual patch > > > +virtual context > > > +virtual org > > > +virtual report > > > + > > > +//---------------------------------------------------------- > > > +// For patch mode > > > +//---------------------------------------------------------- > > > + > > > +@collect depends on patch@ > > > +identifier ret; > > > +expression E; > > > +binary operator cmp =3D {<, <=3D, >, >=3D, =3D=3D, !=3D}; > > > +constant C; > > > +@@ > > > + ret =3D E; > > > + if (\(ret \| !ret \| ret cmp C\)) > > > + return ret; > > > + return ret; > > > + > > > +@depends on patch@ > > > +local idexpression ret; > > > +expression E; > > > +binary operator cmp =3D {<, <=3D, >, >=3D, =3D=3D, !=3D}; > > > +constant C; > > > +@@ > > > +- ret =3D E; > > > +- if (\(ret \| !ret \| ret cmp C\)) > > > +- return ret; > > > +- return ret; > > > ++ return E; > > > + > > > > If we can make these rules depend on an earlier rule, it should > > improve the performance a bit. I will look into whether it is > > worthwhile. > > I don't see an opportunity for more efficiency for the above rules, but g= o > ahead if you have some idea. > > > > > > +@depends on patch@ > > > +idexpression ret; > > > +binary operator cmp =3D {<, <=3D, >, >=3D, =3D=3D, !=3D}; > > > +constant C; > > > +@@ > > > +- if (\(ret \| !ret \| ret cmp C\)) > > > +- return ret; > > > + return ret; > > > + > > > +@depends on patch@ > > > +type T; > > > +identifier collect.ret; > > > +@@ > > > +- T ret; > > > + ... when !=3D ret > > > + when strict > > > + > > > +@depends on patch@ > > > +type T; > > > +identifier collect.ret; > > > +constant C; > > > +@@ > > > +- T ret =3D C; > > > + ... when !=3D ret > > > + when strict > > > + > > > > While testing the script, I found that this rule can unexpectedly > > remove the declaration of a global or static variable in the same > > file, even when it is still used elsewhere. There is no such case in > > this series, but I will fix it in v2 by matching the declaration > > inside a function. > > I think you could avoid matching the path from the top of the function to > the declaration by doing the following: > > declaration D; > statement S; > > ( > - T ret =3D C > ( > D > | > S > ) > & > T ret =3D C; > ... when !=3D ret > when strict > ) > > The first part ensures that it is not a top-level declaration and the > second part does the check you had previously. > > To ensure that it doesn't match "static T ret =3D C;" you can put the > following in the @depends on patch@: > > disable optional_storage Thanks for the suggestion. This looks much better than what I had in mind. I'll use it in v2. > julia > > > > fn(...) { > > ... > > - T ret; > > ... when !=3D ret > > when strict > > } > > > > > + > > > +//---------------------------------------------------------- > > > +// For context mode > > > +//---------------------------------------------------------- > > > + > > > +@depends on context@ > > > +idexpression ret; > > > +binary operator cmp =3D {<, <=3D, >, >=3D, =3D=3D, !=3D}; > > > +constant C; > > > +@@ > > > +* if (\(ret \| !ret \| ret cmp C\)) > > > +* return ret; > > > + return ret; > > > + > > > +//---------------------------------------------------------- > > > +// For org and report mode > > > +//---------------------------------------------------------- > > > + > > > +@r depends on org || report@ > > > +idexpression ret; > > > +binary operator cmp =3D {<, <=3D, >, >=3D, =3D=3D, !=3D}; > > > +constant C; > > > +position p; > > > +@@ > > > + if@p (\(ret \| !ret \| ret cmp C\)) > > > + return ret; > > > + return ret; > > > + > > > +@script:python depends on org@ > > > +p << r.p; > > > +@@ > > > +cocci.print_main("WARNING: conditional return with no effect (both b= ranches return the same value)", p) > > > + > > > +@script:python depends on report@ > > > +p << r.p; > > > +@@ > > > +coccilib.report.print_report(p[0], "WARNING: conditional return with= no effect (both branches return the same value)") > > > -- > > > 2.43.0 > > > > > Best Regards, Sang-Heon Jeon