[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2023-03-23 Thread Nathan James via Phabricator via cfe-commits
njames93 added inline comments.



Comment at: clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp:359
+void UseEarlyExitsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(translationUnitDecl(), this);
+}

PiotrZSL wrote:
> This will trigger on all system code, and then users will complain again that 
> they see poor clang-tidy performance...
> 
> when it could be just something like
> 
> ```
> ifStmt(unless(isExpansionInSystemHeader()),
>unless(isConsteval()),
>unless(isConstexpr()),
>unless(hasElse(stmt())),
>unless(hasInitStatement(stmt()),
>hasThen(compoundStmt(hasSizeAboeLineTreshold())),
>...
> ```
> 
> Simply everything that could be put into matcher should be put into matcher 
> (easier to maintain), also what's a point of checking functions that doesn't 
> have if's. On that point also some implicit functions or if statement should 
> be ignored, to avoid checking templates twice.
> 
Not triggering on system headers is a good point, but for raw performance, that 
code is better residing in the visitor,  which can massively outperform 
matchers as we can straight up ignore huge blocks of code that aren't of 
interest.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2023-03-23 Thread Piotr Zegar via Phabricator via cfe-commits
PiotrZSL added inline comments.



Comment at: clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp:359
+void UseEarlyExitsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(translationUnitDecl(), this);
+}

This will trigger on all system code, and then users will complain again that 
they see poor clang-tidy performance...

when it could be just something like

```
ifStmt(unless(isExpansionInSystemHeader()),
   unless(isConsteval()),
   unless(isConstexpr()),
   unless(hasElse(stmt())),
   unless(hasInitStatement(stmt()),
   hasThen(compoundStmt(hasSizeAboeLineTreshold())),
   ...
```

Simply everything that could be put into matcher should be put into matcher 
(easier to maintain), also what's a point of checking functions that doesn't 
have if's. On that point also some implicit functions or if statement should be 
ignored, to avoid checking templates twice.




Comment at: 
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp:144
+  //  CHECK-FIXES-NEXT: }
+}

- Missing test with if in template function & implicit specialization, just to 
make sure that fixes won't get to mess up.
- Missing test with if under macro.
- Missing test with if under switch under loop (to check if brak/continue will 
be used correctly, instead of return).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2023-03-22 Thread Nathan James via Phabricator via cfe-commits
njames93 added a comment.

In D130181#4213779 , 
@LegalizeAdulthood wrote:

> I'm not certain that the result of the transformation is more "readable"; is 
> this check intended to aid conformance to a style guide?

One of the driving factors of this is that it can be used to remove nesting 
levels, which can definitely aid with readability.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2023-03-22 Thread Richard via Phabricator via cfe-commits
LegalizeAdulthood added a comment.
Herald added a subscriber: PiotrZSL.

I'm not certain that the result of the transformation is more "readable"; is 
this check intended to aid conformance to a style guide?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-09-19 Thread Jonas Toth via Phabricator via cfe-commits
JonasToth added a comment.

In D130181#3769618 , @njames93 wrote:

> In D130181#3769083 , @JonasToth 
> wrote:
>
>> ...
>
> Your concerns aren't actually that important. Because the transformations 
> only work on for binary operators, and not CXXOperatorCallExpr, it would 
> always never do any special logic, instead just wrap the whole thing in 
> parens and negate it.

Ah yes, you are right! That makes it very much better.

> I think the best way to resolve that could be delayed diagnostics for 
> template operators.
> So cache the locations of all dependent binary (and unary) operators, and see 
> if any of them either stay as binary operators or get transformed into 
> CXXOperatorCallExprs, if so don't emit the fix.
> The second option is to just not emit any fix for template dependent 
> operators.
> WDYT?

I am not 100% sure that delayed diagnostics would solve the issue _always_

  template 
  bool type_dependent_logic(T1 foo, T2 bar) {
  return foo && !bar;
  }

This template would be a counter example to yours, where I feel less 
comfortable.
The definition itself has `BinaryOperator` in the AST.

Now different TUs might use this template wildly different, e.g. TU1.cpp only 
with builtins, making a transformation possible and TU2.cpp with fancy and 
weird types making the transformation not possible.

clang-tidy (e.g. with `run-clang-tidy`) would now still change the template 
definition after it received the diagnostic from TU1.cpp, even though in 
TU2.cpp it is not considered as valid.
This issue is common to many checks, e.g. the `const-correctness` suffered from 
it as well. In the `const` case I had to just had to consider type dependent 
expressions as modifications.

