forked from mirrors/gecko-dev
		
	 f8798bbeb2
			
		
	
	
		f8798bbeb2
		
	
	
	
	
		
			
			- 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();
 | |
|     }
 | |
|   }
 | |
| }
 |