-
Notifications
You must be signed in to change notification settings - Fork 490
/
ThrowExceptionFromFinallyBlockRule.cpp
140 lines (118 loc) · 3.88 KB
/
ThrowExceptionFromFinallyBlockRule.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "oclint/AbstractASTVisitorRule.h"
#include "oclint/RuleSet.h"
#include "oclint/util/StdUtil.h"
using namespace std;
using namespace clang;
using namespace oclint;
class ThrowExceptionFromFinallyBlockRule :
public AbstractASTVisitorRule<ThrowExceptionFromFinallyBlockRule>
{
class ExtractObjCAtThrowStmts : public RecursiveASTVisitor<ExtractObjCAtThrowStmts>
{
private:
vector<ObjCAtThrowStmt*> *_throws;
public:
void extract(ObjCAtFinallyStmt *finallyStmt, vector<ObjCAtThrowStmt*> *throws)
{
_throws = throws;
(void) /* explicitly ignore the return of this function */ TraverseStmt(finallyStmt);
}
bool VisitObjCAtThrowStmt(ObjCAtThrowStmt *throwStmt)
{
_throws->push_back(throwStmt);
return true;
}
};
class ExtractNSExceptionRaiser : public RecursiveASTVisitor<ExtractNSExceptionRaiser>
{
private:
vector<ObjCMessageExpr*> *_raisers;
public:
void extract(ObjCAtFinallyStmt *finallyStmt, vector<ObjCMessageExpr*> *raisers)
{
_raisers = raisers;
(void) /* explicitly ignore the return of this function */ TraverseStmt(finallyStmt);
}
bool VisitObjCMessageExpr(ObjCMessageExpr *objCMsgExpr)
{
string selectorString = objCMsgExpr->getSelector().getAsString();
vector<string> selectorStrings;
selectorStrings.push_back("raise");
selectorStrings.push_back("raise:format:");
selectorStrings.push_back("raise:format:arguments:");
bool isRaiseMethod = vectorContains<string>(selectorString, selectorStrings);
ObjCInterfaceDecl *objCInterfaceDecl = objCMsgExpr->getReceiverInterface();
bool isNSExceptionClass = objCInterfaceDecl &&
objCInterfaceDecl->getNameAsString() == "NSException";
if (isRaiseMethod && isNSExceptionClass)
{
_raisers->push_back(objCMsgExpr);
}
return true;
}
};
public:
virtual const string name() const override
{
return "throw exception from finally block";
}
virtual int priority() const override
{
return 2;
}
virtual const string category() const override
{
return "basic";
}
virtual unsigned int supportedLanguages() const override
{
return LANG_OBJC;
}
#ifdef DOCGEN
virtual const std::string since() const override
{
return "0.6";
}
virtual const std::string description() const override
{
return "Throwing exceptions within a ``finally`` block "
"may mask other exceptions or code defects.";
}
virtual const std::string example() const override
{
return R"rst(
.. code-block:: objective-c
void example()
{
@try {;}
@catch(id ex) {;}
@finally {
id ex1;
@throw ex1; // this throws an exception
NSException *ex2 = [NSException new];
[ex2 raise]; // this throws an exception, too
}
}
)rst";
}
#endif
bool VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *finallyStmt)
{
vector<ObjCAtThrowStmt*> throws;
ExtractObjCAtThrowStmts extractThrowStmts;
extractThrowStmts.extract(finallyStmt, &throws);
for (const auto& throwStmt : throws)
{
addViolation(throwStmt, this);
}
vector<ObjCMessageExpr*> exceptionRaisers;
ExtractNSExceptionRaiser extractExceptions;
extractExceptions.extract(finallyStmt, &exceptionRaisers);
for (const auto& raiseExpr : exceptionRaisers)
{
addViolation(raiseExpr, this);
}
return true;
}
};
static RuleSet rules(new ThrowExceptionFromFinallyBlockRule());