1
/**
2
 * Interfacing with Objective-C.
3
 *
4
 * Specification: $(LINK2 https://dlang.org/spec/objc_interface.html, Interfacing to Objective-C)
5
 *
6
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d)
10
 * Documentation:  https://dlang.org/phobos/dmd_objc.html
11
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/objc.d
12
 */
13

14
module dmd.objc;
15

16
import dmd.aggregate;
17
import dmd.arraytypes;
18
import dmd.attrib;
19
import dmd.cond;
20
import dmd.dclass;
21
import dmd.declaration;
22
import dmd.dmangle;
23
import dmd.dmodule;
24
import dmd.dscope;
25
import dmd.dstruct;
26
import dmd.dsymbol;
27
import dmd.dsymbolsem;
28
import dmd.errors;
29
import dmd.expression;
30
import dmd.expressionsem;
31
import dmd.func;
32
import dmd.globals;
33
import dmd.gluelayer;
34
import dmd.id;
35
import dmd.identifier;
36
import dmd.mtype;
37
import dmd.root.outbuffer;
38
import dmd.root.stringtable;
39
import dmd.target;
40

41
struct ObjcSelector
42
{
43
    // MARK: Selector
44
    private __gshared StringTable!(ObjcSelector*) stringtable;
45
    private __gshared int incnum = 0;
46
    const(char)* stringvalue;
47
    size_t stringlen;
48
    size_t paramCount;
49

50
    extern (C++) static void _init()
51
    {
52 0
        stringtable._init();
53
    }
54

55 0
    extern (D) this(const(char)* sv, size_t len, size_t pcount)
56
    {
57 0
        stringvalue = sv;
58 0
        stringlen = len;
59 0
        paramCount = pcount;
60
    }
61

62
    extern (D) static ObjcSelector* lookup(const(char)* s)
63
    {
64 0
        size_t len = 0;
65 0
        size_t pcount = 0;
66 0
        const(char)* i = s;
67 0
        while (*i != 0)
68
        {
69 0
            ++len;
70 0
            if (*i == ':')
71 0
                ++pcount;
72 0
            ++i;
73
        }
74 0
        return lookup(s, len, pcount);
75
    }
76

77
    extern (D) static ObjcSelector* lookup(const(char)* s, size_t len, size_t pcount)
78
    {
79 0
        auto sv = stringtable.update(s, len);
80 0
        ObjcSelector* sel = sv.value;
81 0
        if (!sel)
82
        {
83 0
            sel = new ObjcSelector(sv.toDchars(), len, pcount);
84 0
            sv.value = sel;
85
        }
86 0
        return sel;
87
    }
88

89
    extern (C++) static ObjcSelector* create(FuncDeclaration fdecl)
90
    {
91 0
        OutBuffer buf;
92 0
        TypeFunction ftype = cast(TypeFunction)fdecl.type;
93 0
        const id = fdecl.ident.toString();
94 0
        const nparams = ftype.parameterList.length;
95
        // Special case: property setter
96 0
        if (ftype.isproperty && nparams == 1)
97
        {
98
            // rewrite "identifier" as "setIdentifier"
99 0
            char firstChar = id[0];
100 0
            if (firstChar >= 'a' && firstChar <= 'z')
101 0
                firstChar = cast(char)(firstChar - 'a' + 'A');
102 0
            buf.writestring("set");
103 0
            buf.writeByte(firstChar);
104 0
            buf.write(id[1 .. id.length - 1]);
105 0
            buf.writeByte(':');
106 0
            goto Lcomplete;
107
        }
108
        // write identifier in selector
109 0
        buf.write(id[]);
110
        // add mangled type and colon for each parameter
111 0
        if (nparams)
112
        {
113 0
            buf.writeByte('_');
114 0
            foreach (i, fparam; ftype.parameterList)
115
            {
116 0
                mangleToBuffer(fparam.type, &buf);
117 0
                buf.writeByte(':');
118
            }
119
        }
120
    Lcomplete:
121 0
        buf.writeByte('\0');
122
        // the slice is not expected to include a terminating 0
123 0
        return lookup(cast(const(char)*)buf[].ptr, buf.length - 1, nparams);
124
    }
125

126
    extern (D) const(char)[] toString() const pure
127
    {
128 0
        return stringvalue[0 .. stringlen];
129
    }
130
}
131

132
private __gshared Objc _objc;
133

134
Objc objc()
135
{
136 1
    return _objc;
137
}
138

139

140
/**
141
 * Contains all data for a class declaration that is needed for the Objective-C
142
 * integration.
143
 */
144
extern (C++) struct ObjcClassDeclaration
145
{
146
    /// `true` if this class is a metaclass.
147
    bool isMeta = false;
148

149
    /// `true` if this class is externally defined.
150
    bool isExtern = false;
151

152
    /// Name of this class.
153
    Identifier identifier;
154

155
    /// The class declaration this belongs to.
156
    ClassDeclaration classDeclaration;
157

158
    /// The metaclass of this class.
159
    ClassDeclaration metaclass;
160

161
    /// List of non-inherited methods.
162
    Dsymbols* methodList;
163

164 1
    extern (D) this(ClassDeclaration classDeclaration)
165
    {
166 1
        this.classDeclaration = classDeclaration;
167 1
        methodList = new Dsymbols;
168
    }
169

170
    bool isRootClass() const
171
    {
172 0
        return classDeclaration.classKind == ClassKind.objc &&
173 0
            !metaclass &&
174 0
            !classDeclaration.baseClass;
175
    }
176
}
177

178
// Should be an interface
179
extern(C++) abstract class Objc
180
{
181
    static void _init()
182
    {
183 1
        if (target.objc.supported)
184 0
            _objc = new Supported;
185
        else
186 1
            _objc = new Unsupported;
187
    }
188

189
    /**
190
     * Deinitializes the global state of the compiler.
191
     *
192
     * This can be used to restore the state set by `_init` to its original
193
     * state.
194
     */
195
    static void deinitialize()
196
    {
197 0
        _objc = _objc.init;
198
    }
199

200
    abstract void setObjc(ClassDeclaration cd);
201
    abstract void setObjc(InterfaceDeclaration);
202

203
    /**
204
     * Deprecate the given Objective-C interface.
205
     *
206
     * Representing an Objective-C class as a D interface has been deprecated.
207
     * Classes have now been properly implemented and the `class` keyword should
208
     * be used instead.
209
     *
210
     * In the future, `extern(Objective-C)` interfaces will be used to represent
211
     * Objective-C protocols.
212
     *
213
     * Params:
214
     *  interfaceDeclaration = the interface declaration to deprecate
215
     */
216
    abstract void deprecate(InterfaceDeclaration interfaceDeclaration) const;
217

218
    abstract void setSelector(FuncDeclaration, Scope* sc);
219
    abstract void validateSelector(FuncDeclaration fd);
220
    abstract void checkLinkage(FuncDeclaration fd);
221

222
    /**
223
     * Returns `true` if the given function declaration is virtual.
224
     *
225
     * Function declarations with Objective-C linkage and which are static or
226
     * final are considered virtual.
227
     *
228
     * Params:
229
     *  fd = the function declaration to check if it's virtual
230
     *
231
     * Returns: `true` if the given function declaration is virtual
232
     */
233
    abstract bool isVirtual(const FuncDeclaration fd) const;
234

235
    /**
236
     * Gets the parent of the given function declaration.
237
     *
238
     * Handles Objective-C static member functions, which are virtual functions
239
     * of the metaclass, by returning the parent class declaration to the
240
     * metaclass.
241
     *
242
     * Params:
243
     *  fd = the function declaration to get the parent of
244
     *  cd = the current parent, i.e. the class declaration the given function
245
     *      declaration belongs to
246
     *
247
     * Returns: the parent
248
     */
249
    abstract ClassDeclaration getParent(FuncDeclaration fd,
250
        ClassDeclaration cd) const;
251

252
    /**
253
     * Adds the given function to the list of Objective-C methods.
254
     *
255
     * This list will later be used output the necessary Objective-C module info.
256
     *
257
     * Params:
258
     *  fd = the function declaration to be added to the list
259
     *  cd = the class declaration the function belongs to
260
     */
261
    abstract void addToClassMethodList(FuncDeclaration fd,
262
        ClassDeclaration cd) const;
263

264
    /**
265
     * Returns the `this` pointer of the given function declaration.
266
     *
267
     * This is only used for class/static methods. For instance methods, no
268
     * Objective-C specialization is necessary.
269
     *
270
     * Params:
271
     *  funcDeclaration = the function declaration to get the `this` pointer for
272
     *
273
     * Returns: the `this` pointer of the given function declaration, or `null`
274
     *  if the given function declaration is not an Objective-C method.
275
     */
276
    abstract inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const;
277

278
    /**
279
     * Creates the selector parameter for the given function declaration.
280
     *
281
     * Objective-C methods has an extra hidden parameter that comes after the
282
     * `this` parameter. The selector parameter is of the Objective-C type `SEL`
283
     * and contains the selector which this method was called with.
284
     *
285
     * Params:
286
     *  fd = the function declaration to create the parameter for
287
     *  sc = the scope from the semantic phase
288
     *
289
     * Returns: the newly created selector parameter or `null` for
290
     *  non-Objective-C functions
291
     */
292
    abstract VarDeclaration createSelectorParameter(FuncDeclaration fd, Scope* sc) const;
293

294
    /**
295
     * Creates and sets the metaclass on the given class/interface declaration.
296
     *
297
     * Will only be performed on regular Objective-C classes, not on metaclasses.
298
     *
299
     * Params:
300
     *  classDeclaration = the class/interface declaration to set the metaclass on
301
     */
302
    abstract void setMetaclass(InterfaceDeclaration interfaceDeclaration, Scope* sc) const;
303

304
    /// ditto
305
    abstract void setMetaclass(ClassDeclaration classDeclaration, Scope* sc) const;
306

307
    /**
308
     * Returns Objective-C runtime metaclass of the given class declaration.
309
     *
310
     * `ClassDeclaration.ObjcClassDeclaration.metaclass` contains the metaclass
311
     * from the semantic point of view. This function returns the metaclass from
312
     * the Objective-C runtime's point of view. Here, the metaclass of a
313
     * metaclass is the root metaclass, not `null`. The root metaclass's
314
     * metaclass is itself.
315
     *
316
     * Params:
317
     *  classDeclaration = The class declaration to return the metaclass of
318
     *
319
     * Returns: the Objective-C runtime metaclass of the given class declaration
320
     */
321
    abstract ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const;
322

323
    ///
324
    abstract void addSymbols(AttribDeclaration attribDeclaration,
325
        ClassDeclarations* classes, ClassDeclarations* categories) const;
326

327
    ///
328
    abstract void addSymbols(ClassDeclaration classDeclaration,
329
        ClassDeclarations* classes, ClassDeclarations* categories) const;
330

331
    /**
332
     * Issues a compile time error if the `.offsetof`/`.tupleof` property is
333
     * used on a field of an Objective-C class.
334
     *
335
     * To solve the fragile base class problem in Objective-C, fields have a
336
     * dynamic offset instead of a static offset. The compiler outputs a
337
     * statically known offset which later the dynamic loader can update, if
338
     * necessary, when the application is loaded. Due to this behavior it
339
     * doesn't make sense to be able to get the offset of a field at compile
340
     * time, because this offset might not actually be the same at runtime.
341
     *
342
     * To get the offset of a field that is correct at runtime, functionality
343
     * from the Objective-C runtime can be used instead.
344
     *
345
     * Params:
346
     *  expression = the `.offsetof`/`.tupleof` expression
347
     *  aggregateDeclaration = the aggregate declaration the field of the
348
     *      `.offsetof`/`.tupleof` expression belongs to
349
     *  type = the type of the receiver of the `.tupleof` expression
350
     *
351
     * See_Also:
352
     *  $(LINK2 https://en.wikipedia.org/wiki/Fragile_binary_interface_problem,
353
     *      Fragile Binary Interface Problem)
354
     *
355
     * See_Also:
356
     *  $(LINK2 https://developer.apple.com/documentation/objectivec/objective_c_runtime,
357
     *      Objective-C Runtime)
358
     */
359
    abstract void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const;
360

361
    /// ditto
362
    abstract void checkTupleof(Expression expression, TypeClass type) const;
363
}
364

365
extern(C++) private final class Unsupported : Objc
366
{
367 1
    extern(D) final this()
368
    {
369 1
        ObjcGlue.initialize();
370
    }
371

372
    override void setObjc(ClassDeclaration cd)
373
    {
374 0
        cd.error("Objective-C classes not supported");
375
    }
376

377
    override void setObjc(InterfaceDeclaration id)
378
    {
379 0
        id.error("Objective-C interfaces not supported");
380
    }
381

382
    override void deprecate(InterfaceDeclaration) const
383
    {
384
        // noop
385
    }
386

387
    override void setSelector(FuncDeclaration, Scope*)
388
    {
389
        // noop
390
    }
391

392
    override void validateSelector(FuncDeclaration)
393
    {
394
        // noop
395
    }
396

397
    override void checkLinkage(FuncDeclaration)
398
    {
399
        // noop
400
    }
401

402
    override bool isVirtual(const FuncDeclaration) const
403
    {
404 0
        assert(0, "Should never be called when Objective-C is not supported");
405
    }
406

407
    override ClassDeclaration getParent(FuncDeclaration, ClassDeclaration cd) const
408
    {
409 1
        return cd;
410
    }
411

412
    override void addToClassMethodList(FuncDeclaration, ClassDeclaration) const
413
    {
414
        // noop
415
    }
416

417
    override inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const
418
    {
419 1
        return null;
420
    }
421

422
    override VarDeclaration createSelectorParameter(FuncDeclaration, Scope*) const
423
    {
424 1
        return null;
425
    }
426

427
    override void setMetaclass(InterfaceDeclaration, Scope*) const
428
    {
429
        // noop
430
    }
431

432
    override void setMetaclass(ClassDeclaration, Scope*) const
433
    {
434
        // noop
435
    }
436

437
    override ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const
438
    {
439 0
        assert(0, "Should never be called when Objective-C is not supported");
440
    }
441

442
    override void addSymbols(AttribDeclaration attribDeclaration,
443
        ClassDeclarations* classes, ClassDeclarations* categories) const
444
    {
445
        // noop
446
    }
447

448
    override void addSymbols(ClassDeclaration classDeclaration,
449
        ClassDeclarations* classes, ClassDeclarations* categories) const
450
    {
451
        // noop
452
    }
453

454
    override void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const
455
    {
456
        // noop
457
    }
458

459
    override void checkTupleof(Expression expression, TypeClass type) const
460
    {
461
        // noop
462
    }
463
}
464

465
extern(C++) private final class Supported : Objc
466
{
467 0
    extern(D) final this()
468
    {
469 0
        VersionCondition.addPredefinedGlobalIdent("D_ObjectiveC");
470

471 0
        ObjcGlue.initialize();
472 0
        ObjcSelector._init();
473
    }
474

475
    override void setObjc(ClassDeclaration cd)
476
    {
477 0
        cd.classKind = ClassKind.objc;
478 0
        cd.objc.isExtern = (cd.storage_class & STC.extern_) > 0;
479
    }
480

481
    override void setObjc(InterfaceDeclaration id)
482
    {
483 0
        id.classKind = ClassKind.objc;
484 0
        id.objc.isExtern = true;
485
    }
486

487
    override void deprecate(InterfaceDeclaration id) const
488
    in
489
    {
490
        assert(id.classKind == ClassKind.objc);
491
    }
492
    do
493
    {
494
        // don't report deprecations for the metaclass to avoid duplicated
495
        // messages.
496 0
        if (id.objc.isMeta)
497 0
            return;
498

499 0
        id.deprecation("Objective-C interfaces have been deprecated");
500 0
        deprecationSupplemental(id.loc, "Representing an Objective-C class " ~
501
            "as a D interface has been deprecated. Please use "~
502
            "`extern (Objective-C) extern class` instead");
503
    }
504

505
    override void setSelector(FuncDeclaration fd, Scope* sc)
506
    {
507
        import dmd.tokens;
508

509 0
        if (!fd.userAttribDecl)
510 0
            return;
511 0
        Expressions* udas = fd.userAttribDecl.getAttributes();
512 0
        arrayExpressionSemantic(udas, sc, true);
513 0
        for (size_t i = 0; i < udas.dim; i++)
514
        {
515 0
            Expression uda = (*udas)[i];
516 0
            assert(uda);
517 0
            if (uda.op != TOK.tuple)
518 0
                continue;
519 0
            Expressions* exps = (cast(TupleExp)uda).exps;
520 0
            for (size_t j = 0; j < exps.dim; j++)
521
            {
522 0
                Expression e = (*exps)[j];
523 0
                assert(e);
524 0
                if (e.op != TOK.structLiteral)
525 0
                    continue;
526 0
                StructLiteralExp literal = cast(StructLiteralExp)e;
527 0
                assert(literal.sd);
528 0
                if (!isUdaSelector(literal.sd))
529 0
                    continue;
530 0
                if (fd.selector)
531
                {
532 0
                    fd.error("can only have one Objective-C selector per method");
533 0
                    return;
534
                }
535 0
                assert(literal.elements.dim == 1);
536 0
                StringExp se = (*literal.elements)[0].toStringExp();
537 0
                assert(se);
538 0
                fd.selector = ObjcSelector.lookup(cast(const(char)*)se.toUTF8(sc).peekString().ptr);
539
            }
540
        }
541
    }
542

543
    override void validateSelector(FuncDeclaration fd)
544
    {
545 0
        if (!fd.selector)
546 0
            return;
547 0
        TypeFunction tf = cast(TypeFunction)fd.type;
548 0
        if (fd.selector.paramCount != tf.parameterList.parameters.dim)
549 0
            fd.error("number of colons in Objective-C selector must match number of parameters");
550 0
        if (fd.parent && fd.parent.isTemplateInstance())
551 0
            fd.error("template cannot have an Objective-C selector attached");
552
    }
553

554
    override void checkLinkage(FuncDeclaration fd)
555
    {
556 0
        if (fd.linkage != LINK.objc && fd.selector)
557 0
            fd.error("must have Objective-C linkage to attach a selector");
558
    }
559

560
    override bool isVirtual(const FuncDeclaration fd) const
561
    in
562
    {
563
        assert(fd.selector);
564
        assert(fd.isMember);
565
    }
566
    do
567
    {
568
        // * final member functions are kept virtual with Objective-C linkage
569
        //   because the Objective-C runtime always use dynamic dispatch.
570
        // * static member functions are kept virtual too, as they represent
571
        //   methods of the metaclass.
572 0
        with (fd.protection)
573 0
            return !(kind == Prot.Kind.private_ || kind == Prot.Kind.package_);
574
    }
575

576
    override ClassDeclaration getParent(FuncDeclaration fd, ClassDeclaration cd) const
577
    out(metaclass)
578 0
    {
579 0
        assert(metaclass);
580
    }
581
    do
582
    {
583 0
        if (cd.classKind == ClassKind.objc && fd.isStatic && !cd.objc.isMeta)
584 0
            return cd.objc.metaclass;
585
        else
586 0
            return cd;
587
    }
588

589
    override void addToClassMethodList(FuncDeclaration fd, ClassDeclaration cd) const
590
    in
591
    {
592
        assert(fd.parent.isClassDeclaration);
593
    }
594
    do
595
    {
596 0
        if (cd.classKind != ClassKind.objc)
597 0
            return;
598

599 0
        if (!fd.selector)
600 0
            return;
601

602 0
        assert(fd.isStatic ? cd.objc.isMeta : !cd.objc.isMeta);
603

604 0
        cd.objc.methodList.push(fd);
605
    }
606

607
    override inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const
608
    {
609 0
        with(funcDeclaration)
610
        {
611 0
            if (!selector)
612 0
                return null;
613

614
            // Use Objective-C class object as 'this'
615 0
            auto cd = isMember2().isClassDeclaration();
616

617 0
            if (cd.classKind == ClassKind.objc)
618
            {
619 0
                if (!cd.objc.isMeta)
620 0
                    return cd.objc.metaclass;
621
            }
622

623 0
            return null;
624
        }
625
    }
626

627
    override VarDeclaration createSelectorParameter(FuncDeclaration fd, Scope* sc) const
628
    in
629
    {
630
        assert(fd.selectorParameter is null);
631
    }
632
    do
633
    {
634 0
        if (!fd.selector)
635 0
            return null;
636

637 0
        auto var = new VarDeclaration(fd.loc, Type.tvoidptr, Identifier.anonymous, null);
638 0
        var.storage_class |= STC.parameter;
639 0
        var.dsymbolSemantic(sc);
640 0
        if (!sc.insert(var))
641 0
            assert(false);
642 0
        var.parent = fd;
643

644 0
        return var;
645
    }
646

647
    override void setMetaclass(InterfaceDeclaration interfaceDeclaration, Scope* sc) const
648
    {
649
        static auto newMetaclass(Loc loc, BaseClasses* metaBases)
650
        {
651 0
            return new InterfaceDeclaration(loc, null, metaBases);
652
        }
653

654 0
        .setMetaclass!newMetaclass(interfaceDeclaration, sc);
655
    }
656

657
    override void setMetaclass(ClassDeclaration classDeclaration, Scope* sc) const
658
    {
659
        auto newMetaclass(Loc loc, BaseClasses* metaBases)
660
        {
661 0
            return new ClassDeclaration(loc, null, metaBases, new Dsymbols(), 0);
662
        }
663

664 0
        .setMetaclass!newMetaclass(classDeclaration, sc);
665
    }
666

667
    override ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const
668
    {
669 0
        if (!classDeclaration.objc.metaclass && classDeclaration.objc.isMeta)
670
        {
671 0
            if (classDeclaration.baseClass)
672 0
                return getRuntimeMetaclass(classDeclaration.baseClass);
673
            else
674 0
                return classDeclaration;
675
        }
676
        else
677 0
            return classDeclaration.objc.metaclass;
678
    }
679

680
    override void addSymbols(AttribDeclaration attribDeclaration,
681
        ClassDeclarations* classes, ClassDeclarations* categories) const
682
    {
683 0
        auto symbols = attribDeclaration.include(null);
684

685 0
        if (!symbols)
686 0
            return;
687

688 0
        foreach (symbol; *symbols)
689 0
            symbol.addObjcSymbols(classes, categories);
690
    }
691

692
    override void addSymbols(ClassDeclaration classDeclaration,
693
        ClassDeclarations* classes, ClassDeclarations* categories) const
694
    {
695 0
        with (classDeclaration)
696 0
            if (classKind == ClassKind.objc && !objc.isExtern && !objc.isMeta)
697 0
                classes.push(classDeclaration);
698
    }
699

700
    override void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const
701
    {
702 0
        if (aggregateDeclaration.classKind != ClassKind.objc)
703 0
            return;
704

705
        enum errorMessage = "no property `offsetof` for member `%s` of type " ~
706
            "`%s`";
707

708
        enum supplementalMessage = "`offsetof` is not available for members " ~
709
            "of Objective-C classes. Please use the Objective-C runtime instead";
710

711 0
        expression.error(errorMessage, expression.toChars(),
712
            expression.type.toChars());
713 0
        expression.errorSupplemental(supplementalMessage);
714
    }
715

716
    override void checkTupleof(Expression expression, TypeClass type) const
717
    {
718 0
        if (type.sym.classKind != ClassKind.objc)
719 0
            return;
720

721 0
        expression.error("no property `tupleof` for type `%s`", type.toChars());
722 0
        expression.errorSupplemental("`tupleof` is not available for members " ~
723
            "of Objective-C classes. Please use the Objective-C runtime instead");
724
    }
725

726
    extern(D) private bool isUdaSelector(StructDeclaration sd)
727
    {
728 0
        if (sd.ident != Id.udaSelector || !sd.parent)
729 0
            return false;
730 0
        Module _module = sd.parent.isModule();
731 0
        return _module && _module.isCoreModule(Id.attribute);
732
    }
733
}
734

735
/*
736
 * Creates and sets the metaclass on the given class/interface declaration.
737
 *
738
 * Will only be performed on regular Objective-C classes, not on metaclasses.
739
 *
740
 * Params:
741
 *  newMetaclass = a function that returns the metaclass to set. This should
742
 *      return the same type as `T`.
743
 *  classDeclaration = the class/interface declaration to set the metaclass on
744
 */
745
private void setMetaclass(alias newMetaclass, T)(T classDeclaration, Scope* sc)
746
if (is(T == ClassDeclaration) || is(T == InterfaceDeclaration))
747
{
748
    static if (is(T == ClassDeclaration))
749
        enum errorType = "class";
750
    else
751
        enum errorType = "interface";
752

753 0
    with (classDeclaration)
754
    {
755 0
        if (classKind != ClassKind.objc || objc.isMeta || objc.metaclass)
756 0
            return;
757

758 0
        if (!objc.identifier)
759 0
            objc.identifier = classDeclaration.ident;
760

761 0
        auto metaBases = new BaseClasses();
762

763 0
        foreach (base ; baseclasses.opSlice)
764
        {
765 0
            auto baseCd = base.sym;
766 0
            assert(baseCd);
767

768 0
            if (baseCd.classKind == ClassKind.objc)
769
            {
770 0
                assert(baseCd.objc.metaclass);
771 0
                assert(baseCd.objc.metaclass.objc.isMeta);
772 0
                assert(baseCd.objc.metaclass.type.ty == Tclass);
773

774 0
                auto metaBase = new BaseClass(baseCd.objc.metaclass.type);
775 0
                metaBase.sym = baseCd.objc.metaclass;
776 0
                metaBases.push(metaBase);
777
            }
778
            else
779
            {
780 0
                error("base " ~ errorType ~ " for an Objective-C " ~
781
                      errorType ~ " must be `extern (Objective-C)`");
782
            }
783
        }
784

785 0
        objc.metaclass = newMetaclass(loc, metaBases);
786 0
        objc.metaclass.storage_class |= STC.static_;
787 0
        objc.metaclass.classKind = ClassKind.objc;
788 0
        objc.metaclass.objc.isMeta = true;
789 0
        objc.metaclass.objc.isExtern = objc.isExtern;
790 0
        objc.metaclass.objc.identifier = objc.identifier;
791

792 0
        if (baseClass)
793 0
            objc.metaclass.baseClass = baseClass.objc.metaclass;
794

795 0
        members.push(objc.metaclass);
796 0
        objc.metaclass.addMember(sc, classDeclaration);
797

798 0
        objc.metaclass.dsymbolSemantic(sc);
799
    }
800
}

Read our documentation on viewing source code .

Loading