Skip to content

Commit

Permalink
Merge pull request #7762 from jacob-carlborg/objc_class_methods
Browse files Browse the repository at this point in the history
Add support for Objective-C class/static methods
merged-on-behalf-of: Mike Franklin <JinShil@users.noreply.github.com>
  • Loading branch information
dlang-bot committed Mar 3, 2018
2 parents de44987 + bf824c6 commit acacaad
Show file tree
Hide file tree
Showing 20 changed files with 552 additions and 34 deletions.
45 changes: 45 additions & 0 deletions changelog/objc_class_methods.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Support for calling Objective-C class (static) methods has been added.

Previously to call an Objective-C class method it was necessary to make explicit
calls to the Objective-C runtime. The following code is an example of the old
way to call a class method:

---
extern (C) Class objc_lookUpClass(in char* name);

extern (Objective-C)
interface Class
{
NSObject alloc() @selector("alloc");
}

extern (Objective-C)
interface NSObject
{
NSObject init() @selector("init");
}

void main()
{
auto cls = objc_lookUpClass("NSObject");
auto o = cls.alloc().init();
}
---

The above code can now be replaced with the following:

---
extern (Objective-C)
interface NSObject
{
static NSObject alloc() @selector("alloc");
NSObject init() @selector("init");
}

void main()
{
auto o = NSObject.alloc().init();
}
---

Note the use of the `static` attribute in the method declaration.
1 change: 1 addition & 0 deletions src/dmd/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ class ClassDeclaration : public AggregateDeclaration

Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract
Baseok baseok; // set the progress of base classes resolving
ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration
Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr

static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
Expand Down
7 changes: 7 additions & 0 deletions src/dmd/dclass.d
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import dmd.globals;
import dmd.id;
import dmd.identifier;
import dmd.mtype;
import dmd.objc;
import dmd.root.rmem;
import dmd.target;
import dmd.visitor;
Expand Down Expand Up @@ -244,6 +245,12 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
/// set the progress of base classes resolving
Baseok baseok;

/**
* Data for a class declaration that is needed for the Objective-C
* integration.
*/
ObjcClassDeclaration objc;

Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr

final extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
Expand Down
1 change: 1 addition & 0 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -4800,6 +4800,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (idec.baseok == Baseok.done)
{
idec.baseok = Baseok.semanticdone;
objc.setMetaclass(idec);

// initialize vtbl
if (idec.vtblOffset())
Expand Down
5 changes: 5 additions & 0 deletions src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -5423,6 +5423,11 @@ elem *toElem(Expression e, IRState *irs)
result = toElemStructLit(sle, irs, TOK.construct, sle.sym, true);
}

override void visit(ObjcClassReferenceExp e)
{
result = objc.toElem(e);
}

/*****************************************************/
/* CTFE stuff */
/*****************************************************/
Expand Down
36 changes: 36 additions & 0 deletions src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import dmd.identifier;
import dmd.inline;
import dmd.mtype;
import dmd.nspace;
import dmd.objc;
import dmd.opover;
import dmd.optimize;
import dmd.root.ctfloat;
Expand Down Expand Up @@ -97,6 +98,18 @@ L1:
Type t = e1.type.toBasetype();
//printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());

if (e1.op == TOK.objcClassReference)
{
// We already have an Objective-C class reference, just use that as 'this'.
return e1;
}
else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
var.isFuncDeclaration.selector)
{
return new ObjcClassReferenceExp(e1.loc, cast(ClassDeclaration) ad);
}

/* If e1 is not the 'this' pointer for ad
*/
if (ad &&
Expand Down Expand Up @@ -7237,3 +7250,26 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp
v.visit(this);
}
}

/**
* Objective-C class reference expression.
*
* Used to get the metaclass of an Objective-C class, `NSObject.Class`.
*/
extern (C++) final class ObjcClassReferenceExp : Expression
{
ClassDeclaration classDeclaration;

extern (D) this(Loc loc, ClassDeclaration classDeclaration)
{
super(loc, TOK.objcClassReference,
__traits(classInstanceSize, ObjcClassReferenceExp));
this.classDeclaration = classDeclaration;
type = objc.getRuntimeMetaclass(classDeclaration).getType();
}

override void accept(Visitor v)
{
v.visit(this);
}
}
7 changes: 7 additions & 0 deletions src/dmd/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -1383,6 +1383,13 @@ struct UnionExp

/****************************************************************/

class ObjcClassReferenceExp : public Expression
{
ClassDeclaration* classDeclaration;

void accept(Visitor *v) { v->visit(this); }
};

/* Special values used by the interpreter
*/

Expand Down
2 changes: 1 addition & 1 deletion src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -1518,7 +1518,7 @@ extern (C++) class FuncDeclaration : Declaration
override inout(AggregateDeclaration) isThis() inout
{
//printf("+FuncDeclaration::isThis() '%s'\n", toChars());
auto ad = (storage_class & STC.static_) ? null : isMember2();
auto ad = (storage_class & STC.static_) ? objc.isThis(this) : isMember2();
//printf("-FuncDeclaration::isThis() %p\n", ad);
return ad;
}
Expand Down
2 changes: 2 additions & 0 deletions src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ immutable Msgtable[] msgtable =
{ "xopCmp", "__xopCmp" },
{ "xtoHash", "__xtoHash" },

{ "Class" },

{ "LINE", "__LINE__" },
{ "FILE", "__FILE__" },
{ "MODULE", "__MODULE__" },
Expand Down
10 changes: 9 additions & 1 deletion src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -7857,7 +7857,15 @@ extern (C++) final class TypeClass : Type
e = e.expressionSemantic(sc);
return e;
}
if (d.needThis() && sc.intypeof != 1)
if (sym.classKind == ClassKind.objc
&& d.isFuncDeclaration()
&& d.isFuncDeclaration().isStatic
&& d.isFuncDeclaration().selector)
{
auto classRef = new ObjcClassReferenceExp(e.loc, sym);
return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
}
else if (d.needThis() && sc.intypeof != 1)
{
/* Rewrite as:
* this.d
Expand Down

0 comments on commit acacaad

Please sign in to comment.