mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	- We forcefully remove annotations from the AST so that they don't end up impacting codegen. - We change the API such that we use identifiers instead of strings, reducing the chances of typo errors. Differential Revision: https://phabricator.services.mozilla.com/D5493 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			109 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "OverrideBaseCallChecker.h"
 | 
						|
#include "CustomMatchers.h"
 | 
						|
 | 
						|
void OverrideBaseCallChecker::registerMatchers(MatchFinder *AstMatcher) {
 | 
						|
  AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this);
 | 
						|
}
 | 
						|
 | 
						|
bool OverrideBaseCallChecker::isRequiredBaseMethod(
 | 
						|
    const CXXMethodDecl *Method) {
 | 
						|
  return hasCustomAttribute<moz_required_base_method>(Method);
 | 
						|
}
 | 
						|
 | 
						|
void OverrideBaseCallChecker::evaluateExpression(
 | 
						|
    const Stmt *StmtExpr, std::list<const CXXMethodDecl *> &MethodList) {
 | 
						|
  // Continue while we have methods in our list
 | 
						|
  if (!MethodList.size()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) {
 | 
						|
    if (auto Method =
 | 
						|
            dyn_cast<CXXMethodDecl>(MemberFuncCall->getDirectCallee())) {
 | 
						|
      findBaseMethodCall(Method, MethodList);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (auto S : StmtExpr->children()) {
 | 
						|
    if (S) {
 | 
						|
      evaluateExpression(S, MethodList);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void OverrideBaseCallChecker::getRequiredBaseMethod(
 | 
						|
    const CXXMethodDecl *Method,
 | 
						|
    std::list<const CXXMethodDecl *> &MethodsList) {
 | 
						|
 | 
						|
  if (isRequiredBaseMethod(Method)) {
 | 
						|
    MethodsList.push_back(Method);
 | 
						|
  } else {
 | 
						|
    // Loop through all it's base methods.
 | 
						|
    for (auto BaseMethod = Method->begin_overridden_methods();
 | 
						|
         BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
 | 
						|
      getRequiredBaseMethod(*BaseMethod, MethodsList);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void OverrideBaseCallChecker::findBaseMethodCall(
 | 
						|
    const CXXMethodDecl *Method,
 | 
						|
    std::list<const CXXMethodDecl *> &MethodsList) {
 | 
						|
 | 
						|
  MethodsList.remove(Method);
 | 
						|
  // Loop also through all it's base methods;
 | 
						|
  for (auto BaseMethod = Method->begin_overridden_methods();
 | 
						|
       BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
 | 
						|
    findBaseMethodCall(*BaseMethod, MethodsList);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void OverrideBaseCallChecker::check(const MatchFinder::MatchResult &Result) {
 | 
						|
  const char *Error =
 | 
						|
      "Method %0 must be called in all overrides, but is not called in "
 | 
						|
      "this override defined for class %1";
 | 
						|
  const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
 | 
						|
 | 
						|
  // Loop through the methods and look for the ones that are overridden.
 | 
						|
  for (auto Method : Decl->methods()) {
 | 
						|
    // If this method doesn't override other methods or it doesn't have a body,
 | 
						|
    // continue to the next declaration.
 | 
						|
    if (!Method->size_overridden_methods() || !Method->hasBody()) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    // Preferred the usage of list instead of vector in order to avoid
 | 
						|
    // calling erase-remove when deleting items
 | 
						|
    std::list<const CXXMethodDecl *> MethodsList;
 | 
						|
    // For each overridden method push it to a list if it meets our
 | 
						|
    // criteria
 | 
						|
    for (auto BaseMethod = Method->begin_overridden_methods();
 | 
						|
         BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
 | 
						|
      getRequiredBaseMethod(*BaseMethod, MethodsList);
 | 
						|
    }
 | 
						|
 | 
						|
    // If no method has been found then no annotation was used
 | 
						|
    // so checking is not needed
 | 
						|
    if (!MethodsList.size()) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    // Loop through the body of our method and search for calls to
 | 
						|
    // base methods
 | 
						|
    evaluateExpression(Method->getBody(), MethodsList);
 | 
						|
 | 
						|
    // If list is not empty pop up errors
 | 
						|
    for (auto BaseMethod : MethodsList) {
 | 
						|
      std::string QualName;
 | 
						|
      raw_string_ostream OS(QualName);
 | 
						|
      BaseMethod->printQualifiedName(OS);
 | 
						|
 | 
						|
      diag(Method->getLocation(), Error, DiagnosticIDs::Error)
 | 
						|
          << OS.str() << Decl->getName();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |