1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <ObjCUtil.h>
6 #include <Slice/Util.h>
7 #include <IceUtil/Functional.h>
8 #include <IceUtil/StringUtil.h>
9 
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 
13 #ifdef _WIN32
14 #include <direct.h>
15 #endif
16 
17 #ifndef _WIN32
18 #include <unistd.h>
19 #endif
20 
21 using namespace std;
22 using namespace Slice;
23 using namespace IceUtil;
24 using namespace IceUtilInternal;
25 
26 Slice::ObjCGenerator::ModuleMap Slice::ObjCGenerator::_modules;
27 
28 static string
lookupKwd(const string & name,int baseType,bool mangleCasts=false)29 lookupKwd(const string& name, int baseType, bool mangleCasts = false)
30 {
31     //
32     // All lists in this method *must* be kept in case-insensitive
33     // alphabetical order.
34     //
35     static string keywordList[] =
36     {
37         "auto", "BOOL", "break", "bycopy", "byref", "case", "char", "const", "continue",
38         "default", "do", "double", "else", "enum", "extern", "float", "for", "goto",
39         "id", "if", "IMP", "in", "inline", "inout", "int", "long", "nil", "NO", "oneway", "out",
40         "register", "return", "SEL", "self", "short", "signed", "sizeof", "static", "struct", "super", "switch",
41         "typedef", "union", "unsigned", "void", "volatile", "while", "YES"
42     };
43 
44     static string nsObjectList[] =
45     {
46         "autorelease", "class", "classForCoder", "copy", "dealloc", "description", "hash", "init", "isa",
47         "isProxy", "mutableCopy", "release", "retain", "retainCount", "superclass", "zone"
48     };
49     static string nsExceptionList[] =
50     {
51         "callStackReturnAddresses", "name", "raise", "reason", "reserved", "userInfo",
52     };
53 
54     bool found = binary_search(&keywordList[0],
55                                &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
56                                name,
57                                Slice::CICompare());
58     if(!found)
59     {
60         switch(baseType)
61         {
62         case BaseTypeNone:
63             break;
64 
65         case BaseTypeException:
66             found = binary_search(&nsExceptionList[0],
67                                   &nsExceptionList[sizeof(nsExceptionList) / sizeof(*nsExceptionList)],
68                                   name,
69                                   Slice::CICompare());
70             if(found)
71             {
72                 break;
73             }
74             /* FALLTHROUGH */
75 
76         case BaseTypeObject:
77             found = binary_search(&nsObjectList[0],
78                                   &nsObjectList[sizeof(nsObjectList) / sizeof(*nsObjectList)],
79                                   name,
80                                   Slice::CICompare());
81             break;
82         }
83     }
84     if(found || (mangleCasts && (name == "checkedCast" || name == "uncheckedCast")))
85     {
86         return name + "_";
87     }
88     return name;
89 }
90 
91 static string
lookupParamIdKwd(const string & name)92 lookupParamIdKwd(const string& name)
93 {
94     //
95     // All lists in this method *must* be kept in case-insensitive
96     // alphabetical order.
97     //
98     static string keywordList[] =
99     {
100         "nil", "NO", "YES"
101     };
102     if(binary_search(&keywordList[0],
103                      &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
104                      name,
105                      Slice::CICompare()))
106     {
107         return name + "_";
108     }
109     return name;
110 }
111 
112 bool
addModule(const ModulePtr & m,const string & name)113 Slice::ObjCGenerator::addModule(const ModulePtr& m, const string& name)
114 {
115     string scoped = m->scoped();
116     ModuleMap::const_iterator i = _modules.find(scoped);
117     if(i != _modules.end())
118     {
119         if(i->second.name != name)
120         {
121             return false;
122         }
123     }
124     else
125     {
126         ModulePrefix mp;
127         mp.m = m;
128         mp.name = name;
129         _modules[scoped] = mp;
130     }
131     return true;
132 }
133 
134 Slice::ObjCGenerator::ModulePrefix
modulePrefix(const ModulePtr & m)135 Slice::ObjCGenerator::modulePrefix(const ModulePtr& m)
136 {
137     return _modules[m->scoped()];
138 }
139 
140 string
moduleName(const ModulePtr & m)141 Slice::ObjCGenerator::moduleName(const ModulePtr& m)
142 {
143     return _modules[m->scoped()].name;
144 }
145 
146 ModulePtr
findModule(const ContainedPtr & cont,int,bool)147 Slice::ObjCGenerator::findModule(const ContainedPtr& cont, int /*baseTypes*/, bool /*mangleCasts*/)
148 {
149     ModulePtr m = ModulePtr::dynamicCast(cont);
150     ContainerPtr container = cont->container();
151     while(container && !m)
152     {
153         ContainedPtr contained = ContainedPtr::dynamicCast(container);
154         container = contained->container();
155         m = ModulePtr::dynamicCast(contained);
156     }
157     assert(m);
158     return m;
159 }
160 
161 //
162 // If the passed name is a scoped name, return the identical scoped
163 // name, but with all components that are Objective-C keywords
164 // replaced by their prefixed version; otherwise, if the passed name
165 // is not scoped, but an Objective-C keyword, return the prefixed
166 // name; otherwise, check if the name is one of the method names of
167 // baseTypes; if so, returned the prefixed name; otherwise, return the
168 // name unchanged.
169 //
170 string
fixId(const string & name,int baseTypes,bool mangleCasts)171 Slice::ObjCGenerator::fixId(const string& name, int baseTypes, bool mangleCasts)
172 {
173     if(name.empty())
174     {
175         return name;
176     }
177     return lookupKwd(name, baseTypes, mangleCasts);
178 }
179 
180 string
fixId(const ContainedPtr & cont,int baseTypes,bool mangleCasts)181 Slice::ObjCGenerator::fixId(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
182 {
183     return fixId(cont->name(), baseTypes, mangleCasts);
184 }
185 
186 string
fixName(const ContainedPtr & cont,int baseTypes,bool mangleCasts)187 Slice::ObjCGenerator::fixName(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
188 {
189     return moduleName(findModule(cont, baseTypes, mangleCasts)) + cont->name();
190 }
191 
192 string
getParamId(const ContainedPtr & param)193 Slice::ObjCGenerator::getParamId(const ContainedPtr& param)
194 {
195     string n;
196     if(ParamDeclPtr::dynamicCast(param) && param->findMetaData("objc:param:", n))
197     {
198         return lookupParamIdKwd(n.substr(11));
199     }
200     else
201     {
202         return lookupParamIdKwd(param->name());
203     }
204 }
205 
206 string
getParamName(const ContainedPtr & param,bool internal)207 Slice::ObjCGenerator::getParamName(const ContainedPtr& param, bool internal)
208 {
209     if(internal)
210     {
211         return "iceP_" + param->name();
212     }
213     else
214     {
215         return fixId(param->name());
216     }
217 }
218 
219 string
getFactoryMethod(const ContainedPtr & p,bool deprecated)220 Slice::ObjCGenerator::getFactoryMethod(const ContainedPtr& p, bool deprecated)
221 {
222     ClassDefPtr def = ClassDefPtr::dynamicCast(p);
223     if(def && def->declaration()->isLocal())
224     {
225         deprecated = false; // Local classes don't have this issue since they were added after this fix.
226     }
227 
228     //
229     // If deprecated is true, we return uDPConnectionInfo for a class
230     // named UDPConnectionInfo, return udpConnectionInfo otherwise.
231     //
232     string name = fixId(p->name());
233     if(name.empty())
234     {
235         return name;
236     }
237     else if(deprecated || name.size() < 2 || !isupper(*(name.begin() + 1)))
238     {
239         *name.begin() = static_cast<char>(tolower(*name.begin()));
240     }
241     else
242     {
243         for(string::iterator q = name.begin(); q != name.end() && isalpha(*q); ++q)
244         {
245             if(q != name.end() - 1 && isalpha(*(q + 1)) && !isupper(*(q + 1)))
246             {
247                 break;
248             }
249             *q = static_cast<char>(tolower(*q));
250         }
251     }
252     return name;
253 }
254 
255 string
typeToString(const TypePtr & type)256 Slice::ObjCGenerator::typeToString(const TypePtr& type)
257 {
258     if(!type)
259     {
260         return "void";
261     }
262 
263     static const char* builtinTable[] =
264     {
265         "ICEByte",
266         "BOOL",
267         "ICEShort",
268         "ICEInt",
269         "ICELong",
270         "ICEFloat",
271         "ICEDouble",
272         "NSString",
273         "ICEObject",
274         "id<ICEObjectPrx>",
275         "id",            // Dummy--we don't support Slice local Object
276         "ICEObject"
277     };
278 
279     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
280     if(builtin)
281     {
282         return builtinTable[builtin->kind()];
283     }
284 
285     ProxyPtr proxy = ProxyPtr::dynamicCast(type);
286     if(proxy)
287     {
288         string mName = moduleName(findModule(proxy->_class()));
289         return "id<" + mName + (proxy->_class()->name()) + "Prx>";
290     }
291 
292     SequencePtr seq = SequencePtr::dynamicCast(type);
293     if(seq)
294     {
295         return fixName(seq);
296     }
297 
298     DictionaryPtr d = DictionaryPtr::dynamicCast(type);
299     if(d)
300     {
301         return fixName(d);
302     }
303 
304     ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
305     if(cl)
306     {
307         if(cl->isInterface())
308         {
309             if(cl->definition() && cl->definition()->isDelegate())
310             {
311                 return fixName(cl);
312             }
313             else if(cl->isLocal())
314             {
315                 return "id<" + fixName(cl) + ">";
316             }
317             else
318             {
319                 return "ICEObject";
320             }
321         }
322         else if(cl->isLocal())
323         {
324             string name = fixName(cl);
325             return name + "<" + name + ">";
326         }
327     }
328 
329     ContainedPtr contained = ContainedPtr::dynamicCast(type);
330     if(contained)
331     {
332         return fixName(contained);
333     }
334 
335     return "???";
336 }
337 
338 string
inTypeToString(const TypePtr & type,bool optional,bool autoreleasing,bool reference)339 Slice::ObjCGenerator::inTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference)
340 {
341     string s;
342     if(optional)
343     {
344         s = "id";
345     }
346     else
347     {
348         s = typeToString(type);
349         if(mapsToPointerType(type))
350         {
351             s += "*";
352         }
353     }
354     if(autoreleasing && !isValueType(type))
355     {
356         s += " ICE_AUTORELEASING_QUALIFIER";
357     }
358     if(reference)
359     {
360         s += "*";
361     }
362     return s;
363 }
364 
365 string
outTypeToString(const TypePtr & type,bool optional,bool autoreleasing,bool reference)366 Slice::ObjCGenerator::outTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference)
367 {
368     if(!type)
369     {
370         return "void";
371     }
372 
373     string s;
374     if(optional)
375     {
376         s = "id";
377     }
378     else
379     {
380         SequencePtr seq = SequencePtr::dynamicCast(type);
381         DictionaryPtr d = DictionaryPtr::dynamicCast(type);
382         if(isString(type))
383         {
384             s = "NSMutableString";
385         }
386         else if(seq)
387         {
388             string prefix = moduleName(findModule(seq));
389             s = prefix + "Mutable" + seq->name();
390         }
391         else if(d)
392         {
393             string prefix = moduleName(findModule(d));
394             s = prefix + "Mutable" + d->name();
395         }
396         else
397         {
398             s = typeToString(type);
399         }
400         if(mapsToPointerType(type))
401         {
402             s += "*";
403         }
404     }
405     if(autoreleasing && (!isValueType(type) || optional))
406     {
407         s += " ICE_AUTORELEASING_QUALIFIER";
408     }
409     if(reference)
410     {
411         s += "*";
412     }
413     return s;
414 }
415 
416 string
typeToObjCTypeString(const TypePtr & type)417 Slice::ObjCGenerator::typeToObjCTypeString(const TypePtr& type)
418 {
419     ProxyPtr proxy = ProxyPtr::dynamicCast(type);
420     if(proxy)
421     {
422         return moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "Prx";
423     }
424     else
425     {
426         return typeToString(type);
427     }
428 }
429 
430 bool
isValueType(const TypePtr & type)431 Slice::ObjCGenerator::isValueType(const TypePtr& type)
432 {
433     if(!type)
434     {
435         return true;
436     }
437     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
438     if(builtin)
439     {
440         switch(builtin->kind())
441         {
442             case Builtin::KindString:
443             case Builtin::KindObject:
444             case Builtin::KindValue:
445             case Builtin::KindObjectProxy:
446             case Builtin::KindLocalObject:
447             {
448                 return false;
449                 break;
450             }
451             default:
452             {
453                 return true;
454                 break;
455             }
456         }
457     }
458     if(EnumPtr::dynamicCast(type))
459     {
460         return true;
461     }
462     return false;
463 }
464 
465 bool
isString(const TypePtr & type)466 Slice::ObjCGenerator::isString(const TypePtr& type)
467 {
468     if(!type)
469     {
470         return false;
471     }
472     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
473     return builtin && builtin->kind() == Builtin::KindString;
474 }
475 bool
isClass(const TypePtr & type)476 Slice::ObjCGenerator::isClass(const TypePtr& type)
477 {
478     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
479     if(builtin)
480     {
481         return builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue;
482     }
483     return ClassDeclPtr::dynamicCast(type);
484 }
485 
486 bool
mapsToPointerType(const TypePtr & type)487 Slice::ObjCGenerator::mapsToPointerType(const TypePtr& type)
488 {
489     if(isValueType(type))
490     {
491         return false;
492     }
493     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
494     if(builtin)
495     {
496        return builtin->kind() != Builtin::KindObjectProxy && builtin->kind() != Builtin::KindLocalObject;
497     }
498     ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
499     if(cl && cl->isInterface())
500     {
501         if(cl->isLocal() || (cl->definition() && cl->definition()->isDelegate()))
502         {
503             return false;
504         }
505         else
506         {
507             return true;
508         }
509     }
510     return !ProxyPtr::dynamicCast(type);
511 }
512 
513 string
getBuiltinName(const BuiltinPtr & builtin)514 Slice::ObjCGenerator::getBuiltinName(const BuiltinPtr& builtin)
515 {
516     switch(builtin->kind())
517     {
518         case Builtin::KindByte:
519         {
520             return "Byte";
521         }
522         case Builtin::KindBool:
523         {
524             return "Bool";
525         }
526         case Builtin::KindShort:
527         {
528             return "Short";
529         }
530         case Builtin::KindInt:
531         {
532             return "Int";
533         }
534         case Builtin::KindLong:
535         {
536             return "Long";
537         }
538         case Builtin::KindFloat:
539         {
540             return "Float";
541         }
542         case Builtin::KindDouble:
543         {
544             return "Double";
545         }
546         case Builtin::KindString:
547         {
548             return "String";
549         }
550         case Builtin::KindObject:
551         case Builtin::KindValue:
552         {
553             return "Object";
554         }
555         case Builtin::KindObjectProxy:
556         {
557             return "Proxy";
558         }
559         default:
560         {
561             assert(false);
562         }
563     }
564     return "NO__SUCH__TYPE";
565 }
566 
567 string
getOptionalHelperGetter(const TypePtr & type)568 Slice::ObjCGenerator::getOptionalHelperGetter(const TypePtr& type)
569 {
570     if(isValueType(type))
571     {
572         BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
573         if(builtin)
574         {
575             return "get" + getBuiltinName(builtin);
576         }
577         if(EnumPtr::dynamicCast(type))
578         {
579             return "getInt";
580         }
581     }
582     return "get";
583 }
584 
585 //
586 // Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
587 //
588 StringList
splitScopedName(const string & scoped)589 Slice::ObjCGenerator::splitScopedName(const string& scoped)
590 {
591     assert(scoped[0] == ':');
592     StringList ids;
593     string::size_type next = 0;
594     string::size_type pos;
595     while((pos = scoped.find("::", next)) != string::npos)
596     {
597         pos += 2;
598         if(pos != scoped.size())
599         {
600             string::size_type endpos = scoped.find("::", pos);
601             if(endpos != string::npos)
602             {
603                 ids.push_back(scoped.substr(pos, endpos - pos));
604             }
605         }
606         next = pos;
607     }
608     if(next != scoped.size())
609     {
610         ids.push_back(scoped.substr(next));
611     }
612     else
613     {
614         ids.push_back("");
615     }
616 
617     return ids;
618 }
619 
620 string
getOptionalFormat(const TypePtr & type)621 Slice::ObjCGenerator::getOptionalFormat(const TypePtr& type)
622 {
623     BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
624     if(bp)
625     {
626         switch(bp->kind())
627         {
628         case Builtin::KindByte:
629         case Builtin::KindBool:
630         {
631             return "ICEOptionalFormatF1";
632         }
633         case Builtin::KindShort:
634         {
635             return "ICEOptionalFormatF2";
636         }
637         case Builtin::KindInt:
638         case Builtin::KindFloat:
639         {
640             return "ICEOptionalFormatF4";
641         }
642         case Builtin::KindLong:
643         case Builtin::KindDouble:
644         {
645             return "ICEOptionalFormatF8";
646         }
647         case Builtin::KindString:
648         {
649             return "ICEOptionalFormatVSize";
650         }
651         case Builtin::KindObject:
652         case Builtin::KindValue:
653         {
654             return "ICEOptionalFormatClass";
655         }
656         case Builtin::KindObjectProxy:
657         {
658             return "ICEOptionalFormatFSize";
659         }
660         case Builtin::KindLocalObject:
661         {
662             assert(false);
663             break;
664         }
665         }
666     }
667 
668     if(EnumPtr::dynamicCast(type))
669     {
670         return "ICEOptionalFormatSize";
671     }
672 
673     SequencePtr seq = SequencePtr::dynamicCast(type);
674     if(seq)
675     {
676         return seq->type()->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
677     }
678 
679     DictionaryPtr d = DictionaryPtr::dynamicCast(type);
680     if(d)
681     {
682         return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ?
683             "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
684     }
685 
686     StructPtr st = StructPtr::dynamicCast(type);
687     if(st)
688     {
689         return st->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
690     }
691 
692     if(ProxyPtr::dynamicCast(type))
693     {
694         return "ICEOptionalFormatFSize";
695     }
696 
697     ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
698     assert(cl);
699     return "ICEOptionalFormatClass";
700 }
701 
702 void
writeMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,bool marshal,bool autoreleased) const703 Slice::ObjCGenerator::writeMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
704                                                 bool marshal, bool autoreleased) const
705 {
706     string stream = marshal ? "ostr" : "istr";
707     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
708 
709     if(builtin)
710     {
711         string name;
712         if(builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)
713         {
714             if(marshal)
715             {
716                 out << nl << "[" << stream << " writeValue:" << param << "];";
717             }
718             else
719             {
720                 if(autoreleased)
721                 {
722                     out << nl << "[" << stream << " readValue:&" << param << "];";
723                 }
724                 else
725                 {
726                     out << nl << "[" << stream << " newValue:&" << param << "];";
727                 }
728             }
729         }
730         else if(builtin->kind() == Builtin::KindObjectProxy)
731         {
732             if(marshal)
733             {
734                 out << nl << "[" << stream << " writeProxy:" << param << "];";
735             }
736             else
737             {
738                 if(autoreleased)
739                 {
740                     out << nl << param << " = [" << stream << " readProxy:[ICEObjectPrx class]];";
741                 }
742                 else
743                 {
744                     out << nl << param << " = [" << stream << " newProxy:[ICEObjectPrx class]];";
745                 }
746             }
747         }
748         else
749         {
750             if(marshal)
751             {
752                 out << nl << "[" << stream << " write" << getBuiltinName(builtin) << ":" << param << "];";
753             }
754             else
755             {
756                 if(autoreleased || isValueType(builtin))
757                 {
758                     out << nl << param << " = [" << stream << " read" << getBuiltinName(builtin) << "];";
759                 }
760                 else
761                 {
762                     out << nl << param << " = [" << stream << " new" << getBuiltinName(builtin) << "];";
763                 }
764             }
765         }
766         return;
767     }
768 
769     ProxyPtr prx = ProxyPtr::dynamicCast(type);
770     if(prx)
771     {
772         if(marshal)
773         {
774             out << nl << "[" << stream << " writeProxy:(id<ICEObjectPrx>)" << param << "];";
775         }
776         else
777         {
778             string name = moduleName(findModule(prx->_class())) + prx->_class()->name() + "Prx";
779             out << nl << param << " = (id<" << name << ">)[" << stream;
780             if(autoreleased)
781             {
782                 out << " readProxy:";
783             }
784             else
785             {
786                 out << " newProxy:";
787             }
788             //
789             // We use objc_getClass to get the proxy class instead of [name class]. This is to avoid
790             // a warning if the proxy is forward declared.
791             //
792             if(prx->_class()->definition())
793             {
794                 out << "[" << name << " class]];";
795             }
796             else
797             {
798                 out << "objc_getClass(\"" << name << "\")];";
799             }
800         }
801         return;
802     }
803 
804     ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
805     if(cl)
806     {
807         if(marshal)
808         {
809             // Cast avoids warning for forward-declared classes.
810             out << nl << "[" << stream << " writeValue:(ICEObject*)" << param << "];";
811         }
812         else
813         {
814             if(autoreleased)
815             {
816                 out << nl << "[" << stream << " " << "readValue:(ICEObject**)&" << param;
817             }
818             else
819             {
820                 out << nl << "[" << stream << " " << "newValue:(ICEObject**)&" << param;
821             }
822 
823             if(cl->isInterface())
824             {
825                 out << "];";
826             }
827             else
828             {
829                 string name = moduleName(findModule(cl)) + cl->name();
830                 if(cl->definition())
831                 {
832                     out << " expectedType:[" << name << " class]];";
833                 }
834                 else
835                 {
836                     out << " expectedType:objc_getClass(\"" << name << "\")];";
837                 }
838             }
839         }
840         return;
841     }
842 
843     EnumPtr en = EnumPtr::dynamicCast(type);
844     if(en)
845     {
846         if(marshal)
847         {
848             out << nl << "[" << stream << " writeEnumerator:" << param << " min:" << en->minValue()
849                 << " max:" << en->maxValue() << "];";
850         }
851         else
852         {
853             out << nl << param << " = " << "[" << stream << " readEnumerator:" << en->minValue()
854                 << " max:" << en->maxValue() << "];";
855         }
856         return;
857     }
858 
859     ContainedPtr c = ContainedPtr::dynamicCast(type);
860     assert(c);
861     string name = moduleName(findModule(c)) + c->name() + "Helper";
862     if(marshal)
863     {
864         out << nl << "[" + name << " write:" << param << " stream:" << stream << "];";
865     }
866     else
867     {
868         if(StructPtr::dynamicCast(type))
869         {
870             if(autoreleased)
871             {
872                 out << nl << "[" << name << " read:" << stream << " value:&" << param << "];";
873             }
874             else
875             {
876                 out << nl << "[" << name << " readRetained:" << stream << " value:&" << param << "];";
877             }
878         }
879         else
880         {
881             if(autoreleased)
882             {
883                 out << nl << param << " = [" << name << " read:" << stream << "];";
884             }
885             else
886             {
887                 out << nl << param << " = [" << name << " readRetained:" << stream << "];";
888             }
889         }
890     }
891 }
892 
893 void
writeOptMemberMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,bool marshal) const894 Slice::ObjCGenerator::writeOptMemberMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
895                                                          bool marshal) const
896 {
897     string stream = marshal ? "ostr" : "istr";
898     string optionalHelper;
899     string helper;
900 
901     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
902     if(builtin)
903     {
904         if(builtin->kind() == Builtin::KindObjectProxy)
905         {
906             optionalHelper = "ICEVarLengthOptionalHelper";
907             helper = "[ICEProxyHelper class]";
908         }
909         else
910         {
911             writeMarshalUnmarshalCode(out, type, param, marshal, false);
912             return;
913         }
914     }
915 
916     ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
917     if(cl)
918     {
919         writeMarshalUnmarshalCode(out, type, param, marshal, false);
920         return;
921     }
922 
923     EnumPtr en = EnumPtr::dynamicCast(type);
924     if(en)
925     {
926         writeMarshalUnmarshalCode(out, type, param, marshal, false);
927         return;
928     }
929 
930     ProxyPtr prx = ProxyPtr::dynamicCast(type);
931     if(prx)
932     {
933         optionalHelper = "ICEVarLengthOptionalHelper";
934         helper = "objc_getClass(\"" + moduleName(findModule(prx->_class())) + prx->_class()->name() + "PrxHelper\")";
935     }
936 
937     StructPtr st = StructPtr::dynamicCast(type);
938     if(st)
939     {
940         if(st->isVariableLength())
941         {
942             optionalHelper = "ICEVarLengthOptionalHelper";
943         }
944         else
945         {
946             optionalHelper = "ICEFixedLengthOptionalHelper";
947         }
948         helper = "[" + typeToString(st) + "Helper class]";
949     }
950 
951     SequencePtr seq = SequencePtr::dynamicCast(type);
952     if(seq)
953     {
954         TypePtr element = seq->type();
955         if(element->isVariableLength())
956         {
957             optionalHelper = "ICEVarLengthOptionalHelper";
958         }
959         else if(element->minWireSize() == 1)
960         {
961             writeMarshalUnmarshalCode(out, type, param, marshal, false);
962             return;
963         }
964         else
965         {
966             optionalHelper = "ICEFixedSequenceOptionalHelper";
967         }
968         helper = "[" + moduleName(findModule(seq)) + seq->name() + "Helper class]";
969     }
970 
971     DictionaryPtr d = DictionaryPtr::dynamicCast(type);
972     if(d)
973     {
974         if(d->keyType()->isVariableLength() || d->valueType()->isVariableLength())
975         {
976             optionalHelper = "ICEVarLengthOptionalHelper";
977         }
978         else
979         {
980             optionalHelper = "ICEFixedDictionaryOptionalHelper";
981         }
982         helper = "[" + moduleName(findModule(d)) + d->name() + "Helper class]";
983     }
984 
985     out << nl;
986     if(marshal)
987     {
988         out << "[" << optionalHelper  << " write:" << param << " stream:" << stream << " helper:" << helper << "];";
989     }
990     else
991     {
992         out << param << " = [" << optionalHelper << " readRetained:" << stream << " helper:" << helper << "];";
993     }
994 
995 }
996 
997 void
writeOptParamMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & param,int tag,bool marshal) const998 Slice::ObjCGenerator::writeOptParamMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
999                                                         int tag, bool marshal) const
1000 {
1001     string helper;
1002     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
1003     ProxyPtr proxy = ProxyPtr::dynamicCast(type);
1004     if(builtin)
1005     {
1006         helper = "ICE" + getBuiltinName(builtin) + "Helper";
1007     }
1008     else if(proxy)
1009     {
1010         helper = moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "PrxHelper";
1011     }
1012     else
1013     {
1014         helper = typeToString(type) + "Helper";
1015     }
1016 
1017     ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
1018     if(cl)
1019     {
1020         out << nl;
1021         if(marshal)
1022         {
1023             out << "[" << helper << " writeOptional:" << param << " stream:ostr tag:" << tag << "];";
1024         }
1025         else
1026         {
1027             out << "[" << helper << " readOptional:&" << param << " stream:istr tag:" << tag << "];";
1028         }
1029         return;
1030     }
1031 
1032     out << nl;
1033     if(marshal)
1034     {
1035         out << "[" << helper << " writeOptional:" << param << " stream:ostr tag:" << tag << "];";
1036     }
1037     else
1038     {
1039         out << param << " = [" << helper << " readOptional:istr tag:" << tag << "];";
1040     }
1041 }
1042 
1043 void
validateMetaData(const UnitPtr & u)1044 Slice::ObjCGenerator::validateMetaData(const UnitPtr& u)
1045 {
1046     MetaDataVisitor visitor;
1047     u->visit(&visitor, true);
1048 }
1049 
1050 const string Slice::ObjCGenerator::MetaDataVisitor::_objcPrefix = "objc:";
1051 const string Slice::ObjCGenerator::MetaDataVisitor::_msg = "ignoring invalid metadata";
1052 
1053 bool
visitUnitStart(const UnitPtr & p)1054 Slice::ObjCGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p)
1055 {
1056     //
1057     // Validate global metadata in the top-level file and all included files.
1058     //
1059     StringList files = p->allFiles();
1060 
1061     for(StringList::iterator q = files.begin(); q != files.end(); ++q)
1062     {
1063         string file = *q;
1064         DefinitionContextPtr dc = p->findDefinitionContext(file);
1065         assert(dc);
1066         StringList globalMetaData = dc->getMetaData();
1067         int headerDir = 0;
1068         int dllExport = 0;
1069         for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end();)
1070         {
1071             string s = *r++;
1072 
1073             if(s.find(_objcPrefix) == 0)
1074             {
1075                 static const string objcHeaderDirPrefix = "objc:header-dir:";
1076                 static const string objcDllExportPrefix = "objc:dll-export:";
1077                 if(s.find(objcHeaderDirPrefix) == 0 && s.size() > objcHeaderDirPrefix.size())
1078                 {
1079                     headerDir++;
1080                     if(headerDir > 1)
1081                     {
1082                         ostringstream ostr;
1083                         ostr << "ignoring invalid global metadata `" << s
1084                              << "': directive can appear only once per file";
1085                         dc->warning(InvalidMetaData, file, -1, ostr.str());
1086                         globalMetaData.remove(s);
1087                     }
1088                     continue;
1089                 }
1090                 else if(s.find(objcDllExportPrefix) == 0 && s.size() > objcDllExportPrefix.size())
1091                 {
1092                     dllExport++;
1093                     if(dllExport > 1)
1094                     {
1095                         ostringstream ostr;
1096                         ostr << "ignoring invalid global metadata `" << s
1097                              << "': directive can appear only once per file";
1098                         dc->warning(InvalidMetaData, file, -1, ostr.str());
1099                         globalMetaData.remove(s);
1100                     }
1101                     continue;
1102                 }
1103 
1104                 ostringstream ostr;
1105                 ostr << "ignoring invalid global metadata `" << s << "'";
1106                 dc->warning(InvalidMetaData, file, -1, ostr.str());
1107 
1108                 globalMetaData.remove(s);
1109             }
1110         }
1111         dc->setMetaData(globalMetaData);
1112     }
1113 
1114     return true;
1115 }
1116 
1117 bool
visitModuleStart(const ModulePtr & p)1118 Slice::ObjCGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
1119 {
1120     validate(p);
1121     return true;
1122 }
1123 
1124 void
visitModuleEnd(const ModulePtr &)1125 Slice::ObjCGenerator::MetaDataVisitor::visitModuleEnd(const ModulePtr&)
1126 {
1127 }
1128 
1129 void
visitClassDecl(const ClassDeclPtr & p)1130 Slice::ObjCGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
1131 {
1132     validate(p);
1133 }
1134 
1135 bool
visitClassDefStart(const ClassDefPtr & p)1136 Slice::ObjCGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
1137 {
1138     validate(p);
1139     return true;
1140 }
1141 
1142 void
visitClassDefEnd(const ClassDefPtr &)1143 Slice::ObjCGenerator::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
1144 {
1145 }
1146 
1147 bool
visitExceptionStart(const ExceptionPtr & p)1148 Slice::ObjCGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
1149 {
1150     validate(p);
1151     return true;
1152 }
1153 
1154 void
visitExceptionEnd(const ExceptionPtr &)1155 Slice::ObjCGenerator::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
1156 {
1157 }
1158 
1159 bool
visitStructStart(const StructPtr & p)1160 Slice::ObjCGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p)
1161 {
1162     validate(p);
1163     return true;
1164 }
1165 
1166 void
visitStructEnd(const StructPtr &)1167 Slice::ObjCGenerator::MetaDataVisitor::visitStructEnd(const StructPtr&)
1168 {
1169 }
1170 
1171 void
visitOperation(const OperationPtr & p)1172 Slice::ObjCGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p)
1173 {
1174     validate(p);
1175 }
1176 
1177 void
visitParamDecl(const ParamDeclPtr & p)1178 Slice::ObjCGenerator::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p)
1179 {
1180     validate(p);
1181 }
1182 
1183 void
visitDataMember(const DataMemberPtr & p)1184 Slice::ObjCGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p)
1185 {
1186     validate(p);
1187 }
1188 
1189 void
visitSequence(const SequencePtr & p)1190 Slice::ObjCGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p)
1191 {
1192     validate(p);
1193 }
1194 
1195 void
visitDictionary(const DictionaryPtr & p)1196 Slice::ObjCGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p)
1197 {
1198     validate(p);
1199 }
1200 
1201 void
visitEnum(const EnumPtr & p)1202 Slice::ObjCGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p)
1203 {
1204     validate(p);
1205 }
1206 
1207 void
visitConst(const ConstPtr & p)1208 Slice::ObjCGenerator::MetaDataVisitor::visitConst(const ConstPtr& p)
1209 {
1210     validate(p);
1211 }
1212 
1213 void
validate(const ContainedPtr & cont)1214 Slice::ObjCGenerator::MetaDataVisitor::validate(const ContainedPtr& cont)
1215 {
1216     ModulePtr m = ModulePtr::dynamicCast(cont);
1217     if(m)
1218     {
1219         bool error = false;
1220         bool foundPrefix = false;
1221 
1222         StringList meta = getMetaData(m);
1223         for(StringList::iterator p = meta.begin(); p != meta.end();)
1224         {
1225             string s = *p++;
1226             const string prefix = "objc:prefix:";
1227             string name;
1228             if(s.find(prefix) == 0)
1229             {
1230                 foundPrefix = true;
1231                 name = trim(s.substr(prefix.size()));
1232                 if(name.empty())
1233                 {
1234                     m->definitionContext()->warning(InvalidMetaData, m->definitionContext()->filename(),
1235                                                     m->line(), _msg + " `" + s + "'");
1236                     meta.remove(s);
1237                     error = true;
1238                 }
1239                 else
1240                 {
1241                     if(!addModule(m, name))
1242                     {
1243                         modulePrefixError(m, s);
1244                     }
1245                 }
1246             }
1247             else
1248             {
1249                 m->definitionContext()->warning(InvalidMetaData, m->definitionContext()->filename(),
1250                                                 m->line(), _msg + " `" + s + "'");
1251                 meta.remove(s);
1252                 error = true;
1253             }
1254         }
1255         setMetaData(m, meta);
1256 
1257         if(!error && !foundPrefix)
1258         {
1259             StringList names = splitScopedName(m->scoped());
1260             string name;
1261             for(StringList::const_iterator i = names.begin(); i != names.end(); ++i)
1262             {
1263                 name += *i;
1264             }
1265             if(!addModule(m, name))
1266             {
1267                 modulePrefixError(m, "");
1268             }
1269         }
1270     }
1271 
1272     EnumPtr en = EnumPtr::dynamicCast(cont);
1273     if(en)
1274     {
1275         StringList meta = getMetaData(en);
1276         for(StringList::iterator p = meta.begin(); p != meta.end();)
1277         {
1278             string s = *p;
1279             if(s != "objc:scoped")
1280             {
1281                 en->definitionContext()->warning(InvalidMetaData, en->definitionContext()->filename(),
1282                                                 en->line(), _msg + " `" + s + "'");
1283                 meta.erase(p++);
1284             }
1285             else
1286             {
1287                 ++p;
1288             }
1289         }
1290         setMetaData(en, meta);
1291     }
1292 }
1293 
1294 StringList
getMetaData(const ContainedPtr & cont)1295 Slice::ObjCGenerator::MetaDataVisitor::getMetaData(const ContainedPtr& cont)
1296 {
1297     StringList localMetaData = cont->getMetaData();
1298     for(StringList::const_iterator p = localMetaData.begin(); p != localMetaData.end();)
1299     {
1300         string s = *p++;
1301         if(s.find(_objcPrefix) != 0)
1302         {
1303             localMetaData.remove(s);
1304         }
1305     }
1306     return localMetaData;
1307 }
1308 
1309 void
setMetaData(const ContainedPtr & cont,const StringList & metadata)1310 Slice::ObjCGenerator::MetaDataVisitor::setMetaData(const ContainedPtr& cont, const StringList& metadata)
1311 {
1312     StringList localMetaData = cont->getMetaData();
1313     for(StringList::const_iterator p = localMetaData.begin(); p != localMetaData.end();)
1314     {
1315         string s = *p++;
1316         if(s.find(_objcPrefix) == 0)
1317         {
1318             localMetaData.remove(s);
1319         }
1320     }
1321     localMetaData.insert(localMetaData.end(), metadata.begin(), metadata.end());
1322     cont->setMetaData(localMetaData);
1323 }
1324 
1325 void
modulePrefixError(const ModulePtr & m,const string & metadata)1326 Slice::ObjCGenerator::MetaDataVisitor::modulePrefixError(const ModulePtr& m, const string& metadata)
1327 {
1328     string file = m->definitionContext()->filename();
1329     string line = m->line();
1330     ModulePrefix mp = modulePrefix(m);
1331     string old_file = mp.m->definitionContext()->filename();
1332     string old_line = mp.m->line();
1333     ostringstream os;
1334     if(!metadata.empty())
1335     {
1336         os << _msg << " `" << metadata << "': ";
1337     }
1338     os << "inconsistent module prefix previously defined ";
1339     if(old_file != file)
1340     {
1341          os << "in " << old_file << ":";
1342     }
1343     else
1344     {
1345         os << "at line ";
1346     }
1347     os << line;
1348     os << " as `" << mp.name << "'" << endl;
1349     m->definitionContext()->warning(All, file, line, os.str());
1350 }
1351