Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -27,6 +27,7 @@ UseNullptrCheck.cpp UseOverrideCheck.cpp UseTransparentFunctorsCheck.cpp + UseUncaughtExceptionsCheck.cpp UseUsingCheck.cpp LINK_LIBS Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -33,6 +33,7 @@ #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" #include "UseTransparentFunctorsCheck.h" +#include "UseUncaughtExceptionsCheck.h" #include "UseUsingCheck.h" using namespace clang::ast_matchers; @@ -78,6 +79,8 @@ CheckFactories.registerCheck("modernize-use-override"); CheckFactories.registerCheck( "modernize-use-transparent-functors"); + CheckFactories.registerCheck( + "modernize-use-uncaught-exceptions"); CheckFactories.registerCheck("modernize-use-using"); } Index: clang-tidy/modernize/UseUncaughtExceptionsCheck.h =================================================================== --- /dev/null +++ clang-tidy/modernize/UseUncaughtExceptionsCheck.h @@ -0,0 +1,37 @@ +//===--- UseUncaughtExceptionsCheck.h - clang-tidy------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_UNCAUGHT_EXCEPTIONS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_UNCAUGHT_EXCEPTIONS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// This check will warn on calls to std::uncaught_exception and replace them with calls to +/// std::uncaught_exceptions, since std::uncaught_exception was deprecated in C++17. In case of +/// macro ID there will be only a warning without fixits. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-uncaught-exceptions.html +class UseUncaughtExceptionsCheck : public ClangTidyCheck { +public: + UseUncaughtExceptionsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_UNCAUGHT_EXCEPTIONS_H Index: clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp @@ -0,0 +1,104 @@ +//===--- UseUncaughtExceptionsCheck.cpp - clang-tidy--------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UseUncaughtExceptionsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus17) + return; + + std::string MatchText = "::std::uncaught_exception"; + + // Using declaration: warning and fix-it. + Finder->addMatcher( + usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(hasName(MatchText)))) + .bind("using_decl"), + this); + + // DeclRefExpr: warning, no fix-it. + Finder->addMatcher(declRefExpr(allOf(to(functionDecl(hasName(MatchText))), + unless(callExpr()))) + .bind("decl_ref_expr"), + this); + + // CallExpr: warning, fix-it. + Finder->addMatcher( + callExpr(allOf(hasDeclaration(functionDecl(hasName(MatchText))), + unless(hasAncestor(initListExpr())))) + .bind("call_expr"), + this); + // CallExpr in initialisation list: warning, fix-it with avoiding narrowing + // conversions. + Finder->addMatcher( + callExpr(allOf(hasAncestor(initListExpr()), + hasDeclaration(functionDecl(hasName(MatchText))))) + .bind("init_call_expr"), + this); +} + +void UseUncaughtExceptionsCheck::check(const MatchFinder::MatchResult &Result) { + SourceLocation BeginLoc; + SourceLocation EndLoc; + const CallExpr *C = Result.Nodes.getNodeAs("init_call_expr"); + bool WarnOnly = false; + + if (C) { + BeginLoc = C->getLocStart(); + EndLoc = C->getLocEnd(); + } else if (const auto *E = Result.Nodes.getNodeAs("call_expr")) { + BeginLoc = E->getLocStart(); + EndLoc = E->getLocEnd(); + } else if (const auto *D = + Result.Nodes.getNodeAs("decl_ref_expr")) { + BeginLoc = D->getLocStart(); + EndLoc = D->getLocEnd(); + WarnOnly = true; + } else { + const auto *U = Result.Nodes.getNodeAs("using_decl"); + assert(U && "Null pointer, no node provided"); + BeginLoc = U->getNameInfo().getBeginLoc(); + EndLoc = U->getNameInfo().getEndLoc(); + } + + auto Diag = diag(BeginLoc, "'std::uncaught_exception' is deprecated, use " + "'std::uncaught_exceptions' instead"); + + if (!BeginLoc.isMacroID()) { + StringRef Text = + Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), + *Result.SourceManager, getLangOpts()); + + Text.consume_back("()"); + int TextLength = Text.size(); + + if (WarnOnly) { + return; + } + + if (!C) { + Diag << FixItHint::CreateInsertion(BeginLoc.getLocWithOffset(TextLength), + "s"); + } else { + Diag << FixItHint::CreateReplacement(C->getSourceRange(), + "std::uncaught_exceptions() > 0"); + } + } +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -64,6 +64,11 @@ object is statically initialized with a ``constexpr`` constructor or has no explicit constructor. +- New `modernize-use-uncaught-exceptions + `_ check + + Finds and replaces deprecated uses of std::uncaught_exception to std::uncaught_exceptions() + Improvements to include-fixer ----------------------------- Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -173,6 +173,7 @@ modernize-use-nullptr modernize-use-override modernize-use-transparent-functors + modernize-use-uncaught-exceptions modernize-use-using mpi-buffer-deref mpi-type-mismatch Index: docs/clang-tidy/checks/modernize-use-uncaught-exceptions.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/modernize-use-uncaught-exceptions.rst @@ -0,0 +1,64 @@ +.. title:: clang-tidy - modernize-use-uncaught-exceptions + +modernize-use-uncaught-exceptions +==================================== + +This check will warn on calls to ``std::uncaught_exception`` and replace them with +calls to ``std::uncaught_exceptions``, since ``std::uncaught_exception`` was deprecated +in C++17. + +Below are a few examples of what kind of occurrences will be found and what +they will be replaced with. + +.. code-block:: c++ + + #define MACRO1 std::uncaught_exception + #define MACRO2 std::uncaught_exception + + int uncaught_exception() { + return 0; + } + + int main() { + int res; + + res = uncaught_exception(); + // No warning, since it is not the deprecated function from namespace std + + res = MACRO2(); + // Warning, but will not be replaced + + res = std::uncaught_exception(); + // Warning and replaced + + using std::uncaught_exception; + // Warning and replaced + + res = uncaught_exception(); + // Warning and replaced + } + +After applying the fixes the code will look like the following: + +.. code-block:: c++ + + #define MACRO1 std::uncaught_exception + #define MACRO2 std::uncaught_exception + + int uncaught_exception() { + return 0; + } + + int main() { + int res; + + res = uncaught_exception(); + + res = MACRO2(); + + res = std::uncaught_exceptions(); + + using std::uncaught_exceptions; + + res = uncaught_exceptions(); + } Index: test/clang-tidy/modernize-use-uncaught-exceptions.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-use-uncaught-exceptions.cpp @@ -0,0 +1,79 @@ +// RUN: %check_clang_tidy %s modernize-use-uncaught-exceptions %t -- -- -std=c++1z +#define MACRO std::uncaught_exception +// CHECK-FIXES: #define MACRO std::uncaught_exception + +bool uncaught_exception() { + return 0; +} + +namespace std { + bool uncaught_exception() { + return false; + } + + int uncaught_exceptions() { + return 0; + } +} + +template +bool doSomething(T t) { + return t(); + // CHECK-FIXES: return t(); +} + +template +bool doSomething2() { + return T(); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: return T(); +} + +void no_warn() { + + uncaught_exception(); + // CHECK-FIXES: uncaught_exception(); + + doSomething(uncaught_exception); + // CHECK-FIXES: doSomething(uncaught_exception); +} + +void warn() { + + std::uncaught_exception(); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: std::uncaught_exceptions(); + + using std::uncaught_exception; + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: using std::uncaught_exceptions; + + uncaught_exception(); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: uncaught_exceptions(); + + bool b{uncaught_exception()}; + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: bool b{std::uncaught_exceptions() > 0}; + + MACRO(); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: MACRO(); + + doSomething(std::uncaught_exception); + // CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: doSomething(std::uncaught_exception); + + doSomething(uncaught_exception); + // CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: doSomething(uncaught_exception); + + bool (*foo)(); + foo = &uncaught_exception; + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: foo = &uncaught_exception; + + doSomething2(); + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead + // CHECK-FIXES: doSomething2(); +}