Commit 2073dd2d authored by Adrian Prantl's avatar Adrian Prantl
Browse files

Redeclare Objective-C property accessors inside the ObjCImplDecl in which they are synthesized.

This patch is motivated by (and factored out from)
https://reviews.llvm.org/D66121 which is a debug info bugfix. Starting
with DWARF 5 all Objective-C methods are nested inside their
containing type, and that patch implements this for synthesized
Objective-C properties.

1. SemaObjCProperty populates a list of synthesized accessors that may
   need to inserted into an ObjCImplDecl.

2. SemaDeclObjC::ActOnEnd inserts forward-declarations for all
   accessors for which no override was provided into their
   ObjCImplDecl. This patch does *not* synthesize AST function
   *bodies*. Moving that code from the static analyzer into Sema may
   be a good idea though.

3. Places that expect all methods to have bodies have been updated.

I did not update the static analyzer's inliner for synthesized
properties to point back to the property declaration (see
test/Analysis/Inputs/expected-plists/nullability-notes.m.plist), which
I believed to be more bug than a feature.

Differential Revision: https://reviews.llvm.org/D68108

rdar://problem/53782400
parent 8d22100f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1590,6 +1590,9 @@ class DeclContext {
    /// True if this method is the getter or setter for an explicit property.
    uint64_t IsPropertyAccessor : 1;

    /// True if this method is a synthesized property accessor stub.
    uint64_t IsSynthesizedAccessorStub : 1;

    /// Method has a definition.
    uint64_t IsDefined : 1;

+21 −0
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ private:
                 Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
                 DeclContext *contextDecl, bool isInstance = true,
                 bool isVariadic = false, bool isPropertyAccessor = false,
                 bool isSynthesizedAccessorStub = false, 
                 bool isImplicitlyDeclared = false, bool isDefined = false,
                 ImplementationControl impControl = None,
                 bool HasRelatedResultType = false);
@@ -232,6 +233,7 @@ public:
         Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
         DeclContext *contextDecl, bool isInstance = true,
         bool isVariadic = false, bool isPropertyAccessor = false,
         bool isSynthesizedAccessorStub = false,
         bool isImplicitlyDeclared = false, bool isDefined = false,
         ImplementationControl impControl = None,
         bool HasRelatedResultType = false);
@@ -436,6 +438,14 @@ public:
    ObjCMethodDeclBits.IsPropertyAccessor = isAccessor;
  }

  bool isSynthesizedAccessorStub() const {
    return ObjCMethodDeclBits.IsSynthesizedAccessorStub;
  }

  void setSynthesizedAccessorStub(bool isSynthesizedAccessorStub) {
    ObjCMethodDeclBits.IsSynthesizedAccessorStub = isSynthesizedAccessorStub;
  }

  bool isDefined() const { return ObjCMethodDeclBits.IsDefined; }
  void setDefined(bool isDefined) { ObjCMethodDeclBits.IsDefined = isDefined; }

@@ -2779,6 +2789,11 @@ private:
  /// Null for \@dynamic. Required for \@synthesize.
  ObjCIvarDecl *PropertyIvarDecl;

  /// The getter's definition, which has an empty body if synthesized.
  ObjCMethodDecl *GetterMethodDecl = nullptr;
  /// The getter's definition, which has an empty body if synthesized.
  ObjCMethodDecl *SetterMethodDecl = nullptr;

  /// Null for \@dynamic. Non-null if property must be copy-constructed in
  /// getter.
  Expr *GetterCXXConstructor = nullptr;
@@ -2845,6 +2860,12 @@ public:
    return IvarLoc.isValid() && IvarLoc != getLocation();
  }

  ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
  void setGetterMethodDecl(ObjCMethodDecl *MD) { GetterMethodDecl = MD; }

  ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
  void setSetterMethodDecl(ObjCMethodDecl *MD) { SetterMethodDecl = MD; }

  Expr *getGetterCXXConstructor() const {
    return GetterCXXConstructor;
  }
+4 −4
Original line number Diff line number Diff line
@@ -3963,10 +3963,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {

  ObjCMethodDecl *ToMethod;
  if (GetImportedOrCreateDecl(
          ToMethod, D, Importer.getToContext(), Loc,
          ToEndLoc, Name.getObjCSelector(), ToReturnType,
          ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(),
          D->isPropertyAccessor(), D->isImplicit(), D->isDefined(),
          ToMethod, D, Importer.getToContext(), Loc, ToEndLoc,
          Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC,
          D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(),
          D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(),
          D->getImplementationControl(), D->hasRelatedResultType()))
    return ToMethod;

+26 −12
Original line number Diff line number Diff line
@@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
// ObjCMethodDecl
//===----------------------------------------------------------------------===//

ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
                               Selector SelInfo, QualType T,
                               TypeSourceInfo *ReturnTInfo,
                               DeclContext *contextDecl, bool isInstance,
                               bool isVariadic, bool isPropertyAccessor,
                               bool isImplicitlyDeclared, bool isDefined,
                               ImplementationControl impControl,
                               bool HasRelatedResultType)
ObjCMethodDecl::ObjCMethodDecl(
    SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo,
    QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl,
    bool isInstance, bool isVariadic, bool isPropertyAccessor,
    bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined,
    ImplementationControl impControl, bool HasRelatedResultType)
    : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
      DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo),
      DeclEndLoc(endLoc) {
@@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
  setInstanceMethod(isInstance);
  setVariadic(isVariadic);
  setPropertyAccessor(isPropertyAccessor);
  setSynthesizedAccessorStub(isSynthesizedAccessorStub);
  setDefined(isDefined);
  setIsRedeclaration(false);
  setHasRedeclaration(false);
@@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(
    ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
    Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
    DeclContext *contextDecl, bool isInstance, bool isVariadic,
    bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined,
    ImplementationControl impControl, bool HasRelatedResultType) {
    bool isPropertyAccessor, bool isSynthesizedAccessorStub,
    bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl,
    bool HasRelatedResultType) {
  return new (C, contextDecl) ObjCMethodDecl(
      beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
      isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined,
      impControl, HasRelatedResultType);
      isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
      isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
}

ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -1306,6 +1306,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {

  if (isPropertyAccessor()) {
    const auto *Container = cast<ObjCContainerDecl>(getParent());
    // For accessor stubs, go back to the interface.
    if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container))
      if (isSynthesizedAccessorStub())
        Container = ImplDecl->getClassInterface();

    bool IsGetter = (NumArgs == 0);
    bool IsInstance = isInstanceMethod();

@@ -1358,6 +1363,15 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
      }
    }

    assert(isSynthesizedAccessorStub() && "expected an accessor stub");
    for (const auto *Cat : ClassDecl->known_categories()) {
      if (Cat == Container)
        continue;

      if (const auto *Found = findMatchingProperty(Cat))
        return Found;
    }

    llvm_unreachable("Marked as a property accessor but no property found!");
  }

+10 −0
Original line number Diff line number Diff line
@@ -830,6 +830,16 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
  if (D->param_size() != 0)
    return nullptr;

  // If the property was defined in an extension, search the extensions for
  // overrides.
  const ObjCInterfaceDecl *OID = D->getClassInterface();
  if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)
    for (auto *Ext : OID->known_extensions()) {
      auto *OMD = Ext->getInstanceMethod(D->getSelector());
      if (OMD && !OMD->isImplicit())
        return nullptr;
    }

  Val = createObjCPropertyGetter(C, Prop);

  return Val.getValue();
Loading