randomcppprogrammer created this revision.
randomcppprogrammer added reviewers: klimek, cfe-commits, jbcoe.

This patch contains an implementation to check whether exceptions where thrown 
by value and caught by const reference. This is a guideline mentioned in 
different places, e.g. "C++ Coding Standards" by H. Sutter.

Patch by Tobias Langner

http://reviews.llvm.org/D11328

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp
  clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h
  test/clang-tidy/misc-throw-by-value-catch-by-reference.cpp

Index: test/clang-tidy/misc-throw-by-value-catch-by-reference.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-throw-by-value-catch-by-reference.cpp
@@ -0,0 +1,71 @@
+// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-throw-by-value-catch-by-reference %t
+// REQUIRES: shell
+
+class logic_error {
+public:
+  logic_error(const char *message) {}
+};
+
+int selector;
+typedef logic_error *logic_ptr;
+typedef logic_ptr logic_double_typedef;
+
+void testThrowFunc() {
+  switch (selector) {
+  case 0:
+    throw new logic_error("by pointer");
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid throwing pointer
+  // [misc-throw-by-value-catch-by-reference]
+  case 1: {
+    logic_ptr tmp = new logic_error("by pointer");
+    throw tmp;
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: avoid throwing pointer
+    // [misc-throw-by-value-catch-by-reference]
+  }
+  case 2:
+    throw logic_error("by value");
+  }
+}
+
+void catchByPointer() {
+  try {
+    testThrowFunc();
+  } catch (logic_error *e) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch by const reference
+    // [misc-throw-by-value-catch-by-reference]
+  }
+}
+
+void catchByValue() {
+  try {
+    testThrowFunc();
+  } catch (logic_error e) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch by const reference
+    // [misc-throw-by-value-catch-by-reference]
+  }
+}
+
+void catchByReference() {
+  try {
+    testThrowFunc();
+  } catch (logic_error &e) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch by const reference to
+    // avoid unnecessary copies [misc-throw-by-value-catch-by-reference]
+  }
+}
+
+void catchByConstReference() {
+  try {
+    testThrowFunc();
+  } catch (const logic_error &e) {
+  }
+}
+
+void catchTypedef() {
+  try {
+    testThrowFunc();
+  } catch (logic_ptr e) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch by const reference
+    // [misc-throw-by-value-catch-by-reference]
+  }
+}
Index: clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h
@@ -0,0 +1,32 @@
+//===--- ThrowByValueCatchByReferenceCheck.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_THROW_BY_VALUE_CATCH_BY_REFERENCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROW_BY_VALUE_CATCH_BY_REFERENCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+///\brief checks for locations that do not throw by value
+// or catch by reference.
+class ThrowByValueCatchByReferenceCheck : public ClangTidyCheck {
+public:
+  ThrowByValueCatchByReferenceCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROW_BY_VALUE_CATCH_BY_REFERENCE_H
+
Index: clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp
@@ -0,0 +1,57 @@
+//===--- ThrowByValueCatchByReferenceCheck.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 "ThrowByValueCatchByReferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+void ThrowByValueCatchByReferenceCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(throwExpr().bind("throw"), this);
+  Finder->addMatcher(catchStmt().bind("catch"), this);
+}
+
+void ThrowByValueCatchByReferenceCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *throwExpr = Result.Nodes.getNodeAs<CXXThrowExpr>("throw");
+  if (throwExpr != nullptr) {
+    auto *subExpr = throwExpr->getSubExpr();
+    auto qualType = subExpr->getType();
+    auto *type = qualType.getTypePtr();
+    if (type->isPointerType() == true) { // throwing a pointer
+      diag(subExpr->getLocStart(), "avoid throwing pointer");
+    }
+  }
+  const auto *catchStmt = Result.Nodes.getNodeAs<CXXCatchStmt>("catch");
+  if (catchStmt != nullptr) {
+    auto caughtType = catchStmt->getCaughtType();
+    auto *type = caughtType.getTypePtr();
+    auto *varDecl = catchStmt->getExceptionDecl();
+    if (type->isPointerType()) {
+      diag(varDecl->getLocStart(),
+           "catch by const reference");
+    } else if (!type->isReferenceType()) {
+      diag(varDecl->getLocStart(), "catch by const reference");
+    } else {
+      auto* reference = type->castAs<const ReferenceType>();
+      assert(reference!=nullptr);
+      if (reference->getPointeeType().isConstQualified() == false) {
+        diag(varDecl->getLocStart(),
+             "catch by const reference to avoid unnecessary copies");
+      }
+    }
+  }
+}
+
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -21,6 +21,7 @@
 #include "NoexceptMoveConstructorCheck.h"
 #include "StaticAssertCheck.h"
 #include "SwappedArgumentsCheck.h"
+#include "ThrowByValueCatchByReferenceCheck.h"
 #include "UndelegatedConstructor.h"
 #include "UniqueptrResetReleaseCheck.h"
 #include "UnusedRAIICheck.h"
@@ -54,6 +55,8 @@
         "misc-static-assert");
     CheckFactories.registerCheck<SwappedArgumentsCheck>(
         "misc-swapped-arguments");
+    CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
+        "misc-throw-by-value-catch-by-reference");
     CheckFactories.registerCheck<UndelegatedConstructorCheck>(
         "misc-undelegated-constructor");
     CheckFactories.registerCheck<UniqueptrResetReleaseCheck>(
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -13,6 +13,7 @@
   NoexceptMoveConstructorCheck.cpp
   StaticAssertCheck.cpp
   SwappedArgumentsCheck.cpp
+  ThrowByValueCatchByReferenceCheck.cpp
   UndelegatedConstructor.cpp
   UnusedRAIICheck.cpp
   UniqueptrResetReleaseCheck.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to