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/. */
5 #include "OverrideBaseCallChecker.h"
6 #include "CustomMatchers.h"
8 void OverrideBaseCallChecker::registerMatchers(MatchFinder
*AstMatcher
) {
9 AstMatcher
->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this);
12 bool OverrideBaseCallChecker::isRequiredBaseMethod(
13 const CXXMethodDecl
*Method
) {
14 return hasCustomAttribute
<moz_required_base_method
>(Method
);
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()) {
24 if (auto MemberFuncCall
= dyn_cast
<CXXMemberCallExpr
>(StmtExpr
)) {
26 dyn_cast
<CXXMethodDecl
>(MemberFuncCall
->getDirectCallee())) {
27 findBaseMethodCall(Method
, MethodList
);
31 for (auto S
: StmtExpr
->children()) {
33 evaluateExpression(S
, MethodList
);
38 void OverrideBaseCallChecker::getRequiredBaseMethod(
39 const CXXMethodDecl
*Method
,
40 std::list
<const CXXMethodDecl
*> &MethodsList
) {
42 if (isRequiredBaseMethod(Method
)) {
43 MethodsList
.push_back(Method
);
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
);
53 void OverrideBaseCallChecker::findBaseMethodCall(
54 const CXXMethodDecl
*Method
,
55 std::list
<const CXXMethodDecl
*> &MethodsList
) {
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
);
65 void OverrideBaseCallChecker::check(const MatchFinder::MatchResult
&Result
) {
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");
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()) {
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
84 for (auto BaseMethod
= Method
->begin_overridden_methods();
85 BaseMethod
!= Method
->end_overridden_methods(); BaseMethod
++) {
86 getRequiredBaseMethod(*BaseMethod
, MethodsList
);
89 // If no method has been found then no annotation was used
90 // so checking is not needed
91 if (!MethodsList
.size()) {
95 // Loop through the body of our method and search for calls to
97 evaluateExpression(Method
->getBody(), MethodsList
);
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
);
105 diag(Method
->getLocation(), Error
, DiagnosticIDs::Error
)
106 << OS
.str() << Decl
->getName();