/// Warns on methods overridden in DerivedDecl with respect to BaseDecl. /// FIXME: this warns on all overrides outside of the sliced path in case of /// multiple inheritance. void SlicingCheck::DiagnoseSlicedOverriddenMethods( const Expr &Call, const CXXRecordDecl &DerivedDecl, const CXXRecordDecl &BaseDecl) { if (DerivedDecl.getCanonicalDecl() == BaseDecl.getCanonicalDecl()) return; for (const auto &Method : DerivedDecl.methods()) { // Virtual destructors are OK. We're ignoring constructors since they are // tagged as overrides. if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) continue; if (Method->size_overridden_methods() > 0) { diag(Call.getExprLoc(), "slicing object from type %0 to %1 discards override %2") << &DerivedDecl << &BaseDecl << Method; } } // Recursively process bases. for (const auto &Base : DerivedDecl.bases()) { if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) { if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>( BaseRecordType->getDecl()->getDefinition())) DiagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl); } } }
/// \brief Whether this nested name specifier refers to a dependent /// type or not. bool NestedNameSpecifier::isDependent() const { switch (getKind()) { case Identifier: // Identifier specifiers always represent dependent types return true; case Namespace: case NamespaceAlias: case Global: return false; case Super: { CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier); for (const auto &Base : RD->bases()) if (Base.getType()->isDependentType()) return true; return false; } case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isDependentType(); } llvm_unreachable("Invalid NNS Kind!"); }
static bool isParentOf(const CXXRecordDecl &Parent, const CXXRecordDecl &ThisClass) { if (Parent.getCanonicalDecl() == ThisClass.getCanonicalDecl()) return true; const CXXRecordDecl *ParentCanonicalDecl = Parent.getCanonicalDecl(); return ThisClass.bases_end() != llvm::find_if(ThisClass.bases(), [=](const CXXBaseSpecifier &Base) { auto *BaseDecl = Base.getType()->getAsCXXRecordDecl(); assert(BaseDecl); return ParentCanonicalDecl == BaseDecl->getCanonicalDecl(); }); }
static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent, const CXXRecordDecl &ThisClass, const CXXMethodDecl &MemberDecl) { BasesVector Result; for (const auto &Base : ThisClass.bases()) { const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl(); const CXXMethodDecl *ActualMemberDecl = MemberDecl.getCorrespondingMethodInClass(BaseDecl); if (!ActualMemberDecl) continue; // TypePtr is the nearest base class to ThisClass between ThisClass and // GrandParent, where MemberDecl is overridden. TypePtr is the class the // check proposes to fix to. const Type *TypePtr = ActualMemberDecl->getThisType().getTypePtr(); const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl(); assert(RecordDeclType && "TypePtr is not a pointer to CXXRecordDecl!"); if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent)) Result.emplace_back(RecordDeclType); } return Result; }