зеркало из https://github.com/mozilla/gecko-dev.git
113 строки
3.6 KiB
C++
113 строки
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 hasCustomAnnotation(Method, "moz_required_base_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();
|
|
}
|
|
}
|
|
}
|