Skip to content

Commit b35337a

Browse files
[clang-tidy] Add new check 'bugprone-inconsistent-ifelse-braces'
1 parent 48babe1 commit b35337a

File tree

8 files changed

+185
-1
lines changed

8 files changed

+185
-1
lines changed

clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "ImplicitWideningOfMultiplicationResultCheck.h"
3434
#include "InaccurateEraseCheck.h"
3535
#include "IncDecInConditionsCheck.h"
36+
#include "InconsistentIfelseBracesCheck.h"
3637
#include "IncorrectEnableIfCheck.h"
3738
#include "IncorrectEnableSharedFromThisCheck.h"
3839
#include "IncorrectRoundingsCheck.h"
@@ -150,6 +151,8 @@ class BugproneModule : public ClangTidyModule {
150151
"bugprone-implicit-widening-of-multiplication-result");
151152
CheckFactories.registerCheck<InaccurateEraseCheck>(
152153
"bugprone-inaccurate-erase");
154+
CheckFactories.registerCheck<InconsistentIfelseBracesCheck>(
155+
"bugprone-inconsistent-ifelse-braces");
153156
CheckFactories.registerCheck<IncorrectEnableIfCheck>(
154157
"bugprone-incorrect-enable-if");
155158
CheckFactories.registerCheck<IncorrectEnableSharedFromThisCheck>(

clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_clang_library(clangTidyBugproneModule STATIC
2828
ForwardingReferenceOverloadCheck.cpp
2929
ImplicitWideningOfMultiplicationResultCheck.cpp
3030
InaccurateEraseCheck.cpp
31+
InconsistentIfelseBracesCheck.cpp
3132
IncorrectEnableIfCheck.cpp
3233
IncorrectEnableSharedFromThisCheck.cpp
3334
InvalidEnumDefaultInitializationCheck.cpp
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "InconsistentIfelseBracesCheck.h"
11+
#include "../utils/BracesAroundStatement.h"
12+
#include "../utils/LexerUtils.h"
13+
#include "clang/AST/ASTTypeTraits.h"
14+
#include "clang/AST/Stmt.h"
15+
#include "clang/ASTMatchers/ASTMatchFinder.h"
16+
#include "clang/ASTMatchers/ASTMatchers.h"
17+
#include "clang/Basic/LangOptions.h"
18+
#include "clang/Basic/SourceLocation.h"
19+
#include "clang/Basic/SourceManager.h"
20+
#include "clang/Basic/TokenKinds.h"
21+
#include "clang/Lex/Lexer.h"
22+
23+
using namespace clang::ast_matchers;
24+
25+
namespace clang::tidy::bugprone {
26+
27+
/// Check that at least one branch of the \p If statement is a \c CompoundStmt.
28+
static bool shouldHaveBraces(const IfStmt *If) {
29+
const Stmt *const Then = If->getThen();
30+
if (isa<CompoundStmt>(Then))
31+
return true;
32+
33+
const Stmt *const Else = If->getElse();
34+
if (const auto *NestedIf = dyn_cast<const IfStmt>(Else))
35+
return shouldHaveBraces(NestedIf);
36+
37+
return isa<CompoundStmt>(Else);
38+
}
39+
40+
void InconsistentIfelseBracesCheck::registerMatchers(MatchFinder *Finder) {
41+
Finder->addMatcher(
42+
traverse(TK_IgnoreUnlessSpelledInSource,
43+
ifStmt(hasElse(anything()), unless(hasParent(ifStmt())))
44+
.bind("if_stmt")),
45+
this);
46+
}
47+
48+
void InconsistentIfelseBracesCheck::check(
49+
const MatchFinder::MatchResult &Result) {
50+
const auto *MatchedIf = Result.Nodes.getNodeAs<IfStmt>("if_stmt");
51+
if (!shouldHaveBraces(MatchedIf))
52+
return;
53+
54+
checkIfStmt(Result, MatchedIf);
55+
}
56+
57+
void InconsistentIfelseBracesCheck::checkIfStmt(
58+
const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If) {
59+
const Stmt *Then = If->getThen();
60+
if (!isa<CompoundStmt>(Then))
61+
checkStmt(Result, If->getThen(), If->getRParenLoc(), If->getElseLoc());
62+
63+
const Stmt *const Else = If->getElse();
64+
if (const auto *NestedIf = dyn_cast<const IfStmt>(Else))
65+
return checkIfStmt(Result, NestedIf);
66+
67+
if (!isa<CompoundStmt>(Else))
68+
checkStmt(Result, If->getElse(), If->getElseLoc());
69+
}
70+
71+
void InconsistentIfelseBracesCheck::checkStmt(
72+
const ast_matchers::MatchFinder::MatchResult &Result, const Stmt *S,
73+
SourceLocation StartLoc, SourceLocation EndLocHint) {
74+
const SourceManager &SM = *Result.SourceManager;
75+
const LangOptions &LangOpts = Result.Context->getLangOpts();
76+
77+
const utils::BraceInsertionHints Hints =
78+
utils::getBraceInsertionsHints(S, LangOpts, SM, StartLoc, EndLocHint);
79+
if (Hints) {
80+
auto Diag = diag(Hints.DiagnosticPos, "braces here!");
81+
if (Hints.offersFixIts()) {
82+
Diag << Hints.openingBraceFixIt() << Hints.closingBraceFixIt();
83+
}
84+
}
85+
}
86+
} // namespace clang::tidy::bugprone
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCONSISTENTIFELSEBRACESCHECK_H
11+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCONSISTENTIFELSEBRACESCHECK_H
12+
13+
#include "../ClangTidyCheck.h"
14+
15+
namespace clang::tidy::bugprone {
16+
17+
/// FIXME: Write a short description.
18+
///
19+
/// For the user-facing documentation see:
20+
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/inconsistent-ifelse-braces.html
21+
class InconsistentIfelseBracesCheck : public ClangTidyCheck {
22+
public:
23+
InconsistentIfelseBracesCheck(StringRef Name, ClangTidyContext *Context)
24+
: ClangTidyCheck(Name, Context) {}
25+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
26+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
27+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
28+
return LangOpts.CPlusPlus;
29+
}
30+
31+
private:
32+
void checkIfStmt(const ast_matchers::MatchFinder::MatchResult &Result,
33+
const IfStmt *If);
34+
void checkStmt(const ast_matchers::MatchFinder::MatchResult &Result,
35+
const Stmt *S, SourceLocation StartLoc,
36+
SourceLocation EndLocHint = SourceLocation());
37+
};
38+
39+
} // namespace clang::tidy::bugprone
40+
41+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCONSISTENTIFELSEBRACESCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ Improvements to clang-tidy
157157
New checks
158158
^^^^^^^^^^
159159

160+
- New :doc:`bugprone-inconsistent-ifelse-braces
161+
<clang-tidy/checks/bugprone/inconsistent-ifelse-braces>` check.
162+
163+
FIXME: Write a short description.
164+
160165
- New :doc:`bugprone-invalid-enum-default-initialization
161166
<clang-tidy/checks/bugprone/invalid-enum-default-initialization>` check.
162167

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. title:: clang-tidy - bugprone-inconsistent-ifelse-braces
2+
3+
bugprone-inconsistent-ifelse-braces
4+
===================================
5+
6+
FIXME: Describe what patterns does the check detect and why. Give examples.

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ Clang-Tidy Checks
101101
:doc:`bugprone-implicit-widening-of-multiplication-result <bugprone/implicit-widening-of-multiplication-result>`, "Yes"
102102
:doc:`bugprone-inaccurate-erase <bugprone/inaccurate-erase>`, "Yes"
103103
:doc:`bugprone-inc-dec-in-conditions <bugprone/inc-dec-in-conditions>`,
104+
:doc:`bugprone-inconsistent-ifelse-braces <bugprone/inconsistent-ifelse-braces>`,
104105
:doc:`bugprone-incorrect-enable-if <bugprone/incorrect-enable-if>`, "Yes"
105106
:doc:`bugprone-incorrect-enable-shared-from-this <bugprone/incorrect-enable-shared-from-this>`, "Yes"
106107
:doc:`bugprone-incorrect-roundings <bugprone/incorrect-roundings>`,
@@ -256,7 +257,7 @@ Clang-Tidy Checks
256257
:doc:`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>`,
257258
:doc:`llvm-twine-local <llvm/twine-local>`, "Yes"
258259
:doc:`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>`, "Yes"
259-
:doc:`llvm-use-ranges <llvm/use-ranges>`, "Yes"
260+
:doc:`llvm-use-ranges <llvm/use-ranges>`,
260261
:doc:`llvmlibc-callee-namespace <llvmlibc/callee-namespace>`,
261262
:doc:`llvmlibc-implementation-in-namespace <llvmlibc/implementation-in-namespace>`,
262263
:doc:`llvmlibc-inline-function-decl <llvmlibc/inline-function-decl>`, "Yes"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %check_clang_tidy %s bugprone-inconsistent-ifelse-braces %t
2+
3+
void f(bool flag) {
4+
int x, y;
5+
6+
if (flag)
7+
x = 0;
8+
else if (flag)
9+
y = 1;
10+
else {
11+
y = 2;
12+
}
13+
14+
if (flag) {
15+
x = 0;
16+
} else
17+
y = 1;
18+
19+
if (flag) {
20+
x = 0;
21+
} else
22+
;
23+
24+
if (flag)
25+
x = 0;
26+
else
27+
y = 1;
28+
}
29+
30+
// FIXME: Add something that triggers the check here.
31+
// void f();
32+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [bugprone-inconsistent-ifelse-braces]
33+
34+
// FIXME: Verify the applied fix.
35+
// * Make the CHECK patterns specific enough and try to make verified lines
36+
// unique to avoid incorrect matches.
37+
// * Use {{}} for regular expressions.
38+
// CHECK-FIXES: {{^}}void awesome_f();{{$}}
39+
40+
// FIXME: Add something that doesn't trigger the check here.
41+
void awesome_f2();

0 commit comments

Comments
 (0)