tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }