Bug 1839316: part 5) Guard the "fetchpriority" attribute behind a pref. r=kershaw...
[gecko.git] / build / clang-plugin / OverrideBaseCallChecker.cpp
blob600d4313354e32cfbbb9710f1f7d0236fd26c34f
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()) {
21 return;
24 if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) {
25 if (auto Method =
26 dyn_cast<CXXMethodDecl>(MemberFuncCall->getDirectCallee())) {
27 findBaseMethodCall(Method, MethodList);
31 for (auto S : StmtExpr->children()) {
32 if (S) {
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);
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);
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) {
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");
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;
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);
89 // If no method has been found then no annotation was used
90 // so checking is not needed
91 if (!MethodsList.size()) {
92 continue;
95 // Loop through the body of our method and search for calls to
96 // base methods
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();