1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * Based on LLVM/Clang.
6 *
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
9 *
10 */
11
12 #ifndef LO_CLANG_SHARED_PLUGINS
13
14 #include "check.hxx"
15 #include "plugin.hxx"
16 #include <clang/Lex/Lexer.h>
17 #include <fstream>
18 #include <set>
19
20 namespace loplugin
21 {
22 /*
23 This is a compile check.
24
25 Check that DBG_UNHANDLED_EXCEPTION is always the first statement in a catch block, otherwise
26 it does not work properly.
27 */
28
29 class DbgUnhandledException : public loplugin::FilteringPlugin<DbgUnhandledException>
30 {
31 public:
32 explicit DbgUnhandledException(InstantiationData const& data);
33 virtual void run() override;
34 bool VisitCallExpr(CallExpr const* call);
35 bool TraverseCXXCatchStmt(CXXCatchStmt*);
36 bool PreTraverseCXXCatchStmt(CXXCatchStmt*);
37 bool PostTraverseCXXCatchStmt(CXXCatchStmt*, bool traverseOk);
38
39 private:
40 std::stack<CXXCatchStmt const*> currCatchStmt;
41 };
42
DbgUnhandledException(const InstantiationData & data)43 DbgUnhandledException::DbgUnhandledException(const InstantiationData& data)
44 : FilteringPlugin(data)
45 {
46 }
47
run()48 void DbgUnhandledException::run()
49 {
50 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
51 }
52
PreTraverseCXXCatchStmt(CXXCatchStmt * catchStmt)53 bool DbgUnhandledException::PreTraverseCXXCatchStmt(CXXCatchStmt* catchStmt)
54 {
55 currCatchStmt.push(catchStmt);
56 return true;
57 }
58
PostTraverseCXXCatchStmt(CXXCatchStmt * catchStmt,bool)59 bool DbgUnhandledException::PostTraverseCXXCatchStmt(CXXCatchStmt* catchStmt, bool)
60 {
61 assert(currCatchStmt.top() == catchStmt);
62 (void)catchStmt;
63 currCatchStmt.pop();
64 return true;
65 }
66
TraverseCXXCatchStmt(CXXCatchStmt * catchStmt)67 bool DbgUnhandledException::TraverseCXXCatchStmt(CXXCatchStmt* catchStmt)
68 {
69 if (!PreTraverseCXXCatchStmt(catchStmt))
70 return false;
71 bool ret = RecursiveASTVisitor::TraverseCXXCatchStmt(catchStmt);
72 if (!PostTraverseCXXCatchStmt(catchStmt, ret))
73 return false;
74 return ret;
75 }
76
VisitCallExpr(const CallExpr * call)77 bool DbgUnhandledException::VisitCallExpr(const CallExpr* call)
78 {
79 if (ignoreLocation(call))
80 return true;
81 const FunctionDecl* func = call->getDirectCallee();
82 if (!func)
83 return true;
84
85 if (!func->getIdentifier() || func->getName() != "DbgUnhandledException")
86 return true;
87
88 if (currCatchStmt.empty())
89 {
90 report(DiagnosticsEngine::Warning, "DBG_UNHANDLED_EXCEPTION outside catch block",
91 compat::getBeginLoc(call));
92 return true;
93 }
94 auto catchBlock = dyn_cast<CompoundStmt>(currCatchStmt.top()->getHandlerBlock());
95 if (!catchBlock)
96 {
97 report(DiagnosticsEngine::Warning,
98 "something wrong with DBG_UNHANDLED_EXCEPTION, no CompoundStmt?",
99 compat::getBeginLoc(call));
100 return true;
101 }
102 if (catchBlock->size() < 1)
103 {
104 report(DiagnosticsEngine::Warning,
105 "something wrong with DBG_UNHANDLED_EXCEPTION, CompoundStmt size == 0?",
106 compat::getBeginLoc(call));
107 return true;
108 }
109
110 Stmt const* firstStmt = *catchBlock->body_begin();
111 if (auto exprWithCleanups = dyn_cast<ExprWithCleanups>(firstStmt))
112 firstStmt = exprWithCleanups->getSubExpr();
113 if (firstStmt != call)
114 {
115 report(DiagnosticsEngine::Warning,
116 "DBG_UNHANDLED_EXCEPTION must be first statement in catch block",
117 compat::getBeginLoc(call));
118 }
119 return true;
120 }
121
122 static Plugin::Registration<DbgUnhandledException> dbgunhandledexception("dbgunhandledexception");
123
124 } // namespace
125
126 #endif // LO_CLANG_SHARED_PLUGINS
127
128 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
129