-
Notifications
You must be signed in to change notification settings - Fork 12.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clang-tidy] Add cppcoreguidelines-avoid-do-while check
Implements rule ES.75 of C++ Core Guidelines. Differential Revision: https://reviews.llvm.org/D132461
- Loading branch information
1 parent
0cf70a3
commit 1ae33bf
Showing
8 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
41 changes: 41 additions & 0 deletions
41
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidDoWhileCheck.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//===--- AvoidDoWhileCheck.cpp - clang-tidy -------------------------------===// | ||
// | ||
// 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 "AvoidDoWhileCheck.h" | ||
#include "clang/AST/ASTContext.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
|
||
using namespace clang::ast_matchers; | ||
|
||
namespace clang { | ||
namespace tidy { | ||
namespace cppcoreguidelines { | ||
|
||
AvoidDoWhileCheck::AvoidDoWhileCheck(StringRef Name, ClangTidyContext *Context) | ||
: ClangTidyCheck(Name, Context), | ||
IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", false)) {} | ||
|
||
void AvoidDoWhileCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { | ||
Options.store(Opts, "IgnoreMacros", IgnoreMacros); | ||
} | ||
|
||
void AvoidDoWhileCheck::registerMatchers(MatchFinder *Finder) { | ||
Finder->addMatcher(doStmt().bind("x"), this); | ||
} | ||
|
||
void AvoidDoWhileCheck::check(const MatchFinder::MatchResult &Result) { | ||
if (const auto *MatchedDecl = Result.Nodes.getNodeAs<DoStmt>("x")) { | ||
if (IgnoreMacros && MatchedDecl->getBeginLoc().isMacroID()) | ||
return; | ||
diag(MatchedDecl->getBeginLoc(), "avoid do-while loops"); | ||
} | ||
} | ||
|
||
} // namespace cppcoreguidelines | ||
} // namespace tidy | ||
} // namespace clang |
41 changes: 41 additions & 0 deletions
41
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidDoWhileCheck.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//===--- AvoidDoWhileCheck.h - clang-tidy -----------------------*- C++ -*-===// | ||
// | ||
// 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_CPPCOREGUIDELINES_AVOIDDOWHILECHECK_H | ||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDDOWHILECHECK_H | ||
|
||
#include "../ClangTidyCheck.h" | ||
|
||
namespace clang { | ||
namespace tidy { | ||
namespace cppcoreguidelines { | ||
|
||
/// do-while loops are less readable than plan while loops, and can lead to | ||
/// subtle bugs. | ||
/// | ||
/// For the user-facing documentation see: | ||
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/avoid-do-while.html | ||
class AvoidDoWhileCheck : public ClangTidyCheck { | ||
public: | ||
AvoidDoWhileCheck(StringRef Name, ClangTidyContext *Context); | ||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { | ||
return LangOpts.CPlusPlus; | ||
} | ||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override; | ||
void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
|
||
private: | ||
bool IgnoreMacros; | ||
}; | ||
|
||
} // namespace cppcoreguidelines | ||
} // namespace tidy | ||
} // namespace clang | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDDOWHILECHECK_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-do-while.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
.. title:: clang-tidy - cppcoreguidelines-avoid-do-while | ||
|
||
cppcoreguidelines-avoid-do-while | ||
================================ | ||
|
||
Warns when using ``do-while`` loops. They are less readable than plain ``while`` | ||
loops, since the termination condition is at the end and the condition is not | ||
checked prior to the first iteration. This can lead to subtle bugs. | ||
|
||
The check implements | ||
`rule ES.75 of C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-do>`_. | ||
|
||
Examples: | ||
|
||
.. code-block:: c++ | ||
|
||
int x; | ||
do { | ||
std::cin >> x; | ||
// ... | ||
} while (x < 0); | ||
|
||
Options | ||
------- | ||
|
||
.. option:: IgnoreMacros | ||
|
||
Ignore the check when analyzing macros. This is useful for safely defining function-like macros: | ||
|
||
.. code-block:: c++ | ||
|
||
#define FOO_BAR(x) \ | ||
do { \ | ||
foo(x); \ | ||
bar(x); \ | ||
} while(0) | ||
|
||
Defaults to `false`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-do-while.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// RUN: %check_clang_tidy -check-suffixes=DEFAULT %s cppcoreguidelines-avoid-do-while %t | ||
// RUN: %check_clang_tidy -check-suffixes=IGNORE-MACROS %s cppcoreguidelines-avoid-do-while %t -- -config='{CheckOptions: [{key: cppcoreguidelines-avoid-do-while.IgnoreMacros, value: true}]}' | ||
|
||
#define FOO(x) \ | ||
do { \ | ||
} while (x != 0) | ||
|
||
#define BAR_0(x) \ | ||
do { \ | ||
bar(x); \ | ||
} while (0) | ||
|
||
#define BAR_FALSE(x) \ | ||
do { \ | ||
bar(x); \ | ||
} while (false) | ||
|
||
void bar(int); | ||
int baz(); | ||
|
||
void foo() | ||
{ | ||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+2]]:5: warning: avoid do-while loops [cppcoreguidelines-avoid-do-while] | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops [cppcoreguidelines-avoid-do-while] | ||
do { | ||
|
||
} while(0); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
do { | ||
|
||
} while(1); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
do { | ||
|
||
} while(-1); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
do { | ||
|
||
} while(false); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
do { | ||
|
||
} while(true); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+3]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
int x1{0}; | ||
do { | ||
x1 = baz(); | ||
} while (x1 > 0); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
do { | ||
|
||
} while (x1 != 0); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+3]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
constexpr int x2{0}; | ||
do { | ||
|
||
} while (x2); | ||
|
||
// CHECK-MESSAGES-IGNORE-MACROS: :[[@LINE+3]]:5: warning: avoid do-while loops | ||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+2]]:5: warning: avoid do-while loops | ||
constexpr bool x3{false}; | ||
do { | ||
|
||
} while (x3); | ||
|
||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
FOO(x1); | ||
|
||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
BAR_0(x1); | ||
|
||
// CHECK-MESSAGES-DEFAULT: :[[@LINE+1]]:5: warning: avoid do-while loops | ||
BAR_FALSE(x1); | ||
} |