예제 #1
0
static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
  DeclContext *DC = D->getDeclContext();

  // This can only happen at top: enum decls only "publish" their
  // immediate members.
  if (isa<EnumDecl>(DC))
    DC = cast<EnumDecl>(DC)->getDeclContext();

  CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
  while (DeclaringClass->isAnonymousStructOrUnion())
    DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
  return DeclaringClass;
}
예제 #2
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;
}