Szelethus created this revision. Szelethus added reviewers: cfe-commits, xazax.hun. Szelethus added a project: clang-tools-extra. Herald added subscribers: hintonda, rnkovacs, mgorny.
New checker called misc-throw-keyword-missing warns about cases where a temporary object's type is (likely) an exception but is not thrown. This is done by checking whether the type's name (or one of its baseclass' name) contains the substring "EXCEPTION", "Exception" or "exception". void f(int i){ if(i = 0) // Exception is created but not thrown. std::runtime_error("Wrong argument"); } Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D43120 Files: clang-tidy/misc/CMakeLists.txt clang-tidy/misc/MiscTidyModule.cpp clang-tidy/misc/ThrowKeywordMissingCheck.cpp clang-tidy/misc/ThrowKeywordMissingCheck.h docs/ReleaseNotes.rst docs/clang-tidy/checks/list.rst docs/clang-tidy/checks/misc-throw-keyword-missing.rst test/clang-tidy/misc-throw-keyword-missing.cpp
Index: test/clang-tidy/misc-throw-keyword-missing.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-throw-keyword-missing.cpp @@ -0,0 +1,152 @@ +// RUN: %check_clang_tidy %s misc-throw-keyword-missing %t + +namespace std { + +// std::string declaration (taken from test/clang-tidy/readability-redundant-string-cstr-msvc.cpp) +template <typename T> +class allocator {}; +template <typename T> +class char_traits {}; +template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>> +struct basic_string { + basic_string(); + basic_string(const basic_string&); + // MSVC headers define two constructors instead of using optional arguments. + basic_string(const C *); + basic_string(const C *, const A &); + ~basic_string(); +}; +typedef basic_string<char> string; +typedef basic_string<wchar_t> wstring; + +// std::exception and std::runtime_error declaration +struct exception{ + exception(); + exception( const exception& other); + virtual ~exception(); +}; + +struct runtime_error : public exception{ + explicit runtime_error( const std::string& what_arg ); +}; + +} //namespace std + +// The usage of this class should never emit a warning +struct RegularClass {}; + +// Classname contains the substring "exception", in certain cases using this class should emit a warning +struct RegularException { + RegularException() {} + + // Constructors with a single argument are treated differently (cxxFunctionalCastExpr) + RegularException(int) {} +}; + +// -------------- + +void stdExceptionNotTrown(int i) { + if (i < 0) + //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception created but is not thrown [misc-throw-keyword-missing] + std::exception(); + + if (i > 0) + //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception created but is not thrown [misc-throw-keyword-missing] + std::runtime_error("Unexpected argument"); + +} + +void stdExceptionThrown(int i) { + if (i < 0) + throw std::exception(); + + if (i > 0) + throw std::runtime_error("Unexpected argument"); +} + +void regularClassNotThrown(int i) { + if (i < 0) + RegularClass(); +} + +void regularClassThrown(int i) { + if (i < 0) + throw RegularClass(); +} + +void nameContainsExceptionNotThrown(int i) { + if (i < 0) + //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception created but is not thrown [misc-throw-keyword-missing] + RegularException(); + + if (i > 0) + //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception created but is not thrown [misc-throw-keyword-missing] + RegularException(5); +} + +void nameContainsExceptionThrown(int i) { + if (i < 0) + throw RegularException(); + + if (i > 0) + throw RegularException(5); +} + + +template <class Exception> +void f(int i, Exception excToBeThrown){} + +void funcCallWithTempExcTest(){ + f(5, RegularException()); +} + +// Global variable initilization test +RegularException exc = RegularException(); +RegularException* excptr = new RegularException(); + +void localVariableInitTest(){ + RegularException exc = RegularException(); + RegularException* excptr = new RegularException(); +} + +class CtorInitializerListTest{ + RegularException exc; + + CtorInitializerListTest() : exc(RegularException()) {} + + CtorInitializerListTest(int) + try : exc(RegularException()) { + //Constructor + } + catch(...){ + //CHECK-MESSAGES: :[[@LINE+1]]:7: warning: exception created but is not thrown [misc-throw-keyword-missing] + RegularException(); + } + + CtorInitializerListTest(float); +}; + +CtorInitializerListTest::CtorInitializerListTest(float) + try : exc(RegularException()) { + //Constructor + } + catch(...){ + //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception created but is not thrown [misc-throw-keyword-missing] + RegularException(); + } + +RegularException funcReturningExceptioniTest(int i){ + return RegularException(); +} + +struct ClassBracedInitListTest{ + ClassBracedInitListTest(RegularException exc) {} +}; + +void functionBracedInitListTest(RegularException, ClassBracedInitListTest) {} + +void bracedInitListTest(){ + RegularException exc{}; + ClassBracedInitListTest test = {RegularException()}; + functionBracedInitListTest({}, {RegularException()}); +} Index: docs/clang-tidy/checks/misc-throw-keyword-missing.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-throw-keyword-missing.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - misc-throw-keyword-missing + +misc-throw-keyword-missing +========================== + +This check warns about the potentially missing `throw` keyword. If a temporary object is created, +but the object's type derives from (or the same as) a class that has 'EXCEPTION', 'Exception' or +'exception' in its name, we can assume that the programmer's intention was to throw that object. + +Example: + +.. code-block:: c++ + void f(int i) { + if(i < 0) { + // Exception is created but is not thrown + std::runtime_error("Unexpected argument"); + } + } + + Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -143,6 +143,7 @@ misc-suspicious-string-compare misc-swapped-arguments misc-throw-by-value-catch-by-reference + misc-throw-keyword-missing misc-unconventional-assign-operator misc-undelegated-constructor misc-uniqueptr-reset-release 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 `misc-throw-keyword-missing + <http://clang.llvm.org/extra/clang-tidy/checks/misc-throw-keyword-missing.html>`_ check + + Warns if a ``throw`` keyword is potentialy missing before a temporary exception object. + Improvements to include-fixer ----------------------------- Index: clang-tidy/misc/ThrowKeywordMissingCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/ThrowKeywordMissingCheck.h @@ -0,0 +1,36 @@ +//===--- ThrowKeywordMissingCheck.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_MISC_THROWKEYWORDMISSINGCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROWKEYWORDMISSINGCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Emits a warning about temporary objects whose type is (or is derived from) a +/// class that has 'EXCEPTION', 'Exception' or 'exception' in its name. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-throw-keyword-missing.html +class ThrowKeywordMissingCheck : public ClangTidyCheck { +public: + ThrowKeywordMissingCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROWKEYWORDMISSINGCHECK_H Index: clang-tidy/misc/ThrowKeywordMissingCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/ThrowKeywordMissingCheck.cpp @@ -0,0 +1,51 @@ +//===--- ThrowKeywordMissingCheck.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 "ThrowKeywordMissingCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) { + // This is a C++ only checker. + if (!getLangOpts().CPlusPlus) + return; + + auto CtorInitializerList = + cxxConstructorDecl(hasAnyConstructorInitializer(anything())); + + Finder->addMatcher( + expr(anyOf(cxxFunctionalCastExpr(), cxxBindTemporaryExpr(), + cxxTemporaryObjectExpr()), + hasType(cxxRecordDecl( + isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION")))), + unless(anyOf(hasAncestor(stmt( + anyOf(cxxThrowExpr(), callExpr(), returnStmt()))), + hasAncestor(varDecl()), + allOf(hasAncestor(cxxConstructorDecl( + hasAnyConstructorInitializer(anything()))), + unless(hasAncestor(cxxCatchStmt())))))) + .bind("temporary-exception-not-thrown"), + this); +} + +void ThrowKeywordMissingCheck::check(const MatchFinder::MatchResult &Result) { + const auto TemporaryExpr = + Result.Nodes.getNodeAs<Expr>("temporary-exception-not-thrown"); + diag(TemporaryExpr->getLocStart(), "exception created but is not thrown"); +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -33,6 +33,7 @@ #include "SuspiciousStringCompareCheck.h" #include "SwappedArgumentsCheck.h" #include "ThrowByValueCatchByReferenceCheck.h" +#include "ThrowKeywordMissingCheck.h" #include "UnconventionalAssignOperatorCheck.h" #include "UndelegatedConstructor.h" #include "UniqueptrResetReleaseCheck.h" @@ -53,6 +54,8 @@ CheckFactories.registerCheck<LambdaFunctionNameCheck>( "misc-lambda-function-name"); CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const"); + CheckFactories.registerCheck<ThrowKeywordMissingCheck>( + "misc-throw-keyword-missing"); CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>( "misc-unconventional-assign-operator"); CheckFactories.registerCheck<DefinitionsInHeadersCheck>( Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -4,6 +4,7 @@ ForwardingReferenceOverloadCheck.cpp LambdaFunctionNameCheck.cpp MisplacedConstCheck.cpp + ThrowKeywordMissingCheck.cpp UnconventionalAssignOperatorCheck.cpp DefinitionsInHeadersCheck.cpp IncorrectRoundings.cpp
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits