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
|
add_clang_library(clangTidyCppCoreGuidelinesModule
|
||||||
AvoidConstOrRefDataMembersCheck.cpp
|
AvoidConstOrRefDataMembersCheck.cpp
|
||||||
|
AvoidDoWhileCheck.cpp
|
||||||
AvoidGotoCheck.cpp
|
AvoidGotoCheck.cpp
|
||||||
AvoidNonConstGlobalVariablesCheck.cpp
|
AvoidNonConstGlobalVariablesCheck.cpp
|
||||||
CppCoreGuidelinesTidyModule.cpp
|
CppCoreGuidelinesTidyModule.cpp
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "../modernize/UseOverrideCheck.h"
|
#include "../modernize/UseOverrideCheck.h"
|
||||||
#include "../readability/MagicNumbersCheck.h"
|
#include "../readability/MagicNumbersCheck.h"
|
||||||
#include "AvoidConstOrRefDataMembersCheck.h"
|
#include "AvoidConstOrRefDataMembersCheck.h"
|
||||||
|
#include "AvoidDoWhileCheck.h"
|
||||||
#include "AvoidGotoCheck.h"
|
#include "AvoidGotoCheck.h"
|
||||||
#include "AvoidNonConstGlobalVariablesCheck.h"
|
#include "AvoidNonConstGlobalVariablesCheck.h"
|
||||||
#include "InitVariablesCheck.h"
|
#include "InitVariablesCheck.h"
|
||||||
|
@ -50,6 +51,8 @@ public:
|
||||||
"cppcoreguidelines-avoid-c-arrays");
|
"cppcoreguidelines-avoid-c-arrays");
|
||||||
CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>(
|
CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>(
|
||||||
"cppcoreguidelines-avoid-const-or-ref-data-members");
|
"cppcoreguidelines-avoid-const-or-ref-data-members");
|
||||||
|
CheckFactories.registerCheck<AvoidDoWhileCheck>(
|
||||||
|
"cppcoreguidelines-avoid-do-while");
|
||||||
CheckFactories.registerCheck<AvoidGotoCheck>(
|
CheckFactories.registerCheck<AvoidGotoCheck>(
|
||||||
"cppcoreguidelines-avoid-goto");
|
"cppcoreguidelines-avoid-goto");
|
||||||
CheckFactories.registerCheck<readability::MagicNumbersCheck>(
|
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.
|
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
|
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-mt-unsafe <concurrency/mt-unsafe.html>`_,
|
||||||
`concurrency-thread-canceltype-asynchronous <concurrency/thread-canceltype-asynchronous.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-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-goto <cppcoreguidelines/avoid-goto.html>`_,
|
||||||
`cppcoreguidelines-avoid-non-const-global-variables <cppcoreguidelines/avoid-non-const-global-variables.html>`_,
|
`cppcoreguidelines-avoid-non-const-global-variables <cppcoreguidelines/avoid-non-const-global-variables.html>`_,
|
||||||
`cppcoreguidelines-init-variables <cppcoreguidelines/init-variables.html>`_, "Yes"
|
`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