Index: clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.h =================================================================== --- clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.h +++ clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ASSERTSIDEEFFECTCHECK_H #include "../ClangTidyCheck.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include @@ -33,6 +34,7 @@ /// can increase the number of false positive warnings. class AssertSideEffectCheck : public ClangTidyCheck { public: + using IgnoredFunctionType = llvm::SmallSet; AssertSideEffectCheck(StringRef Name, ClangTidyContext *Context); void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; @@ -41,7 +43,9 @@ private: const bool CheckFunctionCalls; const std::string RawAssertList; + const std::string RawIgnoredFunctionList; SmallVector AssertMacros; + IgnoredFunctionType IgnoredFunctions; }; } // namespace bugprone Index: clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp +++ clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp @@ -25,7 +25,8 @@ namespace { -AST_MATCHER_P(Expr, hasSideEffect, bool, CheckFunctionCalls) { +AST_MATCHER_P2(Expr, hasSideEffect, bool, CheckFunctionCalls, + AssertSideEffectCheck::IgnoredFunctionType, FunctionExceptions) { const Expr *E = &Node; if (const auto *Op = dyn_cast(E)) { @@ -55,7 +56,8 @@ bool Result = CheckFunctionCalls; if (const auto *FuncDecl = CExpr->getDirectCallee()) { if (FuncDecl->getDeclName().isIdentifier() && - FuncDecl->getName() == "__builtin_expect") // exceptions come here + FunctionExceptions.contains( + FuncDecl->getName())) // exceptions come here Result = false; else if (const auto *MethodDecl = dyn_cast(FuncDecl)) Result &= !MethodDecl->isConst(); @@ -72,20 +74,28 @@ ClangTidyContext *Context) : ClangTidyCheck(Name, Context), CheckFunctionCalls(Options.get("CheckFunctionCalls", false)), - RawAssertList(Options.get("AssertMacros", - "assert,NSAssert,NSCAssert")) { + RawAssertList(Options.get("AssertMacros", "assert,NSAssert,NSCAssert")), + RawIgnoredFunctionList("__builtin_expect," + + Options.get("IgnoredFunctions", "")) { StringRef(RawAssertList).split(AssertMacros, ",", -1, false); + SmallVector IgnoredFunctionVector; + StringRef(RawIgnoredFunctionList) + .split(IgnoredFunctionVector, ",", -1, false); + IgnoredFunctions.insert(IgnoredFunctionVector.begin(), + IgnoredFunctionVector.end()); } // The options are explained in AssertSideEffectCheck.h. void AssertSideEffectCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "CheckFunctionCalls", CheckFunctionCalls); Options.store(Opts, "AssertMacros", RawAssertList); + Options.store(Opts, "IgnoredFunctions", RawIgnoredFunctionList); } void AssertSideEffectCheck::registerMatchers(MatchFinder *Finder) { - auto DescendantWithSideEffect = - traverse(TK_AsIs, hasDescendant(expr(hasSideEffect(CheckFunctionCalls)))); + auto DescendantWithSideEffect = traverse( + TK_AsIs, + hasDescendant(expr(hasSideEffect(CheckFunctionCalls, IgnoredFunctions)))); auto ConditionWithSideEffect = hasCondition(DescendantWithSideEffect); Finder->addMatcher( stmt( Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -145,7 +145,12 @@ Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ +- :doc:`bugprone-assert-side-effect ` + check now supports a ``IgnoredFunctions`` option to explicitly consider the specified + functions or methods as not any having side-effects. + - Removed default setting ``cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors = "true"``, + from :doc:`cppcoreguidelines-explicit-virtual-functions ` to match the current state of the C++ Core Guidelines. - Updated :doc:`google-readability-casting @@ -157,10 +162,10 @@ - Fixed a false positive in :doc:`bugprone-throw-keyword-missing ` when creating an exception object - using placement new + using placement new. - :doc:`cppcoreguidelines-narrowing-conversions ` - check now supports a `WarnOnIntegerToFloatingPointNarrowingConversion` + check now supports a ``WarnOnIntegerToFloatingPointNarrowingConversion`` option to control whether to warn on narrowing integer to floating-point conversions. Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-assert-side-effect.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/bugprone-assert-side-effect.rst +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-assert-side-effect.rst @@ -21,3 +21,8 @@ Whether to treat non-const member and non-member functions as they produce side effects. Disabled by default because it can increase the number of false positive warnings. + +.. option:: FunctionExceptions + + A comma-separated list of the names of functions or methods to be + considered as not having side-effects. Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-assert-side-effect.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-assert-side-effect.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-assert-side-effect.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s bugprone-assert-side-effect %t -- -config="{CheckOptions: [{key: bugprone-assert-side-effect.CheckFunctionCalls, value: true}, {key: bugprone-assert-side-effect.AssertMacros, value: 'assert,assert2,my_assert,convoluted_assert,msvc_assert'}]}" -- -fexceptions +// RUN: %check_clang_tidy %s bugprone-assert-side-effect %t -- -config="{CheckOptions: [{key: bugprone-assert-side-effect.CheckFunctionCalls, value: true}, {key: bugprone-assert-side-effect.AssertMacros, value: 'assert,assert2,my_assert,convoluted_assert,msvc_assert'}, {key: bugprone-assert-side-effect.IgnoredFunctions, value: 'badButIgnoredFunc'}]}" -- -fexceptions //===--- assert definition block ------------------------------------------===// int abort() { return 0; } @@ -46,6 +46,7 @@ class MyClass { public: bool badFunc(int a, int b) { return a * b > 0; } + bool badButIgnoredFunc(int a, int b) { return a * b > 0; } bool goodFunc(int a, int b) const { return a * b > 0; } MyClass &operator=(const MyClass &rhs) { return *this; } @@ -87,6 +88,7 @@ MyClass mc; assert(mc.badFunc(0, 1)); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: side effect in assert() condition discarded in release builds + assert(mc.badButIgnoredFunc(0, 1)); assert(mc.goodFunc(0, 1)); MyClass mc2;