Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "OverrideBaseCallChecker.h"
6
#include "CustomMatchers.h"
7
8
void OverrideBaseCallChecker::registerMatchers(MatchFinder *AstMatcher) {
9
AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this);
10
}
11
12
bool OverrideBaseCallChecker::isRequiredBaseMethod(
13
const CXXMethodDecl *Method) {
14
return hasCustomAttribute<moz_required_base_method>(Method);
15
}
16
17
void OverrideBaseCallChecker::evaluateExpression(
18
const Stmt *StmtExpr, std::list<const CXXMethodDecl *> &MethodList) {
19
// Continue while we have methods in our list
20
if (!MethodList.size()) {
21
return;
22
}
23
24
if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) {
25
if (auto Method =
26
dyn_cast<CXXMethodDecl>(MemberFuncCall->getDirectCallee())) {
27
findBaseMethodCall(Method, MethodList);
28
}
29
}
30
31
for (auto S : StmtExpr->children()) {
32
if (S) {
33
evaluateExpression(S, MethodList);
34
}
35
}
36
}
37
38
void OverrideBaseCallChecker::getRequiredBaseMethod(
39
const CXXMethodDecl *Method,
40
std::list<const CXXMethodDecl *> &MethodsList) {
41
42
if (isRequiredBaseMethod(Method)) {
43
MethodsList.push_back(Method);
44
} else {
45
// Loop through all it's base methods.
46
for (auto BaseMethod = Method->begin_overridden_methods();
47
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
48
getRequiredBaseMethod(*BaseMethod, MethodsList);
49
}
50
}
51
}
52
53
void OverrideBaseCallChecker::findBaseMethodCall(
54
const CXXMethodDecl *Method,
55
std::list<const CXXMethodDecl *> &MethodsList) {
56
57
MethodsList.remove(Method);
58
// Loop also through all it's base methods;
59
for (auto BaseMethod = Method->begin_overridden_methods();
60
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
61
findBaseMethodCall(*BaseMethod, MethodsList);
62
}
63
}
64
65
void OverrideBaseCallChecker::check(const MatchFinder::MatchResult &Result) {
66
const char *Error =
67
"Method %0 must be called in all overrides, but is not called in "
68
"this override defined for class %1";
69
const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
70
71
// Loop through the methods and look for the ones that are overridden.
72
for (auto Method : Decl->methods()) {
73
// If this method doesn't override other methods or it doesn't have a body,
74
// continue to the next declaration.
75
if (!Method->size_overridden_methods() || !Method->hasBody()) {
76
continue;
77
}
78
79
// Preferred the usage of list instead of vector in order to avoid
80
// calling erase-remove when deleting items
81
std::list<const CXXMethodDecl *> MethodsList;
82
// For each overridden method push it to a list if it meets our
83
// criteria
84
for (auto BaseMethod = Method->begin_overridden_methods();
85
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
86
getRequiredBaseMethod(*BaseMethod, MethodsList);
87
}
88
89
// If no method has been found then no annotation was used
90
// so checking is not needed
91
if (!MethodsList.size()) {
92
continue;
93
}
94
95
// Loop through the body of our method and search for calls to
96
// base methods
97
evaluateExpression(Method->getBody(), MethodsList);
98
99
// If list is not empty pop up errors
100
for (auto BaseMethod : MethodsList) {
101
std::string QualName;
102
raw_string_ostream OS(QualName);
103
BaseMethod->printQualifiedName(OS);
104
105
diag(Method->getLocation(), Error, DiagnosticIDs::Error)
106
<< OS.str() << Decl->getName();
107
}
108
}
109
}