summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/dbgunhandledexception.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compilerplugins/clang/dbgunhandledexception.cxx128
1 files changed, 128 insertions, 0 deletions
diff --git a/compilerplugins/clang/dbgunhandledexception.cxx b/compilerplugins/clang/dbgunhandledexception.cxx
new file mode 100644
index 000000000..e6c1f157c
--- /dev/null
+++ b/compilerplugins/clang/dbgunhandledexception.cxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * Based on LLVM/Clang.
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ */
+
+#ifndef LO_CLANG_SHARED_PLUGINS
+
+#include "check.hxx"
+#include "plugin.hxx"
+#include <clang/Lex/Lexer.h>
+#include <fstream>
+#include <set>
+
+namespace loplugin
+{
+/*
+This is a compile check.
+
+Check that DBG_UNHANDLED_EXCEPTION is always the first statement in a catch block, otherwise
+it does not work properly.
+*/
+
+class DbgUnhandledException : public loplugin::FilteringPlugin<DbgUnhandledException>
+{
+public:
+ explicit DbgUnhandledException(InstantiationData const& data);
+ virtual void run() override;
+ bool VisitCallExpr(CallExpr const* call);
+ bool TraverseCXXCatchStmt(CXXCatchStmt*);
+ bool PreTraverseCXXCatchStmt(CXXCatchStmt*);
+ bool PostTraverseCXXCatchStmt(CXXCatchStmt*, bool traverseOk);
+
+private:
+ std::stack<CXXCatchStmt const*> currCatchStmt;
+};
+
+DbgUnhandledException::DbgUnhandledException(const InstantiationData& data)
+ : FilteringPlugin(data)
+{
+}
+
+void DbgUnhandledException::run()
+{
+ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+}
+
+bool DbgUnhandledException::PreTraverseCXXCatchStmt(CXXCatchStmt* catchStmt)
+{
+ currCatchStmt.push(catchStmt);
+ return true;
+}
+
+bool DbgUnhandledException::PostTraverseCXXCatchStmt(CXXCatchStmt* catchStmt, bool)
+{
+ assert(currCatchStmt.top() == catchStmt);
+ (void)catchStmt;
+ currCatchStmt.pop();
+ return true;
+}
+
+bool DbgUnhandledException::TraverseCXXCatchStmt(CXXCatchStmt* catchStmt)
+{
+ if (!PreTraverseCXXCatchStmt(catchStmt))
+ return false;
+ bool ret = RecursiveASTVisitor::TraverseCXXCatchStmt(catchStmt);
+ if (!PostTraverseCXXCatchStmt(catchStmt, ret))
+ return false;
+ return ret;
+}
+
+bool DbgUnhandledException::VisitCallExpr(const CallExpr* call)
+{
+ if (ignoreLocation(call))
+ return true;
+ const FunctionDecl* func = call->getDirectCallee();
+ if (!func)
+ return true;
+
+ if (!func->getIdentifier() || func->getName() != "DbgUnhandledException")
+ return true;
+
+ if (currCatchStmt.empty())
+ {
+ report(DiagnosticsEngine::Warning, "DBG_UNHANDLED_EXCEPTION outside catch block",
+ call->getBeginLoc());
+ return true;
+ }
+ auto catchBlock = dyn_cast<CompoundStmt>(currCatchStmt.top()->getHandlerBlock());
+ if (!catchBlock)
+ {
+ report(DiagnosticsEngine::Warning,
+ "something wrong with DBG_UNHANDLED_EXCEPTION, no CompoundStmt?",
+ call->getBeginLoc());
+ return true;
+ }
+ if (catchBlock->size() < 1)
+ {
+ report(DiagnosticsEngine::Warning,
+ "something wrong with DBG_UNHANDLED_EXCEPTION, CompoundStmt size == 0?",
+ call->getBeginLoc());
+ return true;
+ }
+
+ Stmt const* firstStmt = *catchBlock->body_begin();
+ if (auto exprWithCleanups = dyn_cast<ExprWithCleanups>(firstStmt))
+ firstStmt = exprWithCleanups->getSubExpr();
+ if (firstStmt != call)
+ {
+ report(DiagnosticsEngine::Warning,
+ "DBG_UNHANDLED_EXCEPTION must be first statement in catch block",
+ call->getBeginLoc());
+ }
+ return true;
+}
+
+static Plugin::Registration<DbgUnhandledException> dbgunhandledexception("dbgunhandledexception");
+
+} // namespace
+
+#endif // LO_CLANG_SHARED_PLUGINS
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */