[clang-tidy] Disable Checks on If constexpr statements in template Instantiations for BugproneBranchClone and ReadabilityBracesAroundStatements

Summary: fixes [[ https://bugs.llvm.org/show_bug.cgi?id=32203 | readability-braces-around-statements broken for if constexpr]] and [[ https://bugs.llvm.org/show_bug.cgi?id=44229 | bugprone-branch-clone false positive with template functions and constexpr ]] by disabling the relevant checks on if constexpr statements while inside an instantiated template. This is due to how the else branch of an if constexpr statement is folded away to a null statement if the condition evaluates to false

Reviewers: alexfh, hokein, aaron.ballman, xazax.hun

Reviewed By: aaron.ballman, xazax.hun

Subscribers: rnkovacs, JonasToth, Jim, lebedev.ri, xazax.hun, cfe-commits

Tags: #clang-tools-extra, #clang

Differential Revision: https://reviews.llvm.org/D71980
This commit is contained in:
Nathan 2019-12-31 09:57:16 +00:00
parent 8eb4d25a09
commit f9c46229e4
4 changed files with 112 additions and 2 deletions

View File

@ -59,7 +59,8 @@ namespace bugprone {
void BranchCloneCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
ifStmt(stmt().bind("if"),
ifStmt(unless(allOf(isConstexpr(), isInTemplateInstantiation())),
stmt().bind("if"),
hasParent(stmt(unless(ifStmt(hasElse(equalsBoundNode("if")))))),
hasElse(stmt().bind("else"))),
this);

View File

@ -123,7 +123,10 @@ void BracesAroundStatementsCheck::storeOptions(
}
void BracesAroundStatementsCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(ifStmt().bind("if"), this);
Finder->addMatcher(
ifStmt(unless(allOf(isConstexpr(), isInTemplateInstantiation())))
.bind("if"),
this);
Finder->addMatcher(whileStmt().bind("while"), this);
Finder->addMatcher(doStmt().bind("do"), this);
Finder->addMatcher(forStmt().bind("for"), this);

View File

@ -0,0 +1,58 @@
// RUN: %check_clang_tidy %s bugprone-branch-clone %t -- -- -std=c++17
void handle(int);
template <unsigned Index>
void shouldFail() {
if constexpr (Index == 0) {
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: repeated branch in conditional chain [bugprone-branch-clone]
handle(0);
} else if constexpr (Index == 1) {
handle(1);
} else {
handle(0);
}
}
template <unsigned Index>
void shouldPass() {
if constexpr (Index == 0) {
handle(0);
} else if constexpr (Index == 1) {
handle(1);
} else {
handle(2);
}
}
void shouldFailNonTemplate() {
constexpr unsigned Index = 1;
if constexpr (Index == 0) {
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: repeated branch in conditional chain [bugprone-branch-clone]
handle(0);
} else if constexpr (Index == 1) {
handle(1);
} else {
handle(0);
}
}
void shouldPassNonTemplate() {
constexpr unsigned Index = 1;
if constexpr (Index == 0) {
handle(0);
} else if constexpr (Index == 1) {
handle(1);
} else {
handle(2);
}
}
void run() {
shouldFail<0>();
shouldFail<1>();
shouldFail<2>();
shouldPass<0>();
shouldPass<1>();
shouldPass<2>();
}

View File

@ -0,0 +1,48 @@
// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -- -std=c++17
void handle(bool);
template <bool branch>
void shouldFail() {
if constexpr (branch)
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: statement should be inside braces [readability-braces-around-statements]
handle(true);
else
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: statement should be inside braces [readability-braces-around-statements]
handle(false);
}
template <bool branch>
void shouldPass() {
if constexpr (branch) {
handle(true);
} else {
handle(false);
}
}
void shouldFailNonTemplate() {
constexpr bool branch = false;
if constexpr (branch)
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: statement should be inside braces [readability-braces-around-statements]
handle(true);
else
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: statement should be inside braces [readability-braces-around-statements]
handle(false);
}
void shouldPass() {
constexpr bool branch = false;
if constexpr (branch) {
handle(true);
} else {
handle(false);
}
}
void run() {
shouldFail<true>();
shouldFail<false>();
shouldPass<true>();
shouldPass<false>();
}