Example #1
0
/// 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;
}