Esempio n. 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);
    }
  }
}
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();
         });
}
Esempio n. 3
0
/// Determines whether the accessed entity is accessible.  Public members
/// have been weeded out by this point.
static AccessResult IsAccessible(Sema &S,
                                 const EffectiveContext &EC,
                                 AccessTarget &Entity) {
  // Determine the actual naming class.
  CXXRecordDecl *NamingClass = Entity.getNamingClass();
  while (NamingClass->isAnonymousStructOrUnion())
    NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
  NamingClass = NamingClass->getCanonicalDecl();

  AccessSpecifier UnprivilegedAccess = Entity.getAccess();
  assert(UnprivilegedAccess != AS_public && "public access not weeded out");

  // Before we try to recalculate access paths, try to white-list
  // accesses which just trade in on the final step, i.e. accesses
  // which don't require [M4] or [B4]. These are by far the most
  // common forms of privileged access.
  if (UnprivilegedAccess != AS_none) {
    switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
    case AR_dependent:
      // This is actually an interesting policy decision.  We don't
      // *have* to delay immediately here: we can do the full access
      // calculation in the hope that friendship on some intermediate
      // class will make the declaration accessible non-dependently.
      // But that's not cheap, and odds are very good (note: assertion
      // made without data) that the friend declaration will determine
      // access.
      return AR_dependent;

    case AR_accessible: return AR_accessible;
    case AR_inaccessible: break;
    }
  }

  AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();

  // We lower member accesses to base accesses by pretending that the
  // member is a base class of its declaring class.
  AccessSpecifier FinalAccess;

  if (Entity.isMemberAccess()) {
    // Determine if the declaration is accessible from EC when named
    // in its declaring class.
    NamedDecl *Target = Entity.getTargetDecl();
    const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();

    FinalAccess = Target->getAccess();
    switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
    case AR_accessible:
      FinalAccess = AS_public;
      break;
    case AR_inaccessible: break;
    case AR_dependent: return AR_dependent; // see above
    }

    if (DeclaringClass == NamingClass)
      return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);

    Entity.suppressInstanceContext();
  } else {
    FinalAccess = AS_public;
  }

  assert(Entity.getDeclaringClass() != NamingClass);

  // Append the declaration's access if applicable.
  CXXBasePaths Paths;
  CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
  if (!Path)
    return AR_dependent;

  assert(Path->Access <= UnprivilegedAccess &&
         "access along best path worse than direct?");
  if (Path->Access == AS_public)
    return AR_accessible;
  return AR_inaccessible;
}