forked from OSchip/llvm-project
[clang-tidy] Add cppcoreguidelines-avoid-do-while check
Implements rule ES.75 of C++ Core Guidelines. Differential Revision: https://reviews.llvm.org/D132461
This commit is contained in:
parent
0cf70a33f2
commit
1ae33bf426
|
@ -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
|
|
@ -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
|
|
@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
|
||||
add_clang_library(clangTidyCppCoreGuidelinesModule
|
||||
AvoidConstOrRefDataMembersCheck.cpp
|
||||
AvoidDoWhileCheck.cpp
|
||||
AvoidGotoCheck.cpp
|
||||
AvoidNonConstGlobalVariablesCheck.cpp
|
||||
CppCoreGuidelinesTidyModule.cpp
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "../modernize/UseOverrideCheck.h"
|
||||
#include "../readability/MagicNumbersCheck.h"
|
||||
#include "AvoidConstOrRefDataMembersCheck.h"
|
||||
#include "AvoidDoWhileCheck.h"
|
||||
#include "AvoidGotoCheck.h"
|
||||
#include "AvoidNonConstGlobalVariablesCheck.h"
|
||||
#include "InitVariablesCheck.h"
|
||||
|
@ -50,6 +51,8 @@ public:
|
|||
"cppcoreguidelines-avoid-c-arrays");
|
||||
CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>(
|
||||
"cppcoreguidelines-avoid-const-or-ref-data-members");
|
||||
CheckFactories.registerCheck<AvoidDoWhileCheck>(
|
||||
"cppcoreguidelines-avoid-do-while");
|
||||
CheckFactories.registerCheck<AvoidGotoCheck>(
|
||||
"cppcoreguidelines-avoid-goto");
|
||||
CheckFactories.registerCheck<readability::MagicNumbersCheck>(
|
||||
|
|
|
@ -110,6 +110,11 @@ New checks
|
|||
|
||||
Warns when a struct or class uses const or reference (lvalue or rvalue) data members.
|
||||
|
||||
- New :doc:`cppcoreguidelines-avoid-do-while
|
||||
<clang-tidy/checks/cppcoreguidelines/avoid-do-while>` check.
|
||||
|
||||
Warns when using ``do-while`` loops.
|
||||
|
||||
New check aliases
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -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`.
|
|
@ -178,6 +178,7 @@ Clang-Tidy Checks
|
|||
`concurrency-mt-unsafe <concurrency/mt-unsafe.html>`_,
|
||||
`concurrency-thread-canceltype-asynchronous <concurrency/thread-canceltype-asynchronous.html>`_,
|
||||
`cppcoreguidelines-avoid-const-or-ref-data-members <cppcoreguidelines/avoid-const-or-ref-data-members.html>`_,
|
||||
`cppcoreguidelines-avoid-do-while <cppcoreguidelines/avoid-do-while.html>`_,
|
||||
`cppcoreguidelines-avoid-goto <cppcoreguidelines/avoid-goto.html>`_,
|
||||
`cppcoreguidelines-avoid-non-const-global-variables <cppcoreguidelines/avoid-non-const-global-variables.html>`_,
|
||||
`cppcoreguidelines-init-variables <cppcoreguidelines/init-variables.html>`_, "Yes"
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue