OverrideBaseCallChecker.cpp (3677B)
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 }