Index: clang-tidy/modernize/UseNoexceptCheck.h =================================================================== --- clang-tidy/modernize/UseNoexceptCheck.h +++ clang-tidy/modernize/UseNoexceptCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H #include "../ClangTidy.h" +#include "../utils/ExceptionAnalyzer.h" namespace clang { namespace tidy { @@ -38,7 +39,9 @@ private: const std::string NoexceptMacro; - bool UseNoexceptFalse; + const bool UseNoexceptFalse; + const bool AddMissingNoexcept; + utils::ExceptionAnalyzer Analyzer; }; } // namespace modernize Index: clang-tidy/modernize/UseNoexceptCheck.cpp =================================================================== --- clang-tidy/modernize/UseNoexceptCheck.cpp +++ clang-tidy/modernize/UseNoexceptCheck.cpp @@ -19,11 +19,13 @@ UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), NoexceptMacro(Options.get("ReplacementString", "")), - UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {} + UseNoexceptFalse(Options.get("UseNoexceptFalse", true)), + AddMissingNoexcept(Options.get("AddMissingNoexcept", false)) {} void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "ReplacementString", NoexceptMacro); Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse); + Options.store(Opts, "AddMissingNoexcept", AddMissingNoexcept); } void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) { @@ -56,6 +58,14 @@ functionProtoType(hasDynamicExceptionSpec())))))))) .bind("parmVarDecl"), this); + + if (AddMissingNoexcept) + Finder->addMatcher( + functionDecl(allOf(hasBody(stmt()), + unless(anyOf(isNoThrow(), hasDynamicExceptionSpec(), + isImplicit())))) + .bind("potentialNoexcept"), + this); } void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) { @@ -82,6 +92,14 @@ .IgnoreParens() .castAs() .getExceptionSpecRange(); + } else if (const auto *PotentialNoexcept = + Result.Nodes.getNodeAs("potentialNoexcept")) { + if (!Analyzer.throwsException(PotentialNoexcept) && + PotentialNoexcept->getBeginLoc().isValid()) + diag(PotentialNoexcept->getBeginLoc(), + "this function can not throw an exception, consider adding " + "'noexcept'"); + return; } CharSourceRange CRange = Lexer::makeFileCharRange( CharSourceRange::getTokenRange(Range), *Result.SourceManager, @@ -92,10 +110,10 @@ StringRef ReplacementStr = IsNoThrow ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro.c_str() - : NoexceptMacro.empty() - ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)" - : "" - : ""; + : NoexceptMacro.empty() ? (DtorOrOperatorDel || UseNoexceptFalse) + ? "noexcept(false)" + : "" + : ""; FixItHint FixIt; if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid()) Index: test/clang-tidy/modernize-use-noexcept-new-noexcept.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-use-noexcept-new-noexcept.cpp @@ -0,0 +1,46 @@ +// RUN: %check_clang_tidy %s modernize-use-noexcept %t -- \ +// RUN: -config="{CheckOptions: [{key: modernize-use-noexcept.AddMissingNoexcept, value: 1}]}" \ +// RUN: -- -std=c++11 -fexceptions + +void undefined(); +void undefinedNoexcept() noexcept; + +void empty() {} +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: this function can not throw an exception, consider adding 'noexcept' + +int tryCatchBody() try { + int Array[] = {1, 2, 3, 4}; + throw int(42); + return Array[0] + Array[1] + Array[2] + Array[3]; +} catch (...) { + return 42; +} +// CHECK-MESSAGES: :[[@LINE-7]]:1: warning: this function can not throw an exception, consider adding 'noexcept' + +int functionCanThrow() { + throw int(42); +} + +struct ConstructorWithNoexcept { + ConstructorWithNoexcept() = default; + int nonThrowingMember() { return 42; } + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this function can not throw an exception, consider adding 'noexcept' + int nonThrowingButShown() noexcept { return 42; } + void undefinedMethod(); + int Member; +}; + +template +void nonThrowingTemplateUnknown(); + +template +T nonThrowingTemplateKnown() { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: this function can not throw an exception, consider adding 'noexcept' + return T{}; +} +void instantiate() { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: this function can not throw an exception, consider adding 'noexcept' + (void)nonThrowingTemplateKnown(); + (void)nonThrowingTemplateKnown(); + (void)nonThrowingTemplateKnown(); +} Index: test/clang-tidy/modernize-use-noexcept-opt.cpp =================================================================== --- test/clang-tidy/modernize-use-noexcept-opt.cpp +++ test/clang-tidy/modernize-use-noexcept-opt.cpp @@ -65,11 +65,11 @@ struct S { void f() throw(); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] +// CHECK-FIXES: void f() noexcept; }; void f(void (S::*)() throw()); -// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] -// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] -// CHECK-FIXES: void f() noexcept; +// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] // CHECK-FIXES: void f(void (S::*)() noexcept); typedef void (*fp)(void (*fp2)(int) throw()); Index: test/clang-tidy/modernize-use-noexcept.cpp =================================================================== --- test/clang-tidy/modernize-use-noexcept.cpp +++ test/clang-tidy/modernize-use-noexcept.cpp @@ -10,9 +10,9 @@ template void foo() throw(); -void footest() { foo(); foo(); } -// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] // CHECK-FIXES: void foo() noexcept; +void footest() { foo(); foo(); } void bar() throw(...); // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw(...)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept] @@ -70,21 +70,21 @@ struct S { void f() throw(); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] }; void f(void (S::*)() throw()); -// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] -// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] +// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] // CHECK-FIXES: void f() noexcept; // CHECK-FIXES: void f(void (S::*)() noexcept); template struct ST { void foo() throw(); +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] }; template void ft(void (ST::*)() throw()); -// CHECK-MESSAGES: :[[@LINE-4]]:14: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] -// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] +// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept] // CHECK-FIXES: void foo() noexcept; // CHECK-FIXES: void ft(void (ST::*)() noexcept);