For TU-local templates your strategy is certainly viable. But in the general 
case I would rather not do it, or at least have a "default-off" option for it.

Finally, what are your thoughts on `optional` types? They are kinda `bool` in 
the sense of this check, but suffer from the shortcomings with overloaded 
operators.
Should they be explicitly not considered now (i am fine with that!)? In that 
case, it should be mentioned as limitation in the documentation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-09-05 Thread Nathan James via Phabricator via cfe-commits
njames93 added a comment.

In D130181#3769083 , @JonasToth wrote:

> ...

Your concerns aren't actually that important. Because the transformations only 
work on for binary operators, and not CXXOperatorCallExpr, it would always 
never do any special logic, instead just wrap the whole thing in parens and 
negate it

  if (!(A && B))
continue;
  
  if (!(!B && C))
continue;
  
  padLines();

The only potential issue would be cases when the binary operator is type 
dependent, as binary operators where they type is unresolved are handled as 
BinaryOperators, even if every instantiation would be resolved to an operator 
call

  template 
  void fancyMatrix(Matrix A, Matrix B) {
  
  }


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-09-04 Thread Jonas Toth via Phabricator via cfe-commits
JonasToth added a comment.

IMHO the check looks good, but I do have concerns about correctness of the 
transformation in specific cases, especially overloaded operators.

If the conditions are inverted, it might be the case that the inverted operator 
is not overloaded, resulting in compilation errors.
I think that should be guarded against.

And then there is the more subtle issue of different semantics of the operators.

Hypothetical Matrix Algebra Situation:

  // A, B are matrices of booleans with identical dimensions
  // A && B will do '&&' on each matrix element
  // The matrices overload 'operator bool()' for implicit conversion to 'bool',
  // true := any element != false
  // false := all false
  if (A && B) {
// !C inverts each boolean in C, same '&&' application
if (B && !C) {
  padLines();
}
  }

Transformed to

  if (!A )
continue;
  if ( !B)
continue;
  if (!B )
continue;
  if ( C)
continue;
  padLines();

is highly likely not a correct and equivalent transformation.

My point is not so much about the concrete example, but more general.
C++ allows to implement operators with different semantics and classes must not 
behave like 'int' for the operators. Such overloads are not necessarily 
incorrect. E.g. `boost::sml` uses the operator overloading to define state 
machines, which does not follow anything close to the semantics we need for 
this check.
Expression-template libraries (especially linear algebra and so on) might 
either break or change meaning as well.

In my personal opinion the check should at least have an option to disable 
transformations for classes with overloaded operators and verify that the 
transformation would still compile if done anyway.
I think even better would be a "concept check" to at least verify that the type 
in question models a boolean with its operators. But I am not sure how far such 
a check should go and I am aware that it would not be perfect anyway.




Comment at: clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp:329
+assert(BSize >= CheckAlias.size() + OptName.size());
+memcpy(Buff, CheckAlias.data(), CheckAlias.size());
+memcpy(Buff + CheckAlias.size(), OptName.data(), OptName.size());

i would really prefer to just use strings here.
`std::string Buff = CheckAlias.str() + OptName.str();` is much easier to 
understand and equivalent (?)
 
