Adding a checker (cert-err52-cpp) that detects use of setjmp or longjmp in C++ code. Corresponds to the CERT C++ secure coding rule: https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=1834

llvm-svn: 249727
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index d73e214..6fa984b 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -15,6 +15,7 @@
 #include "../misc/NewDeleteOverloadsCheck.h"
 #include "../misc/NonCopyableObjects.h"
 #include "../misc/StaticAssertCheck.h"
+#include "SetLongJmpCheck.h"
 #include "VariadicFunctionDefCheck.h"
 
 namespace clang {
@@ -35,6 +36,9 @@
     // OOP
     CheckFactories.registerCheck<MoveConstructorInitCheck>(
         "cert-oop11-cpp");
+    // ERR
+    CheckFactories.registerCheck<SetLongJmpCheck>(
+        "cert-err52-cpp");
 
     // C checkers
     // DCL
diff --git a/clang-tools-extra/clang-tidy/cert/CMakeLists.txt b/clang-tools-extra/clang-tidy/cert/CMakeLists.txt
index ce5c2c9..cf252244 100644
--- a/clang-tools-extra/clang-tidy/cert/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/cert/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_clang_library(clangTidyCERTModule
   CERTTidyModule.cpp
+  SetLongJmpCheck.cpp
   VariadicFunctionDefCheck.cpp
 
   LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp b/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp
new file mode 100644
index 0000000..bc5b353
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp
@@ -0,0 +1,77 @@
+//===--- SetLongJmpCheck.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 "SetLongJmpCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+const char SetLongJmpCheck::DiagWording[] =
+    "do not call %0; consider using exception handling instead";
+
+namespace {
+class SetJmpMacroCallbacks : public PPCallbacks {
+  SetLongJmpCheck &Check;
+
+public:
+  explicit SetJmpMacroCallbacks(SetLongJmpCheck &Check) : Check(Check) {}
+
+  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+                    SourceRange Range, const MacroArgs *Args) override {
+    const auto *II = MacroNameTok.getIdentifierInfo();
+    if (!II)
+      return;
+
+    if (II->getName() == "setjmp")
+      Check.diag(Range.getBegin(), Check.DiagWording) << II;
+  }
+};
+} // namespace
+
+void SetLongJmpCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+  // This checker only applies to C++, where exception handling is a superior
+  // solution to setjmp/longjmp calls.
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  // Per [headers]p5, setjmp must be exposed as a macro instead of a function,
+  // despite the allowance in C for setjmp to also be an extern function.
+  Compiler.getPreprocessor().addPPCallbacks(
+      llvm::make_unique<SetJmpMacroCallbacks>(*this));
+}
+
+void SetLongJmpCheck::registerMatchers(MatchFinder *Finder) {
+  // This checker only applies to C++, where exception handling is a superior
+  // solution to setjmp/longjmp calls.
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  // In case there is an implementation that happens to define setjmp as a
+  // function instead of a macro, this will also catch use of it. However, we
+  // are primarily searching for uses of longjmp.
+  Finder->addMatcher(callExpr(callee(functionDecl(anyOf(hasName("setjmp"),
+                                                        hasName("longjmp")))))
+                         .bind("expr"),
+                     this);
+}
+
+void SetLongJmpCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *E = Result.Nodes.getNodeAs<CallExpr>("expr");
+  diag(E->getExprLoc(), DiagWording) << cast<NamedDecl>(E->getCalleeDecl());
+}
+
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.h b/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.h
new file mode 100644
index 0000000..242df6b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.h
@@ -0,0 +1,37 @@
+//===--- SetLongJmpCheck.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_SETLONGJMPCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// Guards against use of setjmp/longjmp in C++ code
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-setlongjmp.html
+class SetLongJmpCheck : public ClangTidyCheck {
+public:
+  SetLongJmpCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void registerPPCallbacks(CompilerInstance &Compiler) override;
+
+  static const char DiagWording[];
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H
+