Szelethus updated this revision to Diff 133597.
Szelethus added a comment.
Changes made according to @whisperity's comments.
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,154 @@
+// 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 instantiated but not bound (did you intend to 'throw'?) [misc-throw-keyword-missing]
+ std::exception();
+
+ if (i > 0)
+ //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception instantiated but not bound (did you intend to 'throw'?) [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 instantiated but not bound (did you intend to 'throw'?) [misc-throw-keyword-missing]
+ RegularException();
+
+ if (i > 0)
+ //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception instantiated but not bound (did you intend to 'throw'?) [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 body
+ } catch (...) {
+ //CHECK-MESSAGES: :[[@LINE+1]]:5: warning: exception instantiated but not bound (did you intend to 'throw'?) [misc-throw-keyword-missing]
+ RegularException();
+ }
+
+ CtorInitializerListTest(float);
+};
+
+CtorInitializerListTest::CtorInitializerListTest(float) try : exc(RegularException()) {
+ //Constructor body
+} catch (...) {
+ //CHECK-MESSAGES: :[[@LINE+1]]:3: warning: exception instantiated but not bound (did you intend to 'throw'?) [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()});
+}
+
+typedef std::exception ERROR_BASE;
+class RegularError : public ERROR_BASE {};
+
+void preprocessorCheck() {
+ //CHECK-MESSAGES: :[[@LINE+1]]:3: warning: exception instantiated but not bound (did you intend to 'throw'?) [misc-throw-keyword-missing]
+ RegularError();
+}
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,50 @@
+//===--- 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) {
+ 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(CtorInitializerList),
+ 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 instantiated but not bound (did you intend to 'throw'?)");
+}
+
+} // 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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits