]> granicus.if.org Git - clang/commitdiff
Objective-C @synthesize support.
authorDaniel Dunbar <daniel@zuster.org>
Tue, 26 Aug 2008 08:29:31 +0000 (08:29 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Tue, 26 Aug 2008 08:29:31 +0000 (08:29 +0000)
 - Only supports simple assignment and atomic semantics are ignored.
 - Not quite usable yet because the methods do not actually get added
   to the class metadata.
 - Added ObjCPropertyDecl::getSetterKind (one of Assign, Copy, Retain).
 - Rearrange CodeGenFunction so synthesis can reuse function prolog /
   epilog code.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55365 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclObjC.h
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGObjCMac.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h

index d985ce39626d8cd5a45ed62dd0397128874b6919..df95847124160e69cf6a8a84fcf32405d71d1752 100644 (file)
@@ -1172,7 +1172,8 @@ public:
     OBJC_PR_nonatomic = 0x40,
     OBJC_PR_setter    = 0x80
   };
-  
+
+  enum SetterKind { Assign, Retain, Copy };
   enum PropertyControl { None, Required, Optional };
 private:
   QualType DeclType;
@@ -1206,10 +1207,24 @@ public:
     PropertyAttributes |= PRVal;
   }
 
+  // Helper methods for accessing attributes.
+
+  /// isReadOnly - Return true iff the property has a setter.
   bool isReadOnly() const {
     return (PropertyAttributes & OBJC_PR_readonly);
   }
-  
+
+  /// getSetterKind - Return the method used for doing assignment in
+  /// the property setter. This is only valid if the property has been
+  /// defined to have a setter.
+  SetterKind getSetterKind() const {
+    if (PropertyAttributes & OBJC_PR_retain)
+      return Retain;
+    if (PropertyAttributes & OBJC_PR_copy)
+      return Copy;
+    return Assign;
+  }
+
   Selector getGetterName() const { return GetterName; }
   void setGetterName(Selector Sel) { GetterName = Sel; }
   
@@ -1278,7 +1293,7 @@ public:
     return PropertyIvarDecl ? Synthesize : Dynamic;
   }
   
-  ObjCIvarDecl *getPropertyIvarDecl() {
+  ObjCIvarDecl *getPropertyIvarDecl() const {
     return PropertyIvarDecl;
   }
   
index ddd7c8119be4ff8551b10684aead8f621197c0ef..93567a4f8f58e57d3e9e7fe7a3b3a509d6db8e56 100644 (file)
@@ -88,9 +88,12 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
   return Runtime.GenerateMessageSend(*this, E, Receiver, isClassMessage);
 }
 
-/// Generate an Objective-C method.  An Objective-C method is a C function with
-/// its pointer, name, and types registered in the class struture.  
-void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
+/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
+/// the LLVM function and sets the other context used by
+/// CodeGenFunction.
+
+// FIXME: This should really be merged with GenerateCode.
+void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD) {
   CurFn = CGM.getObjCRuntime().GenerateMethod(OMD);
   llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", CurFn);
   
@@ -127,8 +130,87 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
     EmitParmDecl(*OMD->getParamDecl(i), AI);
   }
   assert(AI == CurFn->arg_end() && "Argument mismatch");
+}
+
+/// Generate an Objective-C method.  An Objective-C method is a C function with
+/// its pointer, name, and types registered in the class struture.  
+void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
+  StartObjCMethod(OMD);
+  EmitStmt(OMD->getBody());
+
+  const CompoundStmt *S = dyn_cast<CompoundStmt>(OMD->getBody());
+  if (S) {
+    FinishFunction(S->getRBracLoc());
+  } else {
+    FinishFunction();
+  }
+}
+
+// FIXME: I wasn't sure about the synthesis approach. If we end up
+// generating an AST for the whole body we can just fall back to
+// having a GenerateFunction which takes the body Stmt.
+
+/// GenerateObjCGetter - Generate an Objective-C property getter
+/// function. The given Decl must be either an ObjCCategoryImplDecl
+/// or an ObjCImplementationDecl.
+void CodeGenFunction::GenerateObjCGetter(const ObjCPropertyImplDecl *PID) {
+  const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+  ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
+  assert(OMD && "Invalid call to generate getter (empty method)");
+  // FIXME: This is rather murky, we create this here since they will
+  // not have been created by Sema for us.
+  OMD->createImplicitParams(getContext());
+  StartObjCMethod(OMD);
+
+  // FIXME: What about nonatomic?
+  SourceLocation Loc = PD->getLocation();
+  ValueDecl *Self = OMD->getSelfDecl();
+  ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
+  DeclRefExpr Base(Self, Self->getType(), Loc);
+  ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base,
+                          true, true);
+  ReturnStmt Return(Loc, &IvarRef);
+  EmitStmt(&Return);
+
+  FinishFunction();
+}
+
+/// GenerateObjCSetter - Generate an Objective-C property setter
+/// function. The given Decl must be either an ObjCCategoryImplDecl
+/// or an ObjCImplementationDecl.
+void CodeGenFunction::GenerateObjCSetter(const ObjCPropertyImplDecl *PID) {
+  const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+  ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
+  assert(OMD && "Invalid call to generate setter (empty method)");
+  // FIXME: This is rather murky, we create this here since they will
+  // not have been created by Sema for us.  
+  OMD->createImplicitParams(getContext());
+  StartObjCMethod(OMD);
+  
+  switch (PD->getSetterKind()) {
+  case ObjCPropertyDecl::Assign: break;
+  case ObjCPropertyDecl::Copy:
+      CGM.ErrorUnsupported(PID, "Obj-C setter with 'copy'");
+      break;
+  case ObjCPropertyDecl::Retain:
+      CGM.ErrorUnsupported(PID, "Obj-C setter with 'retain'");
+      break;
+  }
 
-  GenerateFunction(OMD->getBody());
+  // FIXME: What about nonatomic?
+  SourceLocation Loc = PD->getLocation();
+  ValueDecl *Self = OMD->getSelfDecl();
+  ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
+  DeclRefExpr Base(Self, Self->getType(), Loc);
+  ParmVarDecl *ArgDecl = OMD->getParamDecl(0);
+  DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), Loc);
+  ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base,
+                          true, true);
+  BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign,
+                        Ivar->getType(), Loc);
+  EmitStmt(&Assign);
+
+  FinishFunction();
 }
 
 llvm::Value *CodeGenFunction::LoadObjCSelf(void) {
index 4223709786370e32565f335039218b49c41e7475..50d3abee0ba4bdfc28adf3bc5182ce5c0257ed0c 100644 (file)
@@ -233,9 +233,7 @@ private:
                                 const llvm::Type *InterfaceTy);
 
   /// EmitMethodList - Emit the method list for the given
-  /// implementation. If ForClass is true the list of class methods
-  /// will be emitted, otherwise the list of instance methods will be
-  /// generated. The return value has type MethodListPtrTy.
+  /// implementation. The return value has type MethodListPtrTy.
   llvm::Constant *EmitMethodList(const std::string &Name,
                                  const char *Section,
                    llvm::SmallVector<ObjCMethodDecl*, 32>::const_iterator begin,
index 11fde87302891f5a461c82713e55d6bc0dda70f2..909486a6d1a944a200833e0477c7b055debd3900 100644 (file)
@@ -62,19 +62,15 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
     !T->isVoidType() && !T->isVectorType() && !T->isFunctionType();
 }
 
-void CodeGenFunction::GenerateFunction(const Stmt *Body) {
-  // Emit the function body.
-  EmitStmt(Body);
-
+void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
   // Finish emission of indirect switches.
   EmitIndirectSwitches();
 
   // Emit debug descriptor for function end.
   CGDebugInfo *DI = CGM.getDebugInfo(); 
   if (DI) {
-    const CompoundStmt* s = dyn_cast<CompoundStmt>(Body);
-    if (s && s->getRBracLoc().isValid()) {
-      DI->setLocation(s->getRBracLoc());
+    if (EndLoc.isValid()) {
+      DI->setLocation(EndLoc);
     }
     DI->EmitRegionEnd(CurFn, Builder);
   }
@@ -156,7 +152,15 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD,
       EmitParmDecl(*CurParam, V);
     }
   }
-  GenerateFunction(FD->getBody());
+
+  EmitStmt(FD->getBody());
+  
+  const CompoundStmt *S = dyn_cast<CompoundStmt>(FD->getBody());
+  if (S) {
+    FinishFunction(S->getRBracLoc());
+  } else {
+    FinishFunction();
+  }
 }
 
 /// isDummyBlock - Return true if BB is an empty basic block