this function is called only once in the constructor as well, so speed and 
allocations are not valid in my opinion.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:63
+void Process(bool A, bool B) {
+  if (A && B) {
+// Long processing.

njames93 wrote:
> JonasToth wrote:
> > njames93 wrote:
> > > JonasToth wrote:
> > > > if this option is false, the transformation would be `if(!(A && B))`, 
> > > > right?
> > > > 
> > > > should demorgan rules be applied or at least be mentioned here? I think 
> > > > transforming to `if (!A || !B)` is at least a viable option for enough 
> > > > users.
> > > Once this is in, I plan to merge some common code with the 
> > > simplify-boolean-expr logic for things like demorgan processing. Right 
> > > now the transformation happens, the simplify boolean suggests a demorgan 
> > > transformation of you run the output through clang tidy.
> > a short reference to the `readability-simplify-boolean-expr` check in the 
> > user facing docs would be great.
> > i personally find it ok if the users "pipe" multiple checks together to 
> > reach a final transformation.
> > 
> > would this check then use the same settings as the 
> > `readability-simplify-boolean-expr` check? (that of course off topic and 
> > does not relate to this patch :) )
> I'm not sure it's really necessary to mention that the fix would likely need 
> another fix, besides that comment would just be removed in the follow up.
ok, thats good with me.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-09-01 Thread Nathan James via Phabricator via cfe-commits
njames93 added inline comments.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:63
+void Process(bool A, bool B) {
+  if (A && B) {
+// Long processing.

JonasToth wrote:
> njames93 wrote:
> > JonasToth wrote:
> > > if this option is false, the transformation would be `if(!(A && B))`, 
> > > right?
> > > 
> > > should demorgan rules be applied or at least be mentioned here? I think 
> > > transforming to `if (!A || !B)` is at least a viable option for enough 
> > > users.
> > Once this is in, I plan to merge some common code with the 
> > simplify-boolean-expr logic for things like demorgan processing. Right now 
> > the transformation happens, the simplify boolean suggests a demorgan 
> > transformation of you run the output through clang tidy.
> a short reference to the `readability-simplify-boolean-expr` check in the 
> user facing docs would be great.
> i personally find it ok if the users "pipe" multiple checks together to reach 
> a final transformation.
> 
> would this check then use the same settings as the 
> `readability-simplify-boolean-expr` check? (that of course off topic and does 
> not relate to this patch :) )
I'm not sure it's really necessary to mention that the fix would likely need 
another fix, besides that comment would just be removed in the follow up.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-09-01 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 457199.
njames93 marked 3 inline comments as done.
njames93 added a comment.

Fix documentation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-nested.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,144 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 1}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 1, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: *B = 10;
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) 
+{ }
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  CHECK-FIXES-NEXT:   if (A <= B)
+  //  CHECK-FIXES-NEXT: continue;
+  //  CHECK-FIXES-NEXT:   if (B < A) {
+  //  CHECK-FIXES-NEXT: if (A != B) {
+  //  CHECK-FIXES-NEXT:   padLines();
+  //  CHECK-FIXES-NEXT: }
+  //  CHECK-FIXES-NEXT: } else {
+  //  CHECK-FIXES-NEXT: }
+}
Index: 

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-31 Thread Jonas Toth via Phabricator via cfe-commits
JonasToth added inline comments.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:63
+void Process(bool A, bool B) {
+  if (A && B) {
+// Long processing.

njames93 wrote:
> JonasToth wrote:
> > if this option is false, the transformation would be `if(!(A && B))`, right?
> > 
> > should demorgan rules be applied or at least be mentioned here? I think 
> > transforming to `if (!A || !B)` is at least a viable option for enough 
> > users.
> Once this is in, I plan to merge some common code with the 
> simplify-boolean-expr logic for things like demorgan processing. Right now 
> the transformation happens, the simplify boolean suggests a demorgan 
> transformation of you run the output through clang tidy.
a short reference to the `readability-simplify-boolean-expr` check in the user 
facing docs would be great.
i personally find it ok if the users "pipe" multiple checks together to reach a 
final transformation.

would this check then use the same settings as the 
`readability-simplify-boolean-expr` check? (that of course off topic and does 
not relate to this patch :) )


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-30 Thread Nathan James via Phabricator via cfe-commits
njames93 marked an inline comment as done.
njames93 added inline comments.



Comment at: clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp:66
+  if (needsParensAfterUnaryNegation(Condition)) {
+Diag << FixItHint::CreateInsertion(Condition->getBeginLoc(), "!(")
+ << FixItHint::CreateInsertion(

JonasToth wrote:
> did you consider comma expressions?
> 
> `if (myDirtyCode(), myCondition && yourCondition)`. It seems to me, that the 
> transformation would be incorrect.
Comma operator is a binary operator, so the transformation would wrap the whole 
expression in parens.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:63
+void Process(bool A, bool B) {
+  if (A && B) {
+// Long processing.

JonasToth wrote:
> if this option is false, the transformation would be `if(!(A && B))`, right?
> 
> should demorgan rules be applied or at least be mentioned here? I think 
> transforming to `if (!A || !B)` is at least a viable option for enough users.
Once this is in, I plan to merge some common code with the 
simplify-boolean-expr logic for things like demorgan processing. Right now the 
transformation happens, the simplify boolean suggests a demorgan transformation 
of you run the output through clang tidy.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-29 Thread Jonas Toth via Phabricator via cfe-commits
JonasToth added a comment.

just my 2 cents




Comment at: clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp:66
+  if (needsParensAfterUnaryNegation(Condition)) {
+Diag << FixItHint::CreateInsertion(Condition->getBeginLoc(), "!(")
+ << FixItHint::CreateInsertion(

did you consider comma expressions?

`if (myDirtyCode(), myCondition && yourCondition)`. It seems to me, that the 
transformation would be incorrect.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:55
+
+  If `true`, split up conditions with cunjunctions (``&&``) into multiple 
+  ``if`` statements. Default value is `false`.

typo `cunjunctions -> conjunctions`



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:63
+void Process(bool A, bool B) {
+  if (A && B) {
+// Long processing.

if this option is false, the transformation would be `if(!(A && B))`, right?

should demorgan rules be applied or at least be mentioned here? I think 
transforming to `if (!A || !B)` is at least a viable option for enough users.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:112
+
+  If `true`, the check will only report ifs which contain nested control 
blocks.
+  Default value is `false`

maybe highlight the `if` as code with double quotes?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-21 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 454275.
njames93 added a comment.

Add NestedControlFlow options

This option can be used to silence diagnostics when there aren't any nested 
blocks inside the if statement.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-nested.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,144 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 1}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 1, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: *B = 10;
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) 
+{ }
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  CHECK-FIXES-NEXT:   if (A <= B)
+  //  CHECK-FIXES-NEXT: continue;
+  //  CHECK-FIXES-NEXT:   if (B < A) {
+  //  CHECK-FIXES-NEXT: if (A != B) {
+  //  CHECK-FIXES-NEXT:   padLines();
+  //  CHECK-FIXES-NEXT: }
+  //  CHECK-FIXES-NEXT: } else {
+  //  

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-18 Thread Nathan James via Phabricator via cfe-commits
njames93 added a comment.

Ping?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-11 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 451856.
njames93 added a comment.

Refactor some of the impl.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,150 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  CHECK-FIXES-NEXT:   if (A <= B)
+  //  CHECK-FIXES-NEXT: continue;
+  //  CHECK-FIXES-NEXT:   if (B < A) {
+  //  CHECK-FIXES-NEXT: if (A != B) {
+  //  CHECK-FIXES-NEXT:   padLines();
+  //  CHECK-FIXES-NEXT: }
+  //  CHECK-FIXES-NEXT: } else {
+  //  CHECK-FIXES-NEXT: }
+  //  

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-08-01 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 449048.
njames93 added a comment.

Rebase and Ping??


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: 

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-27 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 447967.
njames93 added a comment.

Fix typo in check list documentation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-25 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 447246.
njames93 added a comment.

NL


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // 

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-25 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 447236.
njames93 added a comment.

Add option `SplitConjunctions` to alter fix-it for `if` statements with `&&` in 
the condition.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-split.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-20 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 446255.
njames93 added a comment.

Fix pre-build failing.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but 
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+  
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  } 
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  CHECK-FIXES-NEXT:   if (A <= B)
+  //  

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-20 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 446219.
njames93 added a comment.

Added logic to infer WrapInBraces option if unspecified.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Run the check with the braces around statements check also enabled, but 
+// ShortStatementLines is set so that we shouldn't add braces.
+// RUN: %check_clang_tidy %s readability-use-early-exits,readability-braces-around-statements -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2, \
+// RUN:readability-braces-around-statements.ShortStatementLines: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+  
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  } 
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-20 Thread Nathan James via Phabricator via cfe-commits
njames93 added inline comments.



Comment at: clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp:217
+  LineCountThreshold(Options.get("LineCountThreshold", 10U)),
+  WrapInBraces(Options.get("WrapInBraces", false)) {}
+

I have an idea that we could infer this using the 
`readability-braces-around-statements` and its hicpp alias.
If enabled, probe the ShortStatementLines option to infer whether or not that 
check would fire if we make this transformation without using braces.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-20 Thread Nathan James via Phabricator via cfe-commits
njames93 updated this revision to Diff 446197.
njames93 added a comment.

Add option to wrap early exit in braces.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  
clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,158 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+  
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  } 
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  CHECK-FIXES-NEXT:   if (A <= B)
+  //  CHECK-FIXES-NEXT: continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   if (B < A) {
+  //  CHECK-FIXES-NEXT: if (A != B) {
+  //  CHECK-FIXES-NEXT:   padLines();
+  //  CHECK-FIXES-NEXT: }
+  //  CHECK-FIXES-NEXT: } else {
+  //  CHECK-FIXES-NEXT: }
+  //  CHECK-FIXES-NEXT: }
+}
Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits-braces.cpp

[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-20 Thread Eugene Zelenko via Phabricator via cfe-commits
Eugene.Zelenko added inline comments.



Comment at: 
clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst:52
+  many lines. Default value is `10`.
\ No newline at end of file


Please add newline.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130181/new/

https://reviews.llvm.org/D130181

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D130181: [clang-tidy] Add readability-use-early-exits check

2022-07-20 Thread Nathan James via Phabricator via cfe-commits
njames93 created this revision.
njames93 added reviewers: alexfh, aaron.ballman.
Herald added subscribers: carlosgalvezp, xazax.hun, mgorny.
Herald added a project: All.
njames93 requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Add a check to flag loops and functions where an `if` at the end of the body 
could be negated and made into an early exit.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130181

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.cpp
  clang-tools-extra/clang-tidy/readability/UseEarlyExitsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/readability/use-early-exits.rst
  clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/readability/use-early-exits.cpp
@@ -0,0 +1,158 @@
+// RUN: %check_clang_tidy %s readability-use-early-exits -format-style=llvm %t -- \
+// RUN:   -config="{CheckOptions: {readability-use-early-exits.LineCountThreshold: 2}}"
+
+// Just to hit the threshold
+void padLines();
+
+void nomralFunc(int *A) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (A) {
+*A = 10;
+  }
+  //   CHECK-FIXES: if (!A)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *A = 10;
+}
+
+void funcWithTrailing(int *B) {
+  // CHECK-MESSAGES: [[@LINE+1]]:3: warning: use early exit
+  if (B) {
+*B = 10;
+  }
+  return;
+  ;
+  //   CHECK-FIXES: if (!B)
+  //  CHECK-FIXES-NEXT: return;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: *B = 10;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: return;
+  //  CHECK-FIXES-NEXT: ;
+}
+
+void normal(int A, int B) {
+  
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A == B) {
+  padLines();
+}
+  }
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A != B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  //  CHECK-FIXES-NEXT: }
+
+  // Eat continue and empty nulls
+  while (true) { // CHECK-MESSAGES: [[@LINE+1]]:5: warning: use early exit
+if (A != B) {
+  padLines();
+}
+continue;
+;
+continue;
+  } 
+  //   CHECK-FIXES:  while (true) {
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT:   ;
+  //  CHECK-FIXES-NEXT:   continue;
+  //  CHECK-FIXES-NEXT: }
+}
+
+void toShort(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+  }
+}
+
+void hasElse(int A, int B) {
+  while (true) {
+if (A == B) {
+
+} else {
+}
+  }
+}
+
+void hasTrailingStmt(int A, int B) {
+  while (true) {
+if (A == B) {
+}
+padLines();
+  }
+}
+
+void nested(int A, int B) {
+  // if (A > B) {
+  // CHECK-MESSAGES: [[@LINE+6]]:5: warning: use early exit
+  // if (B < A) {
+  // CHECK-MESSAGES: [[@LINE+5]]:7: warning: use early exit
+  // if (A == B) {
+  // CHECK-MESSAGES: [[@LINE+4]]:9: warning: use early exit
+  while (true) { // Nested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  }
+}
+  } // EndLoop
+  //   CHECK-FIXES: while (true) { // Nested
+  //  CHECK-FIXES-NEXT: if (A <= B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (B >= A)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: if (A == B)
+  //  CHECK-FIXES-NEXT:   continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: padLines();
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT: } // EndLoop
+}
+
+void badNested(bool B) {
+  // Ensure check doesn't check for nested `if` if outer `if` has else.
+  while (true) {
+if (B) {
+  if (B) {
+  }
+} else {
+}
+  }
+}
+
+void semiNested(int A, int B) {
+  // CHECK-MESSAGES: [[@LINE+2]]:5: warning: use early exit
+  while (true) { // SemiNested
+if (A > B) {
+  if (B < A) {
+if (A != B) {
+  padLines();
+}
+  } else {
+  }
+}
+  }
+  //   CHECK-FIXES: while (true) { // SemiNested
+  //  CHECK-FIXES-NEXT:   if (A <= B)
+  //  CHECK-FIXES-NEXT: continue;
+  // CHECK-FIXES-EMPTY:
+  //  CHECK-FIXES-NEXT:   if (B < A) {
+  //  CHECK-FIXES-NEXT: if (A != B) {
+  //  CHECK-FIXES-NEXT:   padLines();
+  //  CHECK-FIXES-NEXT: }
+  //  CHECK-FIXES-NEXT: } else {
+  //  CHECK-FIXES-NEXT: }