in src/ContextUtils.cpp [117:191]
bool clazy::canTakeAddressOf(CXXMethodDecl *method, DeclContext *context, bool &isSpecialProtectedCase)
{
isSpecialProtectedCase = false;
if (!method || !method->getParent()) {
return false;
}
if (method->getAccess() == clang::AccessSpecifier::AS_public) {
return true;
}
if (!context) {
return false;
}
CXXRecordDecl *contextRecord = nullptr;
do {
contextRecord = dyn_cast<CXXRecordDecl>(context);
context = context->getParent();
} while (contextRecord == nullptr && context);
if (!contextRecord) { // If we're not inside a class method we can't take the address of a private/protected method
return false;
}
CXXRecordDecl *record = method->getParent();
if (record == contextRecord) {
return true;
}
// We're inside a method belonging to a class (contextRecord).
// Is contextRecord a friend of record ? Lets check:
for (auto *fr : record->friends()) {
TypeSourceInfo *si = fr->getFriendType();
if (si) {
const Type *t = si->getType().getTypePtrOrNull();
const CXXRecordDecl *friendClass = t ? t->getAsCXXRecordDecl() : nullptr;
if (friendClass == contextRecord) {
return true;
}
}
}
// There's still hope, lets see if the context is nested inside the class we're trying to access
// Inner classes can access private members of outter classes.
DeclContext *it = contextRecord;
do {
it = it->getParent();
if (it == record) {
return true;
}
} while (it);
if (method->getAccess() == clang::AccessSpecifier::AS_private) {
return false;
}
if (method->getAccess() != clang::AccessSpecifier::AS_protected) { // shouldnt happen, must be protected at this point.
return false;
}
// For protected there's still hope, since record might be a derived or base class
if (clazy::derivesFrom(record, contextRecord)) {
return true;
}
if (clazy::derivesFrom(contextRecord, record)) {
isSpecialProtectedCase = true;
return true;
}
return false;
}