-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang-tidy] Add new check 'bugprone-inconsistent-ifelse-braces' #162361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[clang-tidy] Add new check 'bugprone-inconsistent-ifelse-braces' #162361
Conversation
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
693bcf3 to
29e7a6a
Compare
| const MatchFinder::MatchResult &Result) { | ||
| const auto *MatchedIf = Result.Nodes.getNodeAs<IfStmt>("if_stmt"); | ||
|
|
||
| if (shouldHaveBraces(MatchedIf) && !doesHaveBraces(MatchedIf)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: llvm style is a single statement should not have a brace - hilariously violating this check (different code bases have differing policies so that's not a strike against this check :D)
I realize this is a draft but I saw it while going through open PRs and was wondering what you were diagnosing :)
b35337a to
542f435
Compare
|
✅ With the latest revision this PR passed the C/C++ code linter. |
692b19f to
a0a7126
Compare
e54909d to
28a213b
Compare
|
@llvm/pr-subscribers-clang-tidy @llvm/pr-subscribers-clang-tools-extra Author: Davide Cunial (capitan-davide) ChangesCloses #162140 Full diff: https://github.com/llvm/llvm-project/pull/162361.diff 9 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index fe261e729539c..e1e42d22c520e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -33,6 +33,7 @@
#include "ImplicitWideningOfMultiplicationResultCheck.h"
#include "InaccurateEraseCheck.h"
#include "IncDecInConditionsCheck.h"
+#include "InconsistentIfelseBracesCheck.h"
#include "IncorrectEnableIfCheck.h"
#include "IncorrectEnableSharedFromThisCheck.h"
#include "IncorrectRoundingsCheck.h"
@@ -150,6 +151,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-implicit-widening-of-multiplication-result");
CheckFactories.registerCheck<InaccurateEraseCheck>(
"bugprone-inaccurate-erase");
+ CheckFactories.registerCheck<InconsistentIfelseBracesCheck>(
+ "bugprone-inconsistent-ifelse-braces");
CheckFactories.registerCheck<IncorrectEnableIfCheck>(
"bugprone-incorrect-enable-if");
CheckFactories.registerCheck<IncorrectEnableSharedFromThisCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 46bc8efd44bc5..d19fd5017d2e0 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -28,6 +28,7 @@ add_clang_library(clangTidyBugproneModule STATIC
ForwardingReferenceOverloadCheck.cpp
ImplicitWideningOfMultiplicationResultCheck.cpp
InaccurateEraseCheck.cpp
+ InconsistentIfelseBracesCheck.cpp
IncorrectEnableIfCheck.cpp
IncorrectEnableSharedFromThisCheck.cpp
InvalidEnumDefaultInitializationCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
new file mode 100644
index 0000000000000..0c6b3e3e3ff9c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InconsistentIfelseBracesCheck.h"
+#include "../utils/BracesAroundStatement.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+/// Check that at least one branch of the \p If statement is a \c CompoundStmt.
+static bool shouldHaveBraces(const IfStmt *If) {
+ const Stmt *const Then = If->getThen();
+ if (isa<CompoundStmt>(Then))
+ return true;
+
+ if (const Stmt *const Else = If->getElse()) {
+ if (const auto *NestedIf = dyn_cast<const IfStmt>(Else))
+ return shouldHaveBraces(NestedIf);
+
+ return isa<CompoundStmt>(Else);
+ }
+
+ return false;
+}
+
+void InconsistentIfelseBracesCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ traverse(TK_IgnoreUnlessSpelledInSource,
+ ifStmt(hasElse(anything()),
+ unless(isConsteval()), // 'if consteval' always has braces
+ unless(hasParent(ifStmt())))
+ .bind("if_stmt")),
+ this);
+}
+
+void InconsistentIfelseBracesCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedIf = Result.Nodes.getNodeAs<IfStmt>("if_stmt");
+ if (!shouldHaveBraces(MatchedIf))
+ return;
+ checkIfStmt(Result, MatchedIf);
+}
+
+void InconsistentIfelseBracesCheck::checkIfStmt(
+ const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If) {
+ const Stmt *Then = If->getThen();
+ if (const auto *NestedIf = dyn_cast<const IfStmt>(Then)) {
+ // If the then-branch is a nested IfStmt, first we need to add braces to
+ // it, then we need to check the inner IfStmt.
+ checkStmt(Result, If->getThen(), If->getRParenLoc(), If->getElseLoc());
+ if (shouldHaveBraces(NestedIf))
+ checkIfStmt(Result, NestedIf);
+ } else if (!isa<CompoundStmt>(Then)) {
+ checkStmt(Result, If->getThen(), If->getRParenLoc(), If->getElseLoc());
+ }
+
+ if (const Stmt *const Else = If->getElse()) {
+ if (const auto *NestedIf = dyn_cast<const IfStmt>(Else))
+ checkIfStmt(Result, NestedIf);
+ else if (!isa<CompoundStmt>(Else))
+ checkStmt(Result, If->getElse(), If->getElseLoc());
+ }
+}
+
+void InconsistentIfelseBracesCheck::checkStmt(
+ const ast_matchers::MatchFinder::MatchResult &Result, const Stmt *S,
+ SourceLocation StartLoc, SourceLocation EndLocHint) {
+ const SourceManager &SM = *Result.SourceManager;
+ const LangOptions &LangOpts = Result.Context->getLangOpts();
+
+ const utils::BraceInsertionHints Hints =
+ utils::getBraceInsertionsHints(S, LangOpts, SM, StartLoc, EndLocHint);
+ if (Hints) {
+ DiagnosticBuilder Diag = diag(Hints.DiagnosticPos, "<message>");
+ if (Hints.offersFixIts()) {
+ Diag << Hints.openingBraceFixIt() << Hints.closingBraceFixIt();
+ }
+ }
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.h b/clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.h
new file mode 100644
index 0000000000000..c818f46fea281
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCONSISTENTIFELSEBRACESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCONSISTENTIFELSEBRACESCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects `if`/`else` statements where one branch uses braces and the other
+/// does not.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/inconsistent-ifelse-braces.html
+class InconsistentIfelseBracesCheck : public ClangTidyCheck {
+public:
+ InconsistentIfelseBracesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+
+private:
+ void checkIfStmt(const ast_matchers::MatchFinder::MatchResult &Result,
+ const IfStmt *If);
+ void checkStmt(const ast_matchers::MatchFinder::MatchResult &Result,
+ const Stmt *S, SourceLocation StartLoc,
+ SourceLocation EndLocHint = SourceLocation());
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCONSISTENTIFELSEBRACESCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 7cdff86beeec6..28bebceef1006 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -157,6 +157,12 @@ Improvements to clang-tidy
New checks
^^^^^^^^^^
+- New :doc:`bugprone-inconsistent-ifelse-braces
+ <clang-tidy/checks/bugprone/inconsistent-ifelse-braces>` check.
+
+ Detects ``if``/``else`` statements where one branch uses braces and the other
+ does not.
+
- New :doc:`bugprone-invalid-enum-default-initialization
<clang-tidy/checks/bugprone/invalid-enum-default-initialization>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/inconsistent-ifelse-braces.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/inconsistent-ifelse-braces.rst
new file mode 100644
index 0000000000000..44f2d64452393
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/inconsistent-ifelse-braces.rst
@@ -0,0 +1,42 @@
+.. title:: clang-tidy - bugprone-inconsistent-ifelse-braces
+
+bugprone-inconsistent-ifelse-braces
+===================================
+
+Detects ``if``/``else`` statements where one branch uses braces and the other
+does not.
+
+Before:
+
+.. code-block:: c++
+
+ if (condition) {
+ statement;
+ } else
+ statement;
+
+ if (condition)
+ statement;
+
+ if (condition)
+ statement;
+ else
+ statement;
+
+After:
+
+.. code-block:: c++
+
+ if (condition) {
+ statement;
+ } else {
+ statement;
+ }
+
+ if (condition)
+ statement;
+
+ if (condition)
+ statement;
+ else
+ statement;
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index c490d2ece2e0a..4c5b70f6c47e5 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -101,6 +101,7 @@ Clang-Tidy Checks
:doc:`bugprone-implicit-widening-of-multiplication-result <bugprone/implicit-widening-of-multiplication-result>`, "Yes"
:doc:`bugprone-inaccurate-erase <bugprone/inaccurate-erase>`, "Yes"
:doc:`bugprone-inc-dec-in-conditions <bugprone/inc-dec-in-conditions>`,
+ :doc:`bugprone-inconsistent-ifelse-braces <bugprone/inconsistent-ifelse-braces>`, "Yes"
:doc:`bugprone-incorrect-enable-if <bugprone/incorrect-enable-if>`, "Yes"
:doc:`bugprone-incorrect-enable-shared-from-this <bugprone/incorrect-enable-shared-from-this>`, "Yes"
:doc:`bugprone-incorrect-roundings <bugprone/incorrect-roundings>`,
@@ -256,7 +257,7 @@ Clang-Tidy Checks
:doc:`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>`,
:doc:`llvm-twine-local <llvm/twine-local>`, "Yes"
:doc:`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>`, "Yes"
- :doc:`llvm-use-ranges <llvm/use-ranges>`, "Yes"
+ :doc:`llvm-use-ranges <llvm/use-ranges>`,
:doc:`llvmlibc-callee-namespace <llvmlibc/callee-namespace>`,
:doc:`llvmlibc-implementation-in-namespace <llvmlibc/implementation-in-namespace>`,
:doc:`llvmlibc-inline-function-decl <llvmlibc/inline-function-decl>`, "Yes"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces-consteval-if.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces-consteval-if.cpp
new file mode 100644
index 0000000000000..3eb51c39e2921
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces-consteval-if.cpp
@@ -0,0 +1,55 @@
+// RUN: %check_clang_tidy -std=c++23-or-later %s bugprone-inconsistent-ifelse-braces %t
+
+bool cond(const char *) { return false; }
+
+void do_something(const char *) {}
+
+// Positive tests.
+void f() {
+ if consteval {
+ if (cond("if1"))
+ do_something("if-single-line");
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:21: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if1")) {
+ // CHECK-FIXES: } else {
+ }
+
+ if consteval {
+ if (cond("if2"))
+ do_something("if-single-line");
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:21: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if2")) {
+ // CHECK-FIXES: } else {
+ } else {
+ if (cond("if2.1")) {
+ } else
+ do_something("else-single-line");
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else {
+ // CHECK-FIXES: }
+ }
+}
+
+// Negative tests.
+void g() {
+ if consteval {
+ if (cond("if0")) {
+ do_something("if-single-line");
+ } else if (cond("if0")) {
+ do_something("elseif-single-line");
+ } else {
+ do_something("else-single-line");
+ }
+ } else {
+ if (cond("if0.1"))
+ do_something("if-single-line");
+ else if (cond("if0.1"))
+ do_something("elseif-single-line");
+ else
+ do_something("else-single-line");
+ }
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces.cpp
new file mode 100644
index 0000000000000..3d4af258137ce
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces.cpp
@@ -0,0 +1,123 @@
+// RUN: %check_clang_tidy %s bugprone-inconsistent-ifelse-braces %t
+
+bool cond(const char *) { return false; }
+
+void do_something(const char *) {}
+
+// Positive tests.
+void f() {
+ if (cond("if0") /*comment*/) do_something("if-same-line");
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:31: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if0") /*comment*/) { do_something("if-same-line");
+ // CHECK-FIXES: } else {
+
+ if (cond("if0.1") /*comment*/) {
+ } else do_something("else-same-line");
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else { do_something("else-same-line");
+ // CHECK-FIXES: }
+
+ if (cond("if1"))
+ do_something("if-single-line");
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:19: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if1")) {
+ // CHECK-FIXES: } else {
+
+ if (cond("if1.1")) {
+ } else
+ do_something("else-single-line");
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else {
+ // CHECK-FIXES: }
+
+ if (cond("if2") /*comment*/)
+ // some comment
+ do_something("if-multi-line");
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:31: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if2") /*comment*/) {
+ // CHECK-FIXES: } else {
+
+ if (cond("if2.1") /*comment*/) {
+ } else
+ // some comment
+ do_something("else-multi-line");
+ // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else {
+ // CHECK-FIXES: }
+
+ if (cond("if3")) do_something("elseif-same-line");
+ else if (cond("if3")) {
+ } else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:19: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if3")) { do_something("elseif-same-line");
+ // CHECK-FIXES: } else if (cond("if3")) {
+
+ if (cond("if3.1")) {
+ } else if (cond("if3.1")) do_something("elseif-same-line");
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:28: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else if (cond("if3.1")) { do_something("elseif-same-line");
+ // CHECK-FIXES: } else {
+
+ if (cond("if3.2")) {
+ } else if (cond("if3.2")) {
+ } else do_something("else-same-line");
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else { do_something("else-same-line");
+ // CHECK-FIXES: }
+
+ if (cond("if4-outer"))
+ if (cond("if4-inner"))
+ do_something("if-single-line");
+ else {
+ }
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:25: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-MESSAGES: :[[@LINE-7]]:27: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if4-outer")) {
+ // CHECK-FIXES: if (cond("if4-inner")) {
+ // CHECK-FIXES: } else {
+ // CHECK-FIXES: } else {
+
+ if (cond("if5"))
+ do_something("if-single-line");
+ else if (cond("if5")) {
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:19: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: if (cond("if5")) {
+ // CHECK-FIXES: } else if (cond("if5")) {
+
+ if (cond("if5.1")) {
+ } else if (cond("if5.1"))
+ do_something("elseif-single-line");
+ // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: <message> [bugprone-inconsistent-ifelse-braces]
+ // CHECK-FIXES: } else if (cond("if5.1")) {
+ // CHECK-FIXES: }
+}
+
+// Negative tests.
+void g() {
+ if (cond("if0")) {
+ do_something("if-single-line");
+ } else if (cond("if0")) {
+ do_something("elseif-single-line");
+ } else {
+ do_something("else-single-line");
+ }
+
+ if (cond("if1"))
+ do_something("if-single-line");
+ else if (cond("if1"))
+ do_something("elseif-single-line");
+ else
+ do_something("else-single-line");
+}
|
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.h
Outdated
Show resolved
Hide resolved
28a213b to
40570f9
Compare
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.h
Outdated
Show resolved
Hide resolved
clang-tools-extra/test/clang-tidy/checkers/readability/inconsistent-ifelse-braces.cpp
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.h
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/test/clang-tidy/checkers/bugprone/inconsistent-ifelse-braces.cpp
Outdated
Show resolved
Hide resolved
Co-authored-by: Victor Chernyakin <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, this is purely readability check readability-inconsistent-ifelse-braces. I would leave bugprone category for checks that catch pattern which almost certainly have a bug (or very easy to have a bug). With such inconsistent braces, I don't think it's very easy to get a bug. We already have readability-misleading-indentation that catches cases with braces that are likely to have a bug.
localspook
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but we should agree on the warning message and category before merging (I'll be somewhat unhelpful and say that I don't have a strong opinion on whether it should be readability or bugprone)
| const utils::BraceInsertionHints Hints = | ||
| utils::getBraceInsertionsHints(S, LangOpts, SM, StartLoc, EndLocHint); | ||
| if (Hints) { | ||
| DiagnosticBuilder Diag = diag(Hints.DiagnosticPos, "<message>"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just leaving a comment to make sure this PR doesn't accidentally get merged without an actual message
|
Also no strong opinions about module name. Thinking out loud, maybe this could be even made to implement LLVM Coding Standard exactly and made into an |
I was thinking about this check, but LLVM guide has so many caveats that I'm afraid it would be too strict and wouldn't satisfy the majority of users (Luckily, we have a whole codebase to test the check). P.S. clang-format already implement part of this functionality in https://clang.llvm.org/docs/ClangFormatStyleOptions.html#removebracesllvm. In total, It's up to you what you want to be implemented, we appreciate all contributions. Your check is valuable in current form, and we can reuse some written functions/matchers when implementing "LLVM" check. |
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/bugprone/InconsistentIfelseBracesCheck.cpp
Outdated
Show resolved
Hide resolved
| const utils::BraceInsertionHints Hints = | ||
| utils::getBraceInsertionsHints(S, LangOpts, SM, StartLoc, EndLocHint); | ||
| if (Hints) { | ||
| DiagnosticBuilder Diag = diag(Hints.DiagnosticPos, "<message>"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we only emitting diagnostics if we can insert hints?
Can there be a situation if we can't emit hint, but still need to emit diagnostics for user to manually fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we only emitting diagnostics if we can insert hints? Can there be a situation if we can't emit hint, but still need to emit diagnostics for user to manually fix.
I updated this to assert that FitIts are always available, when the source location is not a macro expansion. It runs on the clang+clang-tools-extra codebase with 6013 findings and no crashes.
In case the location is a macro expansion we can either:
- warn, but no fix-its
- ignore it (like readability-braces-around-statements)
| @@ -0,0 +1,122 @@ | |||
| // RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-inconsistent-ifelse-braces %t | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests with macros
| void InconsistentIfelseBracesCheck::check( | ||
| const MatchFinder::MatchResult &Result) { | ||
| const auto *MatchedIf = Result.Nodes.getNodeAs<IfStmt>("if_stmt"); | ||
| if (!shouldHaveBraces(MatchedIf)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of matching each if statement, we should be able to check shouldHaveBraces inside addMatcher.
Create custom AST-matcher on IfStmt and run shouldHaveBraces on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm, I am not familiar with other matchers that tries to enforce some kind of "policy". What would be the benefits of this approach? IMHO it hurts readability a bit.
7e1efdd to
b660692
Compare
Renamed to |
Also, renamed from `bugprone-*` to `readability-*`
b660692 to
02aa926
Compare
Closes #162140