diff --git a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp @@ -59,7 +59,8 @@ 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); diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp @@ -123,7 +123,10 @@ } 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); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone-if-constexpr-template.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone-if-constexpr-template.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone-if-constexpr-template.cpp @@ -0,0 +1,58 @@ +// RUN: %check_clang_tidy %s bugprone-branch-clone %t -- -- -std=c++17 + +void handle(int); + +template +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 +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>(); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-braces-around-statements-constexpr-if-templates.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-braces-around-statements-constexpr-if-templates.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-braces-around-statements-constexpr-if-templates.cpp @@ -0,0 +1,48 @@ +// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -- -std=c++17 + +void handle(bool); + +template +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 +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(); + shouldFail(); + shouldPass(); + shouldPass(); +}