index 2ba6b8ddcce6660c6f764349e1d8dafe57b75c7c..4eed9a7173f574bd7c1f41d4b67d771da447ccf5 100644 (file)
@@ -39,6 +39,7 @@ namespace clang {
   class FunctionTypeProto;
   class LabelStmt;
   class ObjCMethodDecl;
+  class ObjCPropertyImplDecl;
   class TargetInfo;
   class VarDecl;
 
@@ -112,9 +113,20 @@ public:
   ASTContext &getContext() const;
 
   void GenerateObjCMethod(const ObjCMethodDecl *OMD);
+
+  void StartObjCMethod(const ObjCMethodDecl *MD);
+
+  /// GenerateObjCGetter - Synthesize an Objective-C property getter
+  /// function.
+  void GenerateObjCGetter(const ObjCPropertyImplDecl *PID);
+
+  /// GenerateObjCSetter - Synthesize an Objective-C property setter
+  /// function for the given property.
+  void GenerateObjCSetter(const ObjCPropertyImplDecl *PID);
+
   void GenerateCode(const FunctionDecl *FD,
                     llvm::Function *Fn);
-  void GenerateFunction(const Stmt *Body);
+  void FinishFunction(SourceLocation EndLoc=SourceLocation());
   
   const llvm::Type *ConvertType(QualType T);
 
index 51428c07ac81f0654f4c97c955c2621918ad5806..57d5377bc377f966f301d8841ea155d1d0777410 100644 (file)
@@ -836,6 +836,32 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str)
   return GetAddrOfConstantString(str + "\0");
 }
 
+/// EmitObjCPropertyImplementations - Emit information for synthesized
+/// properties for an implementation.
+void CodeGenModule::EmitObjCPropertyImplementations(const 
+                                                    ObjCImplementationDecl *D) {
+  for (ObjCImplementationDecl::propimpl_iterator i = D->propimpl_begin(),
+         e = D->propimpl_end(); i != e; ++i) {
+    ObjCPropertyImplDecl *PID = *i;
+    
+    // Dynamic is just for type-checking.
+    if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
+      ObjCPropertyDecl *PD = PID->getPropertyDecl();
+
+      // Determine which methods need to be implemented, some may have
+      // been overridden. Note that ::isSynthesized is not the method
+      // we want, that just indicates if the decl came from a
+      // property. What we want to know is if the method is defined in
+      // this implementation.
+      if (!D->getInstanceMethod(PD->getGetterName()))
+        CodeGenFunction(*this).GenerateObjCGetter(PID);
+      if (!PD->isReadOnly() &&
+          !D->getInstanceMethod(PD->getSetterName()))
+        CodeGenFunction(*this).GenerateObjCSetter(PID);
+    }
+  }
+}
+
 /// EmitTopLevelDecl - Emit code for a single top level declaration.
 void CodeGenModule::EmitTopLevelDecl(Decl *D) {
   // If an error has occurred, stop code generation, but continue
@@ -868,13 +894,18 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
     break;
 
   case Decl::ObjCCategoryImpl:
+    // Categories have properties but don't support synthesize so we
+    // can ignore them here.
+
     Runtime->GenerateCategory(cast<ObjCCategoryImplDecl>(D));
     break;
 
-  case Decl::ObjCImplementation:
-    Runtime->GenerateClass(cast<ObjCImplementationDecl>(D));
+  case Decl::ObjCImplementation: {
+    ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
+    EmitObjCPropertyImplementations(OMD);
+    Runtime->GenerateClass(OMD);
     break;
-    
+  } 
   case Decl::ObjCMethod: {
     ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(D);
     // If this is not a prototype, emit the body.
@@ -882,9 +913,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
       CodeGenFunction(*this).GenerateObjCMethod(OMD);
     break;
   }
-  case Decl::ObjCPropertyImpl:
-    assert(0 && "FIXME: ObjCPropertyImpl unsupported");
-    break;
   case Decl::ObjCCompatibleAlias: 
     assert(0 && "FIXME: ObjCCompatibleAlias unsupported");
     break;
index 7501fd461e6c0312f974be73f5f74d78d9591229..b339ae9d67439f70d48ca53c4103c24642fc7eaa 100644 (file)
@@ -217,6 +217,7 @@ private:
   llvm::GlobalValue *EmitForwardFunctionDefinition(const FunctionDecl *D);
   void EmitGlobalFunctionDefinition(const FunctionDecl *D);
   void EmitGlobalVarDefinition(const VarDecl *D);
+  void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
   
   // FIXME: Hardcoding priority here is gross.
   void AddGlobalCtor(llvm::Function * Ctor, int Priority=65535);