1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include "Gen.h"
6 #include <Slice/Util.h>
7 #include <Slice/CPlusPlusUtil.h>
8 #include <IceUtil/Functional.h>
9 #include <IceUtil/Iterator.h>
10 #include <IceUtil/StringUtil.h>
11 #include <Slice/Checksum.h>
12 #include <Slice/FileTracker.h>
13 #include <IceUtil/FileUtil.h>
14 
15 #include <limits>
16 #include <string.h>
17 
18 using namespace std;
19 using namespace Slice;
20 using namespace IceUtil;
21 using namespace IceUtilInternal;
22 
23 namespace
24 {
25 
26 bool
isConstexprType(const TypePtr & type)27 isConstexprType(const TypePtr& type)
28 {
29     BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
30     if(bp)
31     {
32         switch(bp->kind())
33         {
34             case Builtin::KindByte:
35             case Builtin::KindBool:
36             case Builtin::KindShort:
37             case Builtin::KindInt:
38             case Builtin::KindLong:
39             case Builtin::KindFloat:
40             case Builtin::KindDouble:
41             case Builtin::KindValue:
42             case Builtin::KindObject:
43             case Builtin::KindObjectProxy:
44             {
45                 return true;
46             }
47             default:
48             {
49                 return false;
50             }
51         }
52     }
53     else if(EnumPtr::dynamicCast(type) || ProxyPtr::dynamicCast(type) || ClassDeclPtr::dynamicCast(type))
54     {
55         return true;
56     }
57     else
58     {
59         StructPtr s = StructPtr::dynamicCast(type);
60         if(s)
61         {
62             DataMemberList members = s->dataMembers();
63             for(DataMemberList::const_iterator i = members.begin(); i != members.end(); ++i)
64             {
65                 if(!isConstexprType((*i)->type()))
66                 {
67                     return false;
68                 }
69             }
70             return true;
71         }
72         return false;
73     }
74 }
75 
76 string
getDeprecateSymbol(const ContainedPtr & p1,const ContainedPtr & p2)77 getDeprecateSymbol(const ContainedPtr& p1, const ContainedPtr& p2)
78 {
79     string deprecateMetadata, deprecateSymbol;
80     if(p1->findMetaData("deprecate", deprecateMetadata) ||
81        (p2 != 0 && p2->findMetaData("deprecate", deprecateMetadata)))
82     {
83         string msg = "is deprecated";
84         if(deprecateMetadata.find("deprecate:") == 0 && deprecateMetadata.size() > 10)
85         {
86             msg = deprecateMetadata.substr(10);
87         }
88         deprecateSymbol = "ICE_DEPRECATED_API(\"" + msg + "\") ";
89     }
90     return deprecateSymbol;
91 }
92 
93 void
writeConstantValue(IceUtilInternal::Output & out,const TypePtr & type,const SyntaxTreeBasePtr & valueType,const string & value,int typeContext,const StringList & metaData,const string & scope)94 writeConstantValue(IceUtilInternal::Output& out, const TypePtr& type, const SyntaxTreeBasePtr& valueType,
95                    const string& value, int typeContext, const StringList& metaData, const string& scope)
96 {
97     ConstPtr constant = ConstPtr::dynamicCast(valueType);
98     if(constant)
99     {
100         out << getUnqualified(fixKwd(constant->scoped()), scope);
101     }
102     else
103     {
104         bool cpp11 = (typeContext & TypeContextCpp11) == TypeContextCpp11;
105         BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
106         if(bp && bp->kind() == Builtin::KindString)
107         {
108             bool wide = (typeContext & TypeContextUseWstring) || findMetaData(metaData) == "wstring";
109             if(wide || cpp11)
110             {
111                 out << (wide ? "L\"" : "u8\"");
112                 out << toStringLiteral(value, "\a\b\f\n\r\t\v", "?", UCN, cpp11 ? 0 : 0x9F + 1);
113                 out << "\"";
114             }
115             else // C++98 narrow strings
116             {
117                 out << "\"" << toStringLiteral(value, "\a\b\f\n\r\t\v", "?", Octal, 0) << "\"";
118             }
119         }
120         else if(bp && bp->kind() == Builtin::KindLong)
121         {
122             if(cpp11)
123             {
124                 out << value << "LL";
125             }
126             else
127             {
128                 out << "ICE_INT64(" << value << ")";
129             }
130         }
131         else if(bp && bp->kind() == Builtin::KindFloat)
132         {
133             out << value;
134             if(value.find(".") == string::npos)
135             {
136                 out << ".0";
137             }
138             out << "F";
139         }
140         else
141         {
142             EnumPtr ep = EnumPtr::dynamicCast(type);
143             if(ep && valueType)
144             {
145                 EnumeratorPtr enumerator = EnumeratorPtr::dynamicCast(valueType);
146                 assert(enumerator);
147 
148                 bool unscoped = (cpp11 && findMetaData(ep->getMetaData(), TypeContextCpp11) == "%unscoped") ||
149                     (!cpp11 && findMetaData(ep->getMetaData()) != "%scoped");
150 
151                 if(unscoped)
152                 {
153                     out << getUnqualified(fixKwd(ep->scope() + enumerator->name()), scope);
154                 }
155                 else
156                 {
157                     if(cpp11)
158                     {
159                         out << getUnqualified(fixKwd(enumerator->scoped()), scope);
160                     }
161                     else
162                     {
163                         out << getUnqualified(fixKwd(ep->scope() + ep->name() + enumerator->name()), scope);
164                     }
165                 }
166             }
167             else if(!ep)
168             {
169                 out << value;
170             }
171         }
172     }
173 }
174 
175 string
toDllClassExport(const string & dllExport)176 toDllClassExport(const string& dllExport)
177 {
178     if(!dllExport.empty())
179     {
180         return "ICE_CLASS(" + dllExport.substr(0, dllExport.size() - 1) + ") ";
181     }
182     else
183     {
184         return "";
185     }
186 }
187 
188 string
toDllMemberExport(const string & dllExport)189 toDllMemberExport(const string& dllExport)
190 {
191     if(!dllExport.empty())
192     {
193         return "ICE_MEMBER(" + dllExport.substr(0, dllExport.size() - 1) + ") ";
194     }
195     else
196     {
197         return "";
198     }
199 }
200 
201 void
writeDataMemberInitializers(IceUtilInternal::Output & C,const DataMemberList & members,int typeContext)202 writeDataMemberInitializers(IceUtilInternal::Output& C, const DataMemberList& members, int typeContext)
203 {
204     bool first = true;
205     for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p)
206     {
207         ContainedPtr contained = ContainedPtr::dynamicCast((*p)->container());
208         string scope = contained->scope();
209         if((*p)->defaultValueType())
210         {
211             string memberName = fixKwd((*p)->name());
212 
213             if(first)
214             {
215                 first = false;
216             }
217             else
218             {
219                 C << ',';
220             }
221             C << nl << memberName << '(';
222             writeConstantValue(C, (*p)->type(), (*p)->defaultValueType(), (*p)->defaultValue(), typeContext,
223                                (*p)->getMetaData(), scope);
224             C << ')';
225         }
226     }
227 }
228 
229 void
writeInParamsLambda(IceUtilInternal::Output & C,const OperationPtr & p,const ParamDeclList & inParams,const string & scope)230 writeInParamsLambda(IceUtilInternal::Output& C, const OperationPtr& p, const ParamDeclList& inParams,
231                     const string& scope)
232 {
233     if(inParams.empty())
234     {
235         C << "nullptr";
236     }
237     else
238     {
239         C << "[&](" << getUnqualified("::Ice::OutputStream*", scope) << " ostr)";
240         C << sb;
241         writeMarshalCode(C, inParams, 0, true, TypeContextInParam | TypeContextCpp11);
242         if(p->sendsClasses(false))
243         {
244             C << nl << "ostr->writePendingValues();";
245         }
246         C << eb;
247     }
248 }
249 
250 void
throwUserExceptionLambda(IceUtilInternal::Output & C,ExceptionList throws,const string & scope)251 throwUserExceptionLambda(IceUtilInternal::Output& C, ExceptionList throws, const string& scope)
252 {
253     if(throws.empty())
254     {
255         C << "nullptr";
256     }
257     else
258     {
259         throws.sort();
260         throws.unique();
261 
262         //
263         // Arrange exceptions into most-derived to least-derived order. If we don't
264         // do this, a base exception handler can appear before a derived exception
265         // handler, causing compiler warnings and resulting in the base exception
266         // being marshaled instead of the derived exception.
267         //
268         throws.sort(Slice::DerivedToBaseCompare());
269 
270         C << "[](const " << getUnqualified("::Ice::UserException&", scope) << " ex)";
271         C << sb;
272         C << nl << "try";
273         C << sb;
274         C << nl << "ex.ice_throw();";
275         C << eb;
276         //
277         // Generate a catch block for each legal user exception.
278         //
279         for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i)
280         {
281             string scoped = (*i)->scoped();
282             C << nl << "catch(const " << getUnqualified(fixKwd((*i)->scoped()), scope) << "&)";
283             C << sb;
284             C << nl << "throw;";
285             C << eb;
286         }
287         C << nl << "catch(const " << getUnqualified("::Ice::UserException&", scope) << ")";
288         C << sb;
289         C << eb;
290         C << eb;
291     }
292 }
293 
294 string
resultStructName(const string & name,const string & scope="",bool marshaledResult=false)295 resultStructName(const string& name, const string& scope = "", bool marshaledResult = false)
296 {
297     assert(!name.empty());
298     string stName = IceUtilInternal::toUpper(name.substr(0, 1)) + name.substr(1);
299     stName += marshaledResult ? "MarshaledResult" : "Result";
300     if(!scope.empty())
301     {
302         stName = scope + "::" + stName;
303     }
304     return stName;
305 }
306 
307 string
condMove(bool moveIt,const string & str)308 condMove(bool moveIt, const string& str)
309 {
310     return moveIt ? string("::std::move(") + str + ")" : str;
311 }
312 
313 string
escapeParam(const ParamDeclList & params,const string & name)314 escapeParam(const ParamDeclList& params, const string& name)
315 {
316     string r = name;
317     for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p)
318     {
319         if(fixKwd((*p)->name()) == name)
320         {
321             r = name + "_";
322             break;
323         }
324     }
325     return r;
326 }
327 
328 void
writeDocLines(Output & out,const StringList & lines,bool commentFirst,const string & space=" ")329 writeDocLines(Output& out, const StringList& lines, bool commentFirst, const string& space = " ")
330 {
331     StringList l = lines;
332     if(!commentFirst)
333     {
334         out << l.front();
335         l.pop_front();
336     }
337     for(StringList::const_iterator i = l.begin(); i != l.end(); ++i)
338     {
339         out << nl << " *";
340         if(!i->empty())
341         {
342             out << space << *i;
343         }
344     }
345 }
346 
347 void
writeSeeAlso(Output & out,const StringList & lines,const string & space=" ")348 writeSeeAlso(Output& out, const StringList& lines, const string& space = " ")
349 {
350     for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i)
351     {
352         out << nl << " *";
353         if(!i->empty())
354         {
355             out << space << "@see " << *i;
356         }
357     }
358 }
359 
360 string
getDocSentence(const StringList & lines)361 getDocSentence(const StringList& lines)
362 {
363     //
364     // Extract the first sentence.
365     //
366     ostringstream ostr;
367     for(StringList::const_iterator i = lines.begin(); i != lines.end(); ++i)
368     {
369         const string ws = " \t";
370 
371         if(i->empty())
372         {
373             break;
374         }
375         if(i != lines.begin() && i->find_first_not_of(ws) == 0)
376         {
377             ostr << " ";
378         }
379         string::size_type pos = i->find('.');
380         if(pos == string::npos)
381         {
382             ostr << *i;
383         }
384         else if(pos == i->size() - 1)
385         {
386             ostr << *i;
387             break;
388         }
389         else
390         {
391             //
392             // Assume a period followed by whitespace indicates the end of the sentence.
393             //
394             while(pos != string::npos)
395             {
396                 if(ws.find((*i)[pos + 1]) != string::npos)
397                 {
398                     break;
399                 }
400                 pos = i->find('.', pos + 1);
401             }
402             if(pos != string::npos)
403             {
404                 ostr << i->substr(0, pos + 1);
405                 break;
406             }
407             else
408             {
409                 ostr << *i;
410             }
411         }
412     }
413 
414     return ostr.str();
415 }
416 
417 void
writeDocSummary(Output & out,const ContainedPtr & p)418 writeDocSummary(Output& out, const ContainedPtr& p)
419 {
420     if(p->comment().empty())
421     {
422         return;
423     }
424 
425     CommentPtr doc = p->parseComment(false);
426 
427     out << nl << "/**";
428 
429     if(!doc->overview().empty())
430     {
431         writeDocLines(out, doc->overview(), true);
432     }
433 
434     if(!doc->misc().empty())
435     {
436         writeDocLines(out, doc->misc(), true);
437     }
438 
439     if(!doc->seeAlso().empty())
440     {
441         writeSeeAlso(out, doc->seeAlso());
442     }
443 
444     if(!doc->deprecated().empty())
445     {
446         out << nl << " *";
447         out << nl << " * @deprecated ";
448         writeDocLines(out, doc->deprecated(), false);
449     }
450     else if(doc->isDeprecated())
451     {
452         out << nl << " *";
453         out << nl << " * @deprecated";
454     }
455 
456     switch(p->containedType())
457     {
458         case Contained::ContainedTypeClass:
459         case Contained::ContainedTypeStruct:
460         case Contained::ContainedTypeException:
461         {
462             UnitPtr unt = p->container()->unit();
463             string file = p->file();
464             assert(!file.empty());
465             static const string prefix = "cpp:doxygen:include:";
466             DefinitionContextPtr dc = unt->findDefinitionContext(file);
467             assert(dc);
468             string q = dc->findMetaData(prefix);
469             if(!q.empty())
470             {
471                 out << nl << " * \\headerfile " << q.substr(prefix.size());
472             }
473             break;
474         }
475         default:
476             break;
477     }
478 
479     out << nl << " */";
480 }
481 
482 enum OpDocParamType { OpDocInParams, OpDocOutParams, OpDocAllParams };
483 
484 void
writeOpDocParams(Output & out,const OperationPtr & op,const CommentPtr & doc,OpDocParamType type,const StringList & preParams=StringList (),const StringList & postParams=StringList ())485 writeOpDocParams(Output& out, const OperationPtr& op, const CommentPtr& doc, OpDocParamType type,
486                  const StringList& preParams = StringList(), const StringList& postParams = StringList())
487 {
488     ParamDeclList params;
489     switch(type)
490     {
491         case OpDocInParams:
492             params = op->inParameters();
493             break;
494         case OpDocOutParams:
495             params = op->outParameters();
496             break;
497         case OpDocAllParams:
498             params = op->parameters();
499             break;
500     }
501 
502     if(!preParams.empty())
503     {
504         writeDocLines(out, preParams, true);
505     }
506 
507     map<string, StringList> paramDoc = doc->parameters();
508     for(ParamDeclList::iterator p = params.begin(); p != params.end(); ++p)
509     {
510         map<string, StringList>::iterator q = paramDoc.find((*p)->name());
511         if(q != paramDoc.end())
512         {
513             out << nl << " * @param " << fixKwd(q->first) << " ";
514             writeDocLines(out, q->second, false);
515         }
516     }
517 
518     if(!postParams.empty())
519     {
520         writeDocLines(out, postParams, true);
521     }
522 }
523 
524 void
writeOpDocExceptions(Output & out,const OperationPtr & op,const CommentPtr & doc)525 writeOpDocExceptions(Output& out, const OperationPtr& op, const CommentPtr& doc)
526 {
527     map<string, StringList> exDoc = doc->exceptions();
528     for(map<string, StringList>::iterator p = exDoc.begin(); p != exDoc.end(); ++p)
529     {
530         //
531         // Try to locate the exception's definition using the name given in the comment.
532         //
533         string name = p->first;
534         ExceptionPtr ex = op->container()->lookupException(name, false);
535         if(ex)
536         {
537             name = ex->scoped().substr(2);
538         }
539         out << nl << " * @throws " << name << " ";
540         writeDocLines(out, p->second, false);
541     }
542 }
543 
544 void
writeOpDocSummary(Output & out,const OperationPtr & op,const CommentPtr & doc,OpDocParamType type,bool showExceptions,const StringList & preParams=StringList (),const StringList & postParams=StringList (),const StringList & returns=StringList ())545 writeOpDocSummary(Output& out, const OperationPtr& op, const CommentPtr& doc, OpDocParamType type, bool showExceptions,
546                   const StringList& preParams = StringList(), const StringList& postParams = StringList(),
547                   const StringList& returns = StringList())
548 {
549     out << nl << "/**";
550 
551     if(!doc->overview().empty())
552     {
553         writeDocLines(out, doc->overview(), true);
554     }
555 
556     writeOpDocParams(out, op, doc, type, preParams, postParams);
557 
558     if(!returns.empty())
559     {
560         out << nl << " * @return ";
561         writeDocLines(out, returns, false);
562     }
563 
564     if(showExceptions)
565     {
566         writeOpDocExceptions(out, op, doc);
567     }
568 
569     if(!doc->misc().empty())
570     {
571         writeDocLines(out, doc->misc(), true);
572     }
573 
574     if(!doc->seeAlso().empty())
575     {
576         writeSeeAlso(out, doc->seeAlso());
577     }
578 
579     if(!doc->deprecated().empty())
580     {
581         out << nl << " *";
582         out << nl << " * @deprecated ";
583         writeDocLines(out, doc->deprecated(), false);
584     }
585     else if(doc->isDeprecated())
586     {
587         out << nl << " *";
588         out << nl << " * @deprecated";
589     }
590 
591     out << nl << " */";
592 }
593 
594 void
emitOpNameResult(IceUtilInternal::Output & H,const OperationPtr & p,int useWstring)595 emitOpNameResult(IceUtilInternal::Output& H, const OperationPtr& p, int useWstring)
596 {
597     string name = p->name();
598 
599     ContainerPtr container = p->container();
600     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
601     string clScope = fixKwd(cl->scope());
602 
603     TypePtr ret = p->returnType();
604     string retS = returnTypeToString(ret, p->returnIsOptional(), clScope, p->getMetaData(),
605                                      useWstring | TypeContextCpp11);
606 
607     ParamDeclList outParams = p->outParameters();
608 
609     if((outParams.size() > 1) || (ret && outParams.size() > 0))
610     {
611         //
612         // Generate OpNameResult struct
613         //
614         string returnValueS = "returnValue";
615 
616         for(ParamDeclList::iterator q = outParams.begin(); q != outParams.end(); ++q)
617         {
618             if((*q)->name() == "returnValue")
619             {
620                 returnValueS = "_returnValue";
621             }
622         }
623 
624         H << sp;
625         H << nl << "/**";
626         H << nl << " * Encapsulates the results of a call to " << fixKwd(name) << ".";
627         H << nl << " */";
628         H << nl << "struct " << resultStructName(name);
629         H << sb;
630         CommentPtr comment = p->parseComment(false);
631         map<string, StringList> paramComments;
632         if(comment)
633         {
634             paramComments = comment->parameters();
635         }
636         if(ret)
637         {
638             if(comment && !comment->returns().empty())
639             {
640                 H << nl << "/** " << getDocSentence(comment->returns()) << " */";
641             }
642             H << nl << retS << " " << returnValueS << ";";
643         }
644         for(ParamDeclList::iterator q = outParams.begin(); q != outParams.end(); ++q)
645         {
646             string typeString = typeToString((*q)->type(), (*q)->optional(), clScope, (*q)->getMetaData(),
647                                              useWstring | TypeContextCpp11);
648 
649             map<string, StringList>::iterator r = paramComments.find((*q)->name());
650             if(r != paramComments.end())
651             {
652                 H << nl << "/** " << getDocSentence(r->second) << " */";
653             }
654             H << nl << typeString << " " << fixKwd((*q)->name()) << ";";
655         }
656         H << eb << ";";
657     }
658 }
659 
660 }
661 
Gen(const string & base,const string & headerExtension,const string & sourceExtension,const vector<string> & extraHeaders,const string & include,const vector<string> & includePaths,const string & dllExport,const string & dir,bool implCpp98,bool implCpp11,bool checksum,bool ice)662 Slice::Gen::Gen(const string& base, const string& headerExtension, const string& sourceExtension,
663                 const vector<string>& extraHeaders, const string& include,
664                 const vector<string>& includePaths, const string& dllExport, const string& dir,
665                 bool implCpp98, bool implCpp11, bool checksum, bool ice) :
666     _base(base),
667     _headerExtension(headerExtension),
668     _implHeaderExtension(headerExtension),
669     _sourceExtension(sourceExtension),
670     _extraHeaders(extraHeaders),
671     _include(include),
672     _includePaths(includePaths),
673     _dllExport(dllExport),
674     _dir(dir),
675     _implCpp98(implCpp98),
676     _implCpp11(implCpp11),
677     _checksum(checksum),
678     _ice(ice)
679 {
680     for(vector<string>::iterator p = _includePaths.begin(); p != _includePaths.end(); ++p)
681     {
682         *p = fullPath(*p);
683     }
684 
685     string::size_type pos = _base.find_last_of("/\\");
686     if(pos != string::npos)
687     {
688         _base.erase(0, pos + 1);
689     }
690 }
691 
~Gen()692 Slice::Gen::~Gen()
693 {
694     H << "\n\n#include <IceUtil/PopDisableWarnings.h>";
695     H << "\n#endif\n";
696     C << '\n';
697 
698     if(_implCpp98 || _implCpp11)
699     {
700         implH << "\n\n#endif\n";
701         implC << '\n';
702     }
703 }
704 
705 void
generateChecksumMap(const UnitPtr & p)706 Slice::Gen::generateChecksumMap(const UnitPtr& p)
707 {
708     if(_checksum)
709     {
710         ChecksumMap map = createChecksums(p);
711         if(!map.empty())
712         {
713             C << sp << nl << "namespace";
714             C << nl << "{";
715             C << sp << nl << "const char* iceSliceChecksums[] =";
716             C << sb;
717             for(ChecksumMap::const_iterator q = map.begin(); q != map.end(); ++q)
718             {
719                 C << nl << "\"" << q->first << "\", \"";
720                 ostringstream str;
721                 str.flags(ios_base::hex);
722                 str.fill('0');
723                 for(vector<unsigned char>::const_iterator r = q->second.begin(); r != q->second.end(); ++r)
724                 {
725                     str << static_cast<int>(*r);
726                 }
727                 C << str.str() << "\",";
728             }
729             C << nl << "0";
730             C << eb << ';';
731             C << nl << "const IceInternal::SliceChecksumInit iceSliceChecksumInit(iceSliceChecksums);";
732             C << sp << nl << "}";
733         }
734     }
735 }
736 
737 void
generate(const UnitPtr & p)738 Slice::Gen::generate(const UnitPtr& p)
739 {
740     string file = p->topLevelFile();
741 
742     //
743     // Give precedence to header-ext/source-ext global metadata.
744     //
745     string headerExtension = getHeaderExt(file, p);
746     if(!headerExtension.empty())
747     {
748         _headerExtension = headerExtension;
749     }
750 
751     string sourceExtension = getSourceExt(file, p);
752     if(!sourceExtension.empty())
753     {
754         _sourceExtension = sourceExtension;
755     }
756 
757     //
758     // Give precedence to --dll-export command-line option
759     //
760     if(_dllExport.empty())
761     {
762         DefinitionContextPtr dc = p->findDefinitionContext(file);
763         assert(dc);
764         static const string dllExportPrefix = "cpp:dll-export:";
765         string meta = dc->findMetaData(dllExportPrefix);
766         if(meta.size() > dllExportPrefix.size())
767         {
768             _dllExport = meta.substr(dllExportPrefix.size());
769         }
770     }
771 
772     if(_implCpp98 || _implCpp11)
773     {
774         string fileImplH = _base + "I." + _implHeaderExtension;
775         string fileImplC = _base + "I." + _sourceExtension;
776         if(!_dir.empty())
777         {
778             fileImplH = _dir + '/' + fileImplH;
779             fileImplC = _dir + '/' + fileImplC;
780         }
781 
782         IceUtilInternal::structstat st;
783         if(!IceUtilInternal::stat(fileImplH, &st))
784         {
785             ostringstream os;
786             os << fileImplH << "' already exists - will not overwrite";
787             throw FileException(__FILE__, __LINE__, os.str());
788         }
789         if(!IceUtilInternal::stat(fileImplC, &st))
790         {
791             ostringstream os;
792             os << fileImplC << "' already exists - will not overwrite";
793             throw FileException(__FILE__, __LINE__, os.str());
794         }
795 
796         implH.open(fileImplH.c_str());
797         if(!implH)
798         {
799             ostringstream os;
800             os << "cannot open `" << fileImplH << "': " << IceUtilInternal::errorToString(errno);
801             throw FileException(__FILE__, __LINE__, os.str());
802         }
803         FileTracker::instance()->addFile(fileImplH);
804 
805         implC.open(fileImplC.c_str());
806         if(!implC)
807         {
808             ostringstream os;
809             os << "cannot open `" << fileImplC << "': " << IceUtilInternal::errorToString(errno);
810             throw FileException(__FILE__, __LINE__, os.str());
811         }
812         FileTracker::instance()->addFile(fileImplC);
813 
814         string s = _base + "I." + _implHeaderExtension;
815         if(_include.size())
816         {
817             s = _include + '/' + s;
818         }
819         transform(s.begin(), s.end(), s.begin(), ToIfdef());
820         implH << "#ifndef __" << s << "__";
821         implH << "\n#define __" << s << "__";
822         implH << '\n';
823     }
824 
825     string fileH = _base + "." + _headerExtension;
826     string fileC = _base + "." + _sourceExtension;
827     if(!_dir.empty())
828     {
829         fileH = _dir + '/' + fileH;
830         fileC = _dir + '/' + fileC;
831     }
832 
833     H.open(fileH.c_str());
834     if(!H)
835     {
836         ostringstream os;
837         os << "cannot open `" << fileH << "': " << IceUtilInternal::errorToString(errno);
838         throw FileException(__FILE__, __LINE__, os.str());
839     }
840     FileTracker::instance()->addFile(fileH);
841 
842     C.open(fileC.c_str());
843     if(!C)
844     {
845         ostringstream os;
846         os << "cannot open `" << fileC << "': " << IceUtilInternal::errorToString(errno);
847         throw FileException(__FILE__, __LINE__, os.str());
848     }
849     FileTracker::instance()->addFile(fileC);
850 
851     printHeader(H);
852     printGeneratedHeader(H, _base + ".ice");
853     printHeader(C);
854     printGeneratedHeader(C, _base + ".ice");
855 
856     string s = _base + "." + _headerExtension;
857     if(_include.size())
858     {
859         s = _include + '/' + s;
860     }
861     transform(s.begin(), s.end(), s.begin(), ToIfdef());
862     H << "\n#ifndef __" << s << "__";
863     H << "\n#define __" << s << "__";
864     H << '\n';
865 
866     validateMetaData(p);
867 
868     writeExtraHeaders(C);
869 
870     if(_dllExport.size())
871     {
872         C << "\n#ifndef " << _dllExport << "_EXPORTS";
873         C << "\n#   define " << _dllExport << "_EXPORTS";
874         C << "\n#endif";
875     }
876 
877     C << "\n#include <";
878     if(_include.size())
879     {
880         C << _include << '/';
881     }
882     C << _base << "." << _headerExtension << ">";
883     C <<  "\n#include <IceUtil/PushDisableWarnings.h>";
884 
885     H << "\n#include <IceUtil/PushDisableWarnings.h>";
886     H << "\n#include <Ice/ProxyF.h>";
887     H << "\n#include <Ice/ObjectF.h>";
888     H << "\n#include <Ice/ValueF.h>";
889     H << "\n#include <Ice/Exception.h>";
890     H << "\n#include <Ice/LocalObject.h>";
891     H << "\n#include <Ice/StreamHelpers.h>";
892     H << "\n#include <Ice/Comparable.h>";
893 
894     if(p->hasNonLocalClassDefs())
895     {
896         H << "\n#include <Ice/Proxy.h>";
897         H << "\n#include <Ice/Object.h>";
898         H << "\n#include <Ice/GCObject.h>";
899         H << "\n#include <Ice/Value.h>";
900         H << "\n#include <Ice/Incoming.h>";
901         if(p->hasContentsWithMetaData("amd"))
902         {
903             H << "\n#include <Ice/IncomingAsync.h>";
904         }
905         C << "\n#include <Ice/LocalException.h>";
906         C << "\n#include <Ice/ValueFactory.h>";
907         C << "\n#include <Ice/OutgoingAsync.h>";
908     }
909     else if(p->hasLocalClassDefsWithAsync())
910     {
911         H << "\n#include <Ice/OutgoingAsync.h>";
912     }
913     else if(p->hasNonLocalClassDecls())
914     {
915         H << "\n#include <Ice/Proxy.h>";
916     }
917 
918     if(p->hasNonLocalClassDefs() || p->hasNonLocalExceptions())
919     {
920         H << "\n#include <Ice/FactoryTableInit.h>";
921     }
922 
923     H << "\n#include <IceUtil/ScopedArray.h>";
924     H << "\n#include <Ice/Optional.h>";
925 
926     if(p->hasExceptions())
927     {
928         H << "\n#include <Ice/ExceptionHelpers.h>";
929     }
930 
931     if(p->usesNonLocals())
932     {
933         C << "\n#include <Ice/InputStream.h>";
934         C << "\n#include <Ice/OutputStream.h>";
935     }
936 
937     if(p->hasNonLocalExceptions())
938     {
939         C << "\n#include <Ice/LocalException.h>";
940     }
941 
942     if(p->hasContentsWithMetaData("preserve-slice"))
943     {
944         H << "\n#include <Ice/SlicedDataF.h>";
945         C << "\n#include <Ice/SlicedData.h>";
946     }
947 
948     if(_checksum)
949     {
950         C << "\n#include <Ice/SliceChecksums.h>";
951     }
952 
953     C << "\n#include <IceUtil/PopDisableWarnings.h>";
954 
955     StringList includes = p->includeFiles();
956 
957     for(StringList::const_iterator q = includes.begin(); q != includes.end(); ++q)
958     {
959         string extension = getHeaderExt((*q), p);
960         if(extension.empty())
961         {
962             extension = _headerExtension;
963         }
964         H << "\n#include <" << changeInclude(*q, _includePaths) << "." << extension << ">";
965     }
966 
967     H << "\n#include <IceUtil/UndefSysMacros.h>";
968 
969     //
970     // Emit #include statements for any cpp:include metadata directives
971     // in the top-level Slice file.
972     //
973     {
974         DefinitionContextPtr dc = p->findDefinitionContext(file);
975         assert(dc);
976         StringList globalMetaData = dc->getMetaData();
977         for(StringList::const_iterator q = globalMetaData.begin(); q != globalMetaData.end();)
978         {
979             string md = *q++;
980             static const string includePrefix = "cpp:include:";
981             if(md.find(includePrefix) == 0)
982             {
983                 if(md.size() > includePrefix.size())
984                 {
985                     H << nl << "#include <" << md.substr(includePrefix.size()) << ">";
986                 }
987                 else
988                 {
989                     ostringstream ostr;
990                     ostr << "ignoring invalid global metadata `" << md << "'";
991                     dc->warning(InvalidMetaData, file, -1, ostr.str());
992                     globalMetaData.remove(md);
993                 }
994             }
995         }
996         dc->setMetaData(globalMetaData);
997     }
998 
999     //
1000     // Disable shadow warnings in .cpp file
1001     //
1002     C << sp;
1003     C.zeroIndent();
1004     C << nl << "#if defined(_MSC_VER)";
1005     C << nl << "#   pragma warning(disable:4458) // declaration of ... hides class member";
1006     C << nl << "#elif defined(__clang__)";
1007     C << nl << "#   pragma clang diagnostic ignored \"-Wshadow\"";
1008     C << nl << "#elif defined(__GNUC__)";
1009     C << nl << "#   pragma GCC diagnostic ignored \"-Wshadow\"";
1010     C << nl << "#endif";
1011 
1012     printVersionCheck(H);
1013     printVersionCheck(C);
1014 
1015     printDllExportStuff(H, _dllExport);
1016     if(_dllExport.size())
1017     {
1018         _dllExport += " ";
1019     }
1020 
1021     H << sp;
1022     H.zeroIndent();
1023     H << nl << "#ifdef ICE_CPP11_MAPPING // C++11 mapping";
1024     H.restoreIndent();
1025 
1026     C << sp;
1027     C.zeroIndent();
1028     C << nl << "#ifdef ICE_CPP11_MAPPING // C++11 mapping";
1029     C.restoreIndent();
1030     {
1031         normalizeMetaData(p, true);
1032 
1033         Cpp11DeclVisitor declVisitor(H, C, _dllExport);
1034         p->visit(&declVisitor, false);
1035 
1036         Cpp11TypesVisitor typesVisitor(H, C, _dllExport);
1037         p->visit(&typesVisitor, false);
1038 
1039         Cpp11LocalObjectVisitor localObjectVisitor(H, C, _dllExport);
1040         p->visit(&localObjectVisitor, false);
1041 
1042         Cpp11InterfaceVisitor interfaceVisitor(H, C, _dllExport);
1043         p->visit(&interfaceVisitor, false);
1044 
1045         Cpp11ValueVisitor valueVisitor(H, C, _dllExport);
1046         p->visit(&valueVisitor, false);
1047 
1048         Cpp11ProxyVisitor proxyVisitor(H, C, _dllExport);
1049         p->visit(&proxyVisitor, false);
1050 
1051         Cpp11StreamVisitor streamVisitor(H, C, _dllExport);
1052         p->visit(&streamVisitor, false);
1053 
1054         if(_implCpp11)
1055         {
1056             implH << "\n#include <";
1057             if(_include.size())
1058             {
1059                 implH << _include << '/';
1060             }
1061             implH << _base << "." << _headerExtension << ">";
1062             writeExtraHeaders(implC);
1063 
1064             implC << "\n#include <";
1065             if(_include.size())
1066             {
1067                 implC << _include << '/';
1068             }
1069             implC << _base << "I." << _implHeaderExtension << ">";
1070 
1071             Cpp11ImplVisitor implVisitor(implH, implC, _dllExport);
1072             p->visit(&implVisitor, false);
1073         }
1074 
1075         Cpp11CompatibilityVisitor compatibilityVisitor(H, C, _dllExport);
1076         p->visit(&compatibilityVisitor, false);
1077 
1078         generateChecksumMap(p);
1079     }
1080     H << sp;
1081     H.zeroIndent();
1082     H << nl << "#else // C++98 mapping";
1083     H.restoreIndent();
1084 
1085     C << sp;
1086     C.zeroIndent();
1087     C << nl << "#else // C++98 mapping";
1088     C.restoreIndent();
1089     {
1090         normalizeMetaData(p, false);
1091 
1092         ProxyDeclVisitor proxyDeclVisitor(H, C, _dllExport);
1093         p->visit(&proxyDeclVisitor, false);
1094 
1095         ObjectDeclVisitor objectDeclVisitor(H, C, _dllExport);
1096         p->visit(&objectDeclVisitor, false);
1097 
1098         TypesVisitor typesVisitor(H, C, _dllExport);
1099         p->visit(&typesVisitor, false);
1100 
1101         AsyncVisitor asyncVisitor(H, C, _dllExport);
1102         p->visit(&asyncVisitor, false);
1103 
1104         AsyncImplVisitor asyncImplVisitor(H, C, _dllExport);
1105         p->visit(&asyncImplVisitor, false);
1106 
1107         //
1108         // The templates are emitted before the proxy definition
1109         // so the derivation hierarchy is known to the proxy:
1110         // the proxy relies on knowing the hierarchy to make the begin_
1111         // methods type-safe.
1112         //
1113         AsyncCallbackVisitor asyncCallbackVisitor(H, C, _dllExport);
1114         p->visit(&asyncCallbackVisitor, false);
1115 
1116         ProxyVisitor proxyVisitor(H, C, _dllExport);
1117         p->visit(&proxyVisitor, false);
1118 
1119         ObjectVisitor objectVisitor(H, C, _dllExport);
1120         p->visit(&objectVisitor, false);
1121 
1122         StreamVisitor streamVisitor(H, C, _dllExport);
1123         p->visit(&streamVisitor, false);
1124 
1125         //
1126         // We need to delay generating the template after the proxy
1127         // definition, because completed calls the begin_ method in the
1128         // proxy.
1129         //
1130         AsyncCallbackTemplateVisitor asyncCallbackTemplateVisitor(H, C, _dllExport);
1131         p->visit(&asyncCallbackTemplateVisitor, false);
1132 
1133         if(_implCpp98)
1134         {
1135             implH << "\n#include <";
1136             if(_include.size())
1137             {
1138                 implH << _include << '/';
1139             }
1140             implH << _base << "." << _headerExtension << ">";
1141 
1142             writeExtraHeaders(implC);
1143 
1144             implC << "\n#include <";
1145             if(_include.size())
1146             {
1147                 implC << _include << '/';
1148             }
1149             implC << _base << "I." << _implHeaderExtension << ">";
1150 
1151             ImplVisitor implVisitor(implH, implC, _dllExport);
1152             p->visit(&implVisitor, false);
1153         }
1154 
1155         generateChecksumMap(p);
1156     }
1157 
1158     H << sp;
1159     H.zeroIndent();
1160     H << nl << "#endif";
1161     H.restoreIndent();
1162 
1163     C << sp;
1164     C.zeroIndent();
1165     C << nl << "#endif";
1166     C.restoreIndent();
1167 }
1168 
1169 void
closeOutput()1170 Slice::Gen::closeOutput()
1171 {
1172     H.close();
1173     C.close();
1174     implH.close();
1175     implC.close();
1176 }
1177 
1178 void
writeExtraHeaders(IceUtilInternal::Output & out)1179 Slice::Gen::writeExtraHeaders(IceUtilInternal::Output& out)
1180 {
1181     for(vector<string>::const_iterator i = _extraHeaders.begin(); i != _extraHeaders.end(); ++i)
1182     {
1183         string hdr = *i;
1184         string guard;
1185         string::size_type pos = hdr.rfind(',');
1186         if(pos != string::npos)
1187         {
1188             hdr = i->substr(0, pos);
1189             guard = i->substr(pos + 1);
1190         }
1191         if(!guard.empty())
1192         {
1193             out << "\n#ifndef " << guard;
1194             out << "\n#define " << guard;
1195         }
1196         out << "\n#include <";
1197         out << hdr << '>';
1198         if(!guard.empty())
1199         {
1200             out << "\n#endif";
1201         }
1202     }
1203 }
1204 
TypesVisitor(Output & h,Output & c,const string & dllExport)1205 Slice::Gen::TypesVisitor::TypesVisitor(Output& h, Output& c, const string& dllExport) :
1206     H(h), C(c), _dllExport(dllExport), _doneStaticSymbol(false), _useWstring(false)
1207 {
1208 }
1209 
1210 bool
visitModuleStart(const ModulePtr & p)1211 Slice::Gen::TypesVisitor::visitModuleStart(const ModulePtr& p)
1212 {
1213     if(!p->hasOtherConstructedOrExceptions())
1214     {
1215         return false;
1216     }
1217 
1218     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
1219 
1220     H << sp << nl << "namespace " << fixKwd(p->name()) << nl << '{';
1221 
1222     return true;
1223 }
1224 
1225 void
visitModuleEnd(const ModulePtr &)1226 Slice::Gen::TypesVisitor::visitModuleEnd(const ModulePtr&)
1227 {
1228     H << sp << nl << '}';
1229 
1230     _useWstring = resetUseWstring(_useWstringHist);
1231 }
1232 
1233 bool
visitClassDefStart(const ClassDefPtr &)1234 Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr&)
1235 {
1236     return false;
1237 }
1238 
1239 bool
visitExceptionStart(const ExceptionPtr & p)1240 Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p)
1241 {
1242     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
1243 
1244     string name = fixKwd(p->name());
1245     string scope = fixKwd(p->scope());
1246     string scoped = fixKwd(p->scoped());
1247     ExceptionPtr base = p->base();
1248     DataMemberList dataMembers = p->dataMembers();
1249     DataMemberList allDataMembers = p->allDataMembers();
1250     bool hasDefaultValues = p->hasDefaultValues();
1251 
1252     vector<string> allParamDecls;
1253     vector<string> baseParams;
1254     map<string, CommentPtr> allComments;
1255 
1256     string fileParam = "file";
1257     string lineParam = "line";
1258 
1259     for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
1260     {
1261         string typeName = inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring);
1262         allParamDecls.push_back(typeName + " " + fixKwd((*q)->name()));
1263         CommentPtr comment = (*q)->parseComment(false);
1264         if(comment)
1265         {
1266             allComments[(*q)->name()] = comment;
1267         }
1268 
1269         if((*q)->name() == "file")
1270         {
1271             fileParam = "file_";
1272         }
1273         else if((*q)->name() == "line")
1274         {
1275             fileParam = "line_";
1276         }
1277     }
1278 
1279     if(base)
1280     {
1281         DataMemberList baseDataMembers = base->allDataMembers();
1282         for(DataMemberList::const_iterator q = baseDataMembers.begin(); q != baseDataMembers.end(); ++q)
1283         {
1284             baseParams.push_back(fixKwd((*q)->name()));
1285         }
1286     }
1287 
1288     H << sp;
1289     writeDocSummary(H, p);
1290     H << nl << "class " << _dllExport << name << " : ";
1291     H.useCurrentPosAsIndent();
1292     H << "public ";
1293     if(base)
1294     {
1295         H << getUnqualified(fixKwd(base->scoped()), scope);
1296     }
1297     else
1298     {
1299         H << getUnqualified(p->isLocal() ? "::Ice::LocalException" : "::Ice::UserException", scope);
1300     }
1301     H.restoreIndent();
1302     H << sb;
1303 
1304     H.dec();
1305     H << nl << "public:";
1306     H.inc();
1307 
1308     H << sp;
1309     if(p->isLocal())
1310     {
1311         H << nl << "/**";
1312         H << nl << " * The file and line number are required for all local exceptions.";
1313         H << nl << " * @param " << fileParam
1314           << " The file name in which the exception was raised, typically __FILE__.";
1315         H << nl << " * @param " << lineParam
1316           << " The line number at which the exception was raised, typically __LINE__.";
1317         H << nl << " */";
1318     }
1319     else if(hasDefaultValues)
1320     {
1321         H << nl << "/** Default constructor that assigns default values to members as specified in the "
1322           "Slice definition. */";
1323     }
1324 
1325     H << nl << name << spar;
1326     if(p->isLocal())
1327     {
1328         H << "const char* " + fileParam << "int " + lineParam;
1329     }
1330     H << epar;
1331     if(!p->isLocal() && !hasDefaultValues)
1332     {
1333         H << " {}";
1334     }
1335     else
1336     {
1337         H << ';';
1338     }
1339     if(!allParamDecls.empty())
1340     {
1341         H << nl << "/**";
1342         H << nl << " * One-shot constructor to initialize all data members.";
1343         if(p->isLocal())
1344         {
1345             H << nl << " * The file and line number are required for all local exceptions.";
1346             H << nl << " * @param " << fileParam
1347               << " The file name in which the exception was raised, typically __FILE__.";
1348             H << nl << " * @param " << lineParam
1349               << " The line number at which the exception was raised, typically __LINE__.";
1350         }
1351         for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
1352         {
1353             map<string, CommentPtr>::iterator r = allComments.find((*q)->name());
1354             if(r != allComments.end())
1355             {
1356                 H << nl << " * @param " << fixKwd(r->first) << " " << getDocSentence(r->second->overview());
1357             }
1358         }
1359         H << nl << " */";
1360         H << nl;
1361         if(!p->isLocal() && allParamDecls.size() == 1)
1362         {
1363             H << "explicit ";
1364         }
1365         H << name << spar;
1366         if(p->isLocal())
1367         {
1368             H << "const char* " + fileParam << "int " + lineParam;
1369         }
1370         H << allParamDecls << epar << ';';
1371     }
1372     H << nl << "virtual ~" << name << "() throw();";
1373     H << sp;
1374 
1375     if(!p->isLocal())
1376     {
1377         string initName = "iceC" + p->flattenedScope() + p->name() + "_init";
1378 
1379         C << sp << nl << "namespace";
1380         C << nl << "{";
1381 
1382         C << sp << nl << "const ::IceInternal::DefaultUserExceptionFactoryInit< " << scoped << "> "
1383           << initName << "(\"" << p->scoped() << "\");";
1384 
1385         C << sp << nl << "}";
1386     }
1387 
1388     if(p->isLocal())
1389     {
1390         C << sp << nl << scoped.substr(2) << "::" << name << spar << "const char* " + fileParam
1391           << "int " + lineParam << epar << " :";
1392         C.inc();
1393         emitUpcall(base, "(" + fileParam + ", " + lineParam + ")", scope, true);
1394         if(p->hasDefaultValues())
1395         {
1396             C << ",";
1397             writeDataMemberInitializers(C, dataMembers, _useWstring);
1398         }
1399         C.dec();
1400         C << sb;
1401         C << eb;
1402     }
1403     else if(hasDefaultValues)
1404     {
1405         C << sp << nl << scoped.substr(2) << "::" << name << "() :";
1406         C.inc();
1407         writeDataMemberInitializers(C, dataMembers, _useWstring);
1408         C.dec();
1409         C << sb;
1410         C << eb;
1411     }
1412 
1413     if(!allParamDecls.empty())
1414     {
1415         C << sp << nl;
1416         C << scoped.substr(2) << "::" << name << spar;
1417         if(p->isLocal())
1418         {
1419             C << "const char* " + fileParam << "int " + lineParam;
1420         }
1421         C << allParamDecls << epar;
1422         if(p->isLocal() || !baseParams.empty() || !dataMembers.empty())
1423         {
1424             C << " :";
1425             C.inc();
1426             string upcall;
1427             if(!allParamDecls.empty())
1428             {
1429                 upcall = "(";
1430                 if(p->isLocal())
1431                 {
1432                     upcall += fileParam + ", " + lineParam;
1433                 }
1434                 for(vector<string>::const_iterator pi = baseParams.begin(); pi != baseParams.end(); ++pi)
1435                 {
1436                     if(p->isLocal() || pi != baseParams.begin())
1437                     {
1438                         upcall += ", ";
1439                     }
1440                     upcall += *pi;
1441                 }
1442                 upcall += ")";
1443             }
1444             if(!dataMembers.empty())
1445             {
1446                 upcall += ",";
1447             }
1448             emitUpcall(base, upcall, scope, p->isLocal());
1449         }
1450         for(DataMemberList::const_iterator d = dataMembers.begin();  d != dataMembers.end(); ++d)
1451         {
1452             if(d != dataMembers.begin())
1453             {
1454                 C << ",";
1455             }
1456             string memberName = fixKwd((*d)->name());
1457             C << nl << memberName << "(" << memberName << ")";
1458         }
1459         if(p->isLocal() || !baseParams.empty() || !dataMembers.empty())
1460         {
1461             C.dec();
1462         }
1463         C << sb;
1464         C << eb;
1465     }
1466 
1467     C << sp << nl;
1468     C << scoped.substr(2) << "::~" << name << "() throw()";
1469     C << sb;
1470     C << eb;
1471 
1472     H << nl << "/**";
1473     H << nl << " * Obtains the Slice type ID of this exception.";
1474     H << nl << " * @return The fully-scoped type ID.";
1475     H << nl << " */";
1476     H << nl << "virtual ::std::string ice_id() const;";
1477     C << sp << nl << "::std::string" << nl << scoped.substr(2) << "::ice_id() const";
1478     C << sb;
1479     C << nl << "return \"" << p->scoped() << "\";";
1480     C << eb;
1481 
1482     StringList metaData = p->getMetaData();
1483     if(find(metaData.begin(), metaData.end(), "cpp:ice_print") != metaData.end())
1484     {
1485         H << nl << "/**";
1486         H << nl << " * Prints this exception to the given stream.";
1487         H << nl << " * @param stream The target stream.";
1488         H << nl << " */";
1489         H << nl << "virtual void ice_print(::std::ostream& stream) const;";
1490     }
1491 
1492     H << nl << "/**";
1493     H << nl << " * Polymporphically clones this exception.";
1494     H << nl << " * @return A shallow copy of this exception.";
1495     H << nl << " */";
1496     H << nl << "virtual " << name << "* ice_clone() const;";
1497     C << sp << nl << scoped.substr(2) << "*" << nl << scoped.substr(2) << "::ice_clone() const";
1498     C << sb;
1499     C << nl << "return new " << name << "(*this);";
1500     C << eb;
1501 
1502     H << nl << "/**";
1503     H << nl << " * Throws this exception.";
1504     H << nl << " */";
1505     H << nl << "virtual void ice_throw() const;";
1506     C << sp << nl << "void" << nl << scoped.substr(2) << "::ice_throw() const";
1507     C << sb;
1508     C << nl << "throw *this;";
1509     C << eb;
1510 
1511     if(!p->isLocal() && p->usesClasses(false))
1512     {
1513         if(!base || (base && !base->usesClasses(false)))
1514         {
1515             H << sp;
1516             H << nl << "/// \\cond STREAM";
1517             H << nl << "virtual bool _usesClasses() const;";
1518             H << nl << "/// \\endcond";
1519 
1520             C << sp << nl << "bool";
1521             C << nl << scoped.substr(2) << "::_usesClasses() const";
1522             C << sb;
1523             C << nl << "return true;";
1524             C << eb;
1525         }
1526     }
1527 
1528     if(!dataMembers.empty())
1529     {
1530         H << sp;
1531     }
1532     return true;
1533 }
1534 
1535 void
visitExceptionEnd(const ExceptionPtr & p)1536 Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p)
1537 {
1538     string name = fixKwd(p->name());
1539     string scope = fixKwd(p->scope());
1540     string scoped = fixKwd(p->scoped());
1541     string factoryName;
1542 
1543     if(!p->isLocal())
1544     {
1545         ExceptionPtr base = p->base();
1546         bool basePreserved = p->inheritsMetaData("preserve-slice");
1547         bool preserved = p->hasMetaData("preserve-slice");
1548 
1549         if(preserved && !basePreserved)
1550         {
1551             H << sp;
1552             H << nl << "/**";
1553             H << nl << " * Obtains the SlicedData object created when an unknown exception type was marshaled";
1554             H << nl << " * in the sliced format and the Ice run time sliced it to a known type.";
1555             H << nl << " * @return The SlicedData object, or nil if the exception was not sliced or was not";
1556             H << nl << " * marshaled in the sliced format.";
1557             H << nl << " */";
1558             H << nl << "virtual ::Ice::SlicedDataPtr ice_getSlicedData() const;";
1559 
1560             H << sp;
1561             H << nl << "/// \\cond STREAM";
1562             H << nl << "virtual void _write(::Ice::OutputStream*) const;";
1563             H << nl << "virtual void _read(::Ice::InputStream*);";
1564 
1565             string baseName = base ? fixKwd(base->scoped()) : string("::Ice::UserException");
1566             H << nl << "using " << baseName << "::_write;";
1567             H << nl << "using " << baseName << "::_read;";
1568             H << nl << "/// \\endcond";
1569         }
1570 
1571         H.dec();
1572         H << sp << nl << "protected:";
1573         H.inc();
1574 
1575         H << sp;
1576         H << nl << "/// \\cond STREAM";
1577         H << nl << "virtual void _writeImpl(" << getUnqualified("::Ice::OutputStream*", scope) << ") const;";
1578         H << nl << "virtual void _readImpl(" << getUnqualified("::Ice::InputStream*", scope) << ");";
1579         H << nl << "/// \\endcond";
1580 
1581         string baseName = getUnqualified(base ? fixKwd(base->scoped()) : "::Ice::UserException", scope);
1582 
1583         if(preserved && !basePreserved)
1584         {
1585             H << sp;
1586             H << nl << "/// \\cond STREAM";
1587             H << nl << "::Ice::SlicedDataPtr _slicedData;";
1588             H << nl << "/// \\endcond";
1589 
1590             C << sp;
1591             C << nl << "::Ice::SlicedDataPtr" << nl << scoped.substr(2) << "::ice_getSlicedData() const";
1592             C << sb;
1593             C << nl << "return _slicedData;";
1594             C << eb;
1595 
1596             C << sp << nl << "void" << nl << scoped.substr(2) << "::_write("
1597               << getUnqualified("::Ice::OutputStream*", scope) << " ostr) const";
1598             C << sb;
1599             C << nl << "ostr->startException(_slicedData);";
1600             C << nl << "_writeImpl(ostr);";
1601             C << nl << "ostr->endException();";
1602             C << eb;
1603 
1604             C << sp << nl << "void" << nl << scoped.substr(2) << "::_read("
1605               << getUnqualified("::Ice::InputStream*", scope) << " istr)";
1606             C << sb;
1607             C << nl << "istr->startException();";
1608             C << nl << "_readImpl(istr);";
1609             C << nl << "_slicedData = istr->endException(true);";
1610             C << eb;
1611         }
1612 
1613         C << sp;
1614         C << nl << "/// \\cond STREAM";
1615         C << nl << "void" << nl << scoped.substr(2) << "::_writeImpl("
1616           << getUnqualified("::Ice::OutputStream*", scope) << " ostr) const";
1617         C << sb;
1618         C << nl << "ostr->startSlice(\"" << p->scoped() << "\", -1, " << (!base ? "true" : "false") << ");";
1619         C << nl << getUnqualified("::Ice::StreamWriter", scope) << "< " << name << ", "
1620           << getUnqualified("::Ice::OutputStream", scope) << ">::write(ostr, *this);";
1621         C << nl << "ostr->endSlice();";
1622         if(base)
1623         {
1624             emitUpcall(base, "::_writeImpl(ostr);", scope);
1625         }
1626         C << eb;
1627 
1628         C << sp << nl << "void" << nl << scoped.substr(2) << "::_readImpl("
1629           << getUnqualified("::Ice::InputStream*", scope) << " istr)";
1630         C << sb;
1631         C << nl << "istr->startSlice();";
1632         C << nl << getUnqualified("::Ice::StreamReader", scope) << "< " << name << ", "
1633           << getUnqualified("::Ice::InputStream", scope) << ">::read(istr, *this);";
1634         C << nl << "istr->endSlice();";
1635         if(base)
1636         {
1637             emitUpcall(base, "::_readImpl(istr);", scope);
1638         }
1639         C << eb;
1640         C << nl << "/// \\endcond";
1641     }
1642     H << eb << ';';
1643 
1644     if(!p->isLocal())
1645     {
1646         //
1647         // We need an instance here to trigger initialization if the implementation is in a static library.
1648         // But we do this only once per source file, because a single instance is sufficient to initialize
1649         // all of the globals in a compilation unit.
1650         //
1651         if(!_doneStaticSymbol)
1652         {
1653             _doneStaticSymbol = true;
1654             H << sp;
1655             H << nl << "/// \\cond INTERNAL";
1656             H << nl << "static " << name << " _iceS_" << p->name() << "_init;";
1657             H << nl << "/// \\endcond";
1658         }
1659     }
1660 
1661     _useWstring = resetUseWstring(_useWstringHist);
1662 }
1663 
1664 bool
visitStructStart(const StructPtr & p)1665 Slice::Gen::TypesVisitor::visitStructStart(const StructPtr& p)
1666 {
1667     DataMemberList dataMembers = p->dataMembers();
1668     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
1669     string scope = fixKwd(p->scope());
1670     string name = fixKwd(p->name());
1671 
1672     H << sp;
1673     writeDocSummary(H, p);
1674 
1675     bool classMetaData = findMetaData(p->getMetaData()) == "%class";
1676     if(classMetaData)
1677     {
1678         H << nl << "class " << name << " : public IceUtil::Shared";
1679         H << sb;
1680         H.dec();
1681         H << nl << "public:";
1682         H.inc();
1683         H << nl;
1684         if(p->hasDefaultValues())
1685         {
1686             H << nl << "/** Default constructor that assigns default values to members as specified in the "
1687               "Slice definition. */";
1688             H << nl << name << "() :";
1689             H.inc();
1690             writeDataMemberInitializers(H, dataMembers, _useWstring);
1691             H.dec();
1692             H << sb;
1693             H << eb;
1694         }
1695         else
1696         {
1697             H << nl << name << "() {}";
1698         }
1699     }
1700     else
1701     {
1702         H << nl << "struct " << name;
1703         H << sb;
1704         if(p->hasDefaultValues())
1705         {
1706             H << nl << "/** Default constructor that assigns default values to members as specified in the "
1707               "Slice definition. */";
1708             H << nl << name << "() :";
1709             H.inc();
1710             writeDataMemberInitializers(H, dataMembers, _useWstring);
1711             H.dec();
1712             H << sb;
1713             H << eb << nl;
1714         }
1715     }
1716 
1717     //
1718     // Generate a one-shot constructor if the struct uses the class mapping, or if at least
1719     // one of its members has a default value.
1720     //
1721     if(!dataMembers.empty() && (findMetaData(p->getMetaData()) == "%class" || p->hasDefaultValues()))
1722     {
1723         vector<string> paramDecls;
1724         map<string, CommentPtr> comments;
1725         for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
1726         {
1727             string typeName =
1728                 inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring);
1729             paramDecls.push_back(typeName + " " + fixKwd((*q)->name()));
1730             CommentPtr comment = (*q)->parseComment(false);
1731             if(comment && !comment->overview().empty())
1732             {
1733                 comments[(*q)->name()] = comment;
1734             }
1735         }
1736 
1737         if(!comments.empty())
1738         {
1739             H << nl << "/**";
1740             H << nl << " * One-shot constructor to initialize all data members.";
1741             for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
1742             {
1743                 map<string, CommentPtr>::iterator r = comments.find((*q)->name());
1744                 if(r != comments.end())
1745                 {
1746                     H << nl << " * @param " << fixKwd(r->first) << " " << getDocSentence(r->second->overview());
1747                 }
1748             }
1749             H << nl << " */";
1750         }
1751 
1752         H << nl;
1753         if(paramDecls.size() == 1)
1754         {
1755             H << "explicit ";
1756         }
1757         H << fixKwd(p->name()) << spar << paramDecls << epar << " :";
1758         H.inc();
1759 
1760         for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
1761         {
1762             if(q != dataMembers.begin())
1763             {
1764                 H << ',';
1765             }
1766             string memberName = fixKwd((*q)->name());
1767             H << nl << memberName << '(' << memberName << ')';
1768         }
1769 
1770         H.dec();
1771         H << sb;
1772         H << eb;
1773         H << nl;
1774     }
1775 
1776     H << sp;
1777 
1778     return true;
1779 }
1780 
1781 void
visitStructEnd(const StructPtr & p)1782 Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p)
1783 {
1784     string name = fixKwd(p->name());
1785     string scoped = fixKwd(p->scoped());
1786     string scope = fixKwd(p->scope());
1787 
1788     DataMemberList dataMembers = p->dataMembers();
1789 
1790     vector<string> params;
1791 
1792     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
1793     {
1794         params.push_back(fixKwd((*q)->name()));
1795     }
1796 
1797     bool containsSequence = false;
1798     if((Dictionary::legalKeyType(p, containsSequence) && !containsSequence) || p->hasMetaData("cpp:comparable"))
1799     {
1800         H << sp << nl << "bool operator==(const " << name << "& rhs_) const";
1801         H << sb;
1802         H << nl << "if(this == &rhs_)";
1803         H << sb;
1804         H << nl << "return true;";
1805         H << eb;
1806         for(vector<string>::const_iterator pi = params.begin(); pi != params.end(); ++pi)
1807         {
1808             H << nl << "if(" << *pi << " != rhs_." << *pi << ')';
1809             H << sb;
1810             H << nl << "return false;";
1811             H << eb;
1812         }
1813         H << nl << "return true;";
1814         H << eb;
1815         H << sp << nl << "bool operator<(const " << name << "& rhs_) const";
1816         H << sb;
1817         H << nl << "if(this == &rhs_)";
1818         H << sb;
1819         H << nl << "return false;";
1820         H << eb;
1821         for(vector<string>::const_iterator pi = params.begin(); pi != params.end(); ++pi)
1822         {
1823             H << nl << "if(" << *pi << " < rhs_." << *pi << ')';
1824             H << sb;
1825             H << nl << "return true;";
1826             H << eb;
1827             H << nl << "else if(rhs_." << *pi << " < " << *pi << ')';
1828             H << sb;
1829             H << nl << "return false;";
1830             H << eb;
1831         }
1832         H << nl << "return false;";
1833         H << eb;
1834 
1835         H << sp << nl << "bool operator!=(const " << name << "& rhs_) const";
1836         H << sb;
1837         H << nl << "return !operator==(rhs_);";
1838         H << eb;
1839         H << nl << "bool operator<=(const " << name << "& rhs_) const";
1840         H << sb;
1841         H << nl << "return operator<(rhs_) || operator==(rhs_);";
1842         H << eb;
1843         H << nl << "bool operator>(const " << name << "& rhs_) const";
1844         H << sb;
1845         H << nl << "return !operator<(rhs_) && !operator==(rhs_);";
1846         H << eb;
1847         H << nl << "bool operator>=(const " << name << "& rhs_) const";
1848         H << sb;
1849         H << nl << "return !operator<(rhs_);";
1850         H << eb;
1851     }
1852     H << eb << ';';
1853 
1854     if(findMetaData(p->getMetaData()) == "%class")
1855     {
1856         H << sp << nl << "typedef ::IceUtil::Handle< " << scoped << "> " << p->name() + "Ptr;";
1857     }
1858 
1859     _useWstring = resetUseWstring(_useWstringHist);
1860 }
1861 
1862 void
visitDataMember(const DataMemberPtr & p)1863 Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p)
1864 {
1865     ContainerPtr container = p->container();
1866     string name = fixKwd(p->name());
1867 
1868     string scope = "";
1869     StructPtr st = StructPtr::dynamicCast(container);
1870     if(st)
1871     {
1872         scope = fixKwd(st->scope());
1873     }
1874 
1875     ExceptionPtr ex = ExceptionPtr::dynamicCast(container);
1876     if(ex)
1877     {
1878         scope = fixKwd(ex->scope());
1879     }
1880 
1881     writeDocSummary(H, p);
1882     H << nl << typeToString(p->type(), p->optional(), scope, p->getMetaData(), _useWstring) << ' ' << name << ';';
1883 }
1884 
1885 void
visitSequence(const SequencePtr & p)1886 Slice::Gen::TypesVisitor::visitSequence(const SequencePtr& p)
1887 {
1888     string name = fixKwd(p->name());
1889     TypePtr type = p->type();
1890     ContainedPtr cont = ContainedPtr::dynamicCast(p->container());
1891     string scope = fixKwd(p->scope());
1892     string s = typeToString(type, scope, p->typeMetaData(), _useWstring);
1893     StringList metaData = p->getMetaData();
1894 
1895     string seqType = findMetaData(metaData, _useWstring);
1896     H << sp;
1897 
1898     writeDocSummary(H, p);
1899 
1900     if(!seqType.empty())
1901     {
1902         H << nl << "typedef " << seqType << ' ' << name << ';';
1903     }
1904     else
1905     {
1906         H << nl << "typedef ::std::vector<" << (s[0] == ':' ? " " : "") << s << "> " << name << ';';
1907     }
1908 }
1909 
1910 void
visitDictionary(const DictionaryPtr & p)1911 Slice::Gen::TypesVisitor::visitDictionary(const DictionaryPtr& p)
1912 {
1913     string name = fixKwd(p->name());
1914     ContainedPtr cont = ContainedPtr::dynamicCast(p->container());
1915     string scope = fixKwd(p->scope());
1916     string dictType = findMetaData(p->getMetaData());
1917 
1918     H << sp;
1919     writeDocSummary(H, p);
1920 
1921     if(dictType.empty())
1922     {
1923         //
1924         // A default std::map dictionary
1925         //
1926 
1927         TypePtr keyType = p->keyType();
1928         TypePtr valueType = p->valueType();
1929         string ks = typeToString(keyType, scope, p->keyMetaData(), _useWstring);
1930         if(ks[0] == ':')
1931         {
1932             ks.insert(0, " ");
1933         }
1934         string vs = typeToString(valueType, scope, p->valueMetaData(), _useWstring);
1935 
1936         H << nl << "typedef ::std::map<" << ks << ", " << vs << "> " << name << ';';
1937     }
1938     else
1939     {
1940         //
1941         // A custom dictionary
1942         //
1943         H << nl << "typedef " << dictType << ' ' << name << ';';
1944     }
1945 }
1946 
1947 void
visitEnum(const EnumPtr & p)1948 Slice::Gen::TypesVisitor::visitEnum(const EnumPtr& p)
1949 {
1950     string name = fixKwd(p->name());
1951     EnumeratorList enumerators = p->enumerators();
1952 
1953     string enumeratorPrefix = findMetaData(p->getMetaData()) == "%scoped" ? name : "";
1954 
1955     //
1956     // Check if any of the enumerators were assigned an explicit value.
1957     //
1958     const bool explicitValue = p->explicitValue();
1959 
1960     H << sp;
1961     writeDocSummary(H, p);
1962 
1963     H << nl << "enum " << name;
1964     H << sb;
1965 
1966     EnumeratorList::const_iterator en = enumerators.begin();
1967     while(en != enumerators.end())
1968     {
1969         writeDocSummary(H, *en);
1970         H << nl << fixKwd(enumeratorPrefix + (*en)->name());
1971         //
1972         // If any of the enumerators were assigned an explicit value, we emit
1973         // an explicit value for *all* enumerators.
1974         //
1975         if(explicitValue)
1976         {
1977             H << " = " << int64ToString((*en)->value());
1978         }
1979         if(++en != enumerators.end())
1980         {
1981             H << ',';
1982         }
1983     }
1984     H << eb << ';';
1985 }
1986 
1987 void
visitConst(const ConstPtr & p)1988 Slice::Gen::TypesVisitor::visitConst(const ConstPtr& p)
1989 {
1990     string scope = fixKwd(p->scope());
1991     H << sp;
1992     writeDocSummary(H, p);
1993     H << nl << "const " << typeToString(p->type(), scope, p->typeMetaData(), _useWstring) << " " << fixKwd(p->name())
1994       << " = ";
1995     writeConstantValue(H, p->type(), p->valueType(), p->value(), _useWstring, p->typeMetaData(), scope);
1996     H << ';';
1997 }
1998 
1999 void
emitUpcall(const ExceptionPtr & base,const string & call,const string & scope,bool isLocal)2000 Slice::Gen::TypesVisitor::emitUpcall(const ExceptionPtr& base, const string& call, const string& scope, bool isLocal)
2001 {
2002     C << nl;
2003     if(base)
2004     {
2005         C << getUnqualified(fixKwd(base->scoped()), scope);
2006     }
2007     else
2008     {
2009         C << getUnqualified(isLocal ? "::Ice::LocalException" : "::Ice::UserException", scope);
2010     }
2011     C << call;
2012 }
2013 
ProxyDeclVisitor(Output & h,Output &,const string & dllExport)2014 Slice::Gen::ProxyDeclVisitor::ProxyDeclVisitor(Output& h, Output&, const string& dllExport) :
2015     H(h), _dllExport(dllExport)
2016 {
2017 }
2018 
2019 bool
visitUnitStart(const UnitPtr & p)2020 Slice::Gen::ProxyDeclVisitor::visitUnitStart(const UnitPtr& p)
2021 {
2022     if(!p->hasNonLocalClassDecls())
2023     {
2024         return false;
2025     }
2026 
2027     H << sp << nl << "namespace IceProxy" << nl << '{';
2028 
2029     return true;
2030 }
2031 
2032 void
visitUnitEnd(const UnitPtr &)2033 Slice::Gen::ProxyDeclVisitor::visitUnitEnd(const UnitPtr&)
2034 {
2035     H << sp << nl << '}';
2036 }
2037 
2038 bool
visitModuleStart(const ModulePtr & p)2039 Slice::Gen::ProxyDeclVisitor::visitModuleStart(const ModulePtr& p)
2040 {
2041     if(!p->hasNonLocalClassDecls())
2042     {
2043         return false;
2044     }
2045 
2046     string name = fixKwd(p->name());
2047 
2048     H << sp << nl << "namespace " << name << nl << '{';
2049 
2050     return true;
2051 }
2052 
2053 void
visitModuleEnd(const ModulePtr &)2054 Slice::Gen::ProxyDeclVisitor::visitModuleEnd(const ModulePtr&)
2055 {
2056     H << sp << nl << '}';
2057 }
2058 
2059 void
visitClassDecl(const ClassDeclPtr & p)2060 Slice::Gen::ProxyDeclVisitor::visitClassDecl(const ClassDeclPtr& p)
2061 {
2062     if(p->isLocal())
2063     {
2064         return;
2065     }
2066 
2067     string name = fixKwd(p->name());
2068 
2069     H << sp << nl << "class " << name << ';';
2070     //
2071     // Underscore prefix because it's a private function that should not clash with
2072     // an interface named 'readProxy'
2073     // Note that _readProxy is always in the IceProxy::... namespace
2074     //
2075     H << nl << "/// \\cond INTERNAL";
2076     H << nl << _dllExport << "void _readProxy(::Ice::InputStream*, ::IceInternal::ProxyHandle< " << name << ">&);";
2077     H << nl << _dllExport << "::IceProxy::Ice::Object* upCast(" << name << "*);";
2078     H << nl << "/// \\endcond";
2079 }
2080 
ProxyVisitor(Output & h,Output & c,const string & dllExport)2081 Slice::Gen::ProxyVisitor::ProxyVisitor(Output& h, Output& c, const string& dllExport) :
2082     H(h), C(c), _dllExport(dllExport), _dllClassExport(toDllClassExport(dllExport)),
2083     _dllMemberExport(toDllMemberExport(dllExport)), _useWstring(false)
2084 {
2085 }
2086 
2087 bool
visitUnitStart(const UnitPtr & p)2088 Slice::Gen::ProxyVisitor::visitUnitStart(const UnitPtr& p)
2089 {
2090     if(!p->hasNonLocalClassDefs())
2091     {
2092         return false;
2093     }
2094 
2095     H << sp << nl << "namespace IceProxy" << nl << '{';
2096 
2097     return true;
2098 }
2099 
2100 void
visitUnitEnd(const UnitPtr &)2101 Slice::Gen::ProxyVisitor::visitUnitEnd(const UnitPtr&)
2102 {
2103     H << sp << nl << '}';
2104 }
2105 
2106 bool
visitModuleStart(const ModulePtr & p)2107 Slice::Gen::ProxyVisitor::visitModuleStart(const ModulePtr& p)
2108 {
2109     if(!p->hasNonLocalClassDefs())
2110     {
2111         return false;
2112     }
2113 
2114     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
2115 
2116     string name = fixKwd(p->name());
2117 
2118     H << sp << nl << "namespace " << name << nl << '{';
2119 
2120     return true;
2121 }
2122 
2123 void
visitModuleEnd(const ModulePtr &)2124 Slice::Gen::ProxyVisitor::visitModuleEnd(const ModulePtr&)
2125 {
2126     H << sp << nl << '}';
2127 
2128     _useWstring = resetUseWstring(_useWstringHist);
2129 }
2130 
2131 bool
visitClassDefStart(const ClassDefPtr & p)2132 Slice::Gen::ProxyVisitor::visitClassDefStart(const ClassDefPtr& p)
2133 {
2134     if(p->isLocal())
2135     {
2136         return false;
2137     }
2138 
2139     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
2140 
2141     string name = fixKwd(p->name());
2142     string scope = fixKwd(p->scope());
2143     string scoped = fixKwd(p->scoped());
2144     ClassList bases = p->bases();
2145 
2146     if(bases.size() > 1)
2147     {
2148         //
2149         // Generated helper class to deal with multiple inheritance
2150         // when using Proxy template.
2151         //
2152 
2153         string baseName = fixKwd("_" + p->name() + "Base");
2154 
2155         H << sp;
2156         H << nl << "/// \\cond INTERNAL";
2157         H << nl << "class " << _dllClassExport << baseName << " : ";
2158         H.useCurrentPosAsIndent();
2159         for(ClassList::const_iterator q = bases.begin(); q != bases.end();)
2160         {
2161             H << "public virtual ::IceProxy" << fixKwd((*q)->scoped());
2162             if(++q != bases.end())
2163             {
2164                 H << ", " << nl;
2165             }
2166         }
2167         H.restoreIndent();
2168         H << sb;
2169 
2170         H.dec();
2171         H << nl << "public:";
2172         H.inc();
2173 
2174         // Out of line dtor to avoid weak vtable
2175         H << sp << nl << _dllMemberExport << "virtual ~" << baseName << "();";
2176         C << sp;
2177         C << nl << "::IceProxy" << scope << baseName << "::~" << baseName << "()";
2178         C << sb;
2179         C << eb;
2180 
2181         H.dec();
2182         H << sp << nl << "protected:";
2183         H.inc();
2184 
2185         H << sp << nl << "virtual Object* _newInstance() const = 0;";
2186         H << eb << ';';
2187         H << nl << "/// \\endcond";
2188     }
2189 
2190     H << sp << nl << "class " << _dllClassExport << name << " : ";
2191     H << "public virtual ::Ice::Proxy<" << name << ", ";
2192     if(bases.empty())
2193     {
2194         H << "::IceProxy::Ice::Object";
2195     }
2196     else if(bases.size() == 1)
2197     {
2198         H << "::IceProxy" << fixKwd(bases.front()->scoped());
2199     }
2200     else
2201     {
2202         H << fixKwd("_" + p->name() + "Base");
2203     }
2204     H << ">";
2205 
2206     H << sb;
2207     H.dec();
2208     H << nl << "public:";
2209     H.inc();
2210 
2211     C << sp;
2212     C << nl << "/// \\cond INTERNAL";
2213     C << nl
2214       << _dllExport
2215       << "::IceProxy::Ice::Object* ::IceProxy" << scope << "upCast(" << name << "* p) { return p; }";
2216 
2217     C << sp;
2218     C << nl << "void" << nl << "::IceProxy" << scope << "_readProxy(::Ice::InputStream* istr, "
2219       << "::IceInternal::ProxyHandle< " << name << ">& v)";
2220     C << sb;
2221     C << nl << "::Ice::ObjectPrx proxy;";
2222     C << nl << "istr->read(proxy);";
2223     C << nl << "if(!proxy)";
2224     C << sb;
2225     C << nl << "v = 0;";
2226     C << eb;
2227     C << nl << "else";
2228     C << sb;
2229     C << nl << "v = new " << name << ';';
2230     C << nl << "v->_copyFrom(proxy);";
2231     C << eb;
2232     C << eb;
2233     C << nl << "/// \\endcond";
2234 
2235     return true;
2236 }
2237 
2238 void
visitClassDefEnd(const ClassDefPtr & p)2239 Slice::Gen::ProxyVisitor::visitClassDefEnd(const ClassDefPtr& p)
2240 {
2241     string name = fixKwd(p->name());
2242     string scoped = fixKwd(p->scoped());
2243     string scope = fixKwd(p->scope());
2244 
2245     H << sp;
2246     H << nl << "/**";
2247     H << nl << " * Obtains the Slice type ID corresponding to this " << (p->isInterface() ? "interface" : "class")
2248       << ".";
2249     H << nl << " * @return A fully-scoped type ID.";
2250     H << nl << " */";
2251     H << nl << _dllMemberExport << "static const ::std::string& ice_staticId();";
2252 
2253     H.dec();
2254     H << sp << nl << "protected:";
2255     H.inc();
2256     H << nl << "/// \\cond INTERNAL";
2257     H << sp << nl << _dllMemberExport << "virtual ::IceProxy::Ice::Object* _newInstance() const;";
2258     H << nl << "/// \\endcond";
2259     H << eb << ';';
2260 
2261     C << sp;
2262     C << nl << "/// \\cond INTERNAL";
2263     C << nl << "::IceProxy::Ice::Object*";
2264     C << nl << "IceProxy" << scoped << "::_newInstance() const";
2265     C << sb;
2266     C << nl << "return new " << name << ";";
2267     C << eb;
2268     C << nl << "/// \\endcond";
2269 
2270     C << sp;
2271     C << nl << "const ::std::string&" << nl << "IceProxy" << scoped << "::ice_staticId()";
2272     C << sb;
2273     C << nl << "return " << scoped << "::ice_staticId();";
2274     C << eb;
2275 
2276     _useWstring = resetUseWstring(_useWstringHist);
2277 }
2278 
2279 namespace
2280 {
2281 
2282 bool
usePrivateEnd(const OperationPtr & p)2283 usePrivateEnd(const OperationPtr& p)
2284 {
2285     TypePtr ret = p->returnType();
2286     bool retIsOpt = p->returnIsOptional();
2287     string retSEnd = returnTypeToString(ret, retIsOpt, "", p->getMetaData(), TypeContextAMIEnd);
2288     string retSPrivateEnd = returnTypeToString(ret, retIsOpt, "", p->getMetaData(), TypeContextAMIPrivateEnd);
2289 
2290     ParamDeclList outParams;
2291     vector<string> outDeclsEnd;
2292     vector<string> outDeclsPrivateEnd;
2293 
2294     ParamDeclList paramList = p->parameters();
2295     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
2296     {
2297         if((*q)->isOutParam())
2298         {
2299             outDeclsEnd.push_back(outputTypeToString((*q)->type(), (*q)->optional(), "", (*q)->getMetaData(),
2300                                                      TypeContextAMIEnd));
2301             outDeclsPrivateEnd.push_back(outputTypeToString((*q)->type(), (*q)->optional(), "", (*q)->getMetaData(),
2302                                                             TypeContextAMIPrivateEnd));
2303         }
2304     }
2305 
2306     return retSEnd != retSPrivateEnd || outDeclsEnd != outDeclsPrivateEnd;
2307 }
2308 
2309 }
2310 
2311 void
visitOperation(const OperationPtr & p)2312 Slice::Gen::ProxyVisitor::visitOperation(const OperationPtr& p)
2313 {
2314     string name = p->name();
2315     string flatName = "iceC" + p->flattenedScope() + p->name() + "_name";
2316     string scoped = fixKwd(p->scoped());
2317     string scope = fixKwd(p->scope());
2318 
2319     TypePtr ret = p->returnType();
2320 
2321     bool retIsOpt = p->returnIsOptional();
2322     string retS = returnTypeToString(ret, retIsOpt, "", p->getMetaData(), _useWstring | TypeContextAMIEnd);
2323     string retSEndAMI =
2324         returnTypeToString(ret, retIsOpt, "", p->getMetaData(), _useWstring | TypeContextAMIPrivateEnd);
2325     string retInS = retS != "void" ? inputTypeToString(ret, retIsOpt, "", p->getMetaData(), _useWstring) : "";
2326 
2327     ContainerPtr container = p->container();
2328     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
2329     string clName = cl->name();
2330     string clScope = fixKwd(cl->scope());
2331     string delName = "Callback_" + clName + "_" + name;
2332     string delNameScoped = clScope + delName;
2333 
2334     vector<string> paramsDecl;
2335     vector<string> args;
2336 
2337     vector<string> paramsAMI;
2338     vector<string> paramsDeclAMI;
2339     vector<string> paramsDeclAMIBeginI;
2340     vector<string> argsAMI;
2341     vector<string> outParamsAMI;
2342     vector<string> outParamNamesAMI;
2343     vector<string> outParamsDeclAMI;
2344     vector<string> outParamsDeclImplAMI;
2345     vector<string> outParamsDeclEndAMI;
2346     vector<string> outDecls;
2347 
2348     ParamDeclList paramList = p->parameters();
2349     ParamDeclList inParams = p->inParameters();
2350     ParamDeclList outParams = p->outParameters();
2351 
2352     const string contextParam = escapeParam(paramList, "context");
2353     const string cbParam = escapeParam(inParams, "cb");
2354     const string cookieParam = escapeParam(paramList, "cookie");
2355     const string resultParam = escapeParam(outParams, "result");
2356 
2357     vector<string> outEndArgs;
2358 
2359     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
2360     {
2361         string paramName = fixKwd((*q)->name());
2362 
2363         StringList metaData = (*q)->getMetaData();
2364         string typeString;
2365         string typeStringEndAMI;
2366         if((*q)->isOutParam())
2367         {
2368             typeString =
2369                 outputTypeToString((*q)->type(), (*q)->optional(), "", metaData, _useWstring | TypeContextAMIEnd);
2370             typeStringEndAMI = outputTypeToString((*q)->type(), (*q)->optional(), "", metaData,
2371                                                   _useWstring | TypeContextAMIPrivateEnd);
2372         }
2373         else
2374         {
2375             typeString = inputTypeToString((*q)->type(), (*q)->optional(), "", metaData, _useWstring);
2376         }
2377 
2378         paramsDecl.push_back(typeString + ' ' + paramName);
2379         args.push_back(paramName);
2380 
2381         if(!(*q)->isOutParam())
2382         {
2383             paramsAMI.push_back(typeString);
2384             paramsDeclAMI.push_back(typeString + ' ' + paramName);
2385             paramsDeclAMIBeginI.push_back(typeString + ' ' + paramPrefix + (*q)->name());
2386             argsAMI.push_back(paramName);
2387         }
2388         else
2389         {
2390             outParamsAMI.push_back(typeString);
2391             outParamNamesAMI.push_back(paramName);
2392             outParamsDeclAMI.push_back(typeString + ' ' + paramName);
2393             outParamsDeclImplAMI.push_back(typeString + ' ' + paramPrefix + (*q)->name());
2394             outParamsDeclEndAMI.push_back(typeStringEndAMI + ' ' + paramPrefix + (*q)->name());
2395             outDecls.push_back(
2396                 inputTypeToString((*q)->type(), (*q)->optional(), "", (*q)->getMetaData(), _useWstring));
2397             outEndArgs.push_back(getEndArg((*q)->type(), (*q)->getMetaData(), outParamNamesAMI.back()));
2398         }
2399     }
2400 
2401     //
2402     // Check if we need to generate a private _iceI_end_ method. This is the case if the
2403     // when using certain mapping features such as cpp:array. While
2404     // the regular end_ method can't return pair<const TYPE*, const TYPE*> because the
2405     // pointers would be invalid once end_ returns, we still want to allow using this
2406     // alternate mapping with AMI response callbacks (to allow zero-copy for instance).
2407     // For this purpose, we generate a special _iceI_end method which is used by the
2408     // completed implementation of the generated Callback_Inft_opName operation
2409     // delegate.
2410     //
2411     bool generatePrivateEnd = retS != retSEndAMI || outParamsDeclAMI != outParamsDeclEndAMI;
2412     if(ret && generatePrivateEnd)
2413     {
2414         string typeStringEndAMI = outputTypeToString(ret, p->returnIsOptional(), "", p->getMetaData(),
2415                                                      _useWstring | TypeContextAMIPrivateEnd);
2416         outParamsDeclEndAMI.push_back(typeStringEndAMI + ' ' + "ret");
2417     }
2418 
2419     string thisPointer = fixKwd(scope.substr(0, scope.size() - 2)) + "*";
2420 
2421     CommentPtr comment = p->parseComment(false);
2422     const string contextDoc = "@param " + contextParam + " The Context map to send with the invocation.";
2423     const string contextDecl = "const ::Ice::Context& " + contextParam + " = ::Ice::noExplicitContext";
2424     const string resultDoc = "The asynchronous result object for the invocation.";
2425     const string cbDoc = "@param " + cbParam + " Asynchronous callback object.";
2426     const string cookieDoc = "@param " + cookieParam + " User-defined data to associate with the invocation.";
2427     const string cookieDecl = "const ::Ice::LocalObjectPtr& " + cookieParam + " = 0";
2428 
2429     const string deprecateSymbol = getDeprecateSymbol(p, cl);
2430     H << sp;
2431     if(comment)
2432     {
2433         StringList postParams;
2434         postParams.push_back(contextDoc);
2435         writeOpDocSummary(H, p, comment, OpDocAllParams, true, StringList(), postParams, comment->returns());
2436     }
2437     H << nl << deprecateSymbol << _dllMemberExport << retS << ' ' << fixKwd(name) << spar << paramsDecl
2438       << contextDecl << epar;
2439     H << sb << nl;
2440     if(ret)
2441     {
2442         H << "return ";
2443     }
2444     H << "end_" << name << spar << outParamNamesAMI << "_iceI_begin_" + name << spar << argsAMI;
2445     H << contextParam << "::IceInternal::dummyCallback" << "0" << "true" << epar << epar << ';';
2446     H << eb;
2447 
2448     H << sp;
2449     if(comment)
2450     {
2451         StringList postParams, returns;
2452         postParams.push_back(contextDoc);
2453         returns.push_back(resultDoc);
2454         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
2455     }
2456     H << nl << "::Ice::AsyncResultPtr begin_" << name << spar << paramsDeclAMI << contextDecl << epar;
2457     H << sb;
2458     H << nl << "return _iceI_begin_" << name << spar << argsAMI << contextParam << "::IceInternal::dummyCallback"
2459       << "0"
2460       << epar << ';';
2461     H << eb;
2462 
2463     H << sp;
2464     if(comment)
2465     {
2466         StringList postParams, returns;
2467         postParams.push_back(cbDoc);
2468         postParams.push_back(cookieDoc);
2469         returns.push_back(resultDoc);
2470         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
2471     }
2472     H << nl << "::Ice::AsyncResultPtr begin_" << name << spar << paramsDeclAMI
2473       << "const ::Ice::CallbackPtr& " + cbParam
2474       << cookieDecl << epar;
2475     H << sb;
2476     H << nl << "return _iceI_begin_" << name << spar << argsAMI << "::Ice::noExplicitContext" << cbParam << cookieParam
2477       << epar << ';';
2478     H << eb;
2479 
2480     H << sp;
2481     if(comment)
2482     {
2483         StringList postParams, returns;
2484         postParams.push_back(contextDoc);
2485         postParams.push_back(cbDoc);
2486         postParams.push_back(cookieDoc);
2487         returns.push_back(resultDoc);
2488         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
2489     }
2490     H << nl << "::Ice::AsyncResultPtr begin_" << name << spar << paramsDeclAMI
2491       << "const ::Ice::Context& " + contextParam
2492       << "const ::Ice::CallbackPtr& " + cbParam
2493       << cookieDecl << epar;
2494     H << sb;
2495     H << nl << "return _iceI_begin_" << name << spar << argsAMI << contextParam << cbParam << cookieParam << epar
2496       << ';';
2497     H << eb;
2498 
2499     H << sp;
2500     if(comment)
2501     {
2502         StringList postParams, returns;
2503         postParams.push_back(cbDoc);
2504         postParams.push_back(cookieDoc);
2505         returns.push_back(resultDoc);
2506         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
2507     }
2508     H << nl << "::Ice::AsyncResultPtr begin_" << name << spar << paramsDeclAMI
2509       << "const " + delNameScoped + "Ptr& " + cbParam
2510       << cookieDecl << epar;
2511     H << sb;
2512     H << nl << "return _iceI_begin_" << name << spar << argsAMI << "::Ice::noExplicitContext" << cbParam << cookieParam
2513       << epar << ';';
2514     H << eb;
2515 
2516     H << sp;
2517     if(comment)
2518     {
2519         StringList postParams, returns;
2520         postParams.push_back(contextDoc);
2521         postParams.push_back(cbDoc);
2522         postParams.push_back(cookieDoc);
2523         returns.push_back(resultDoc);
2524         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
2525     }
2526     H << nl << "::Ice::AsyncResultPtr begin_" << name << spar << paramsDeclAMI
2527       << "const ::Ice::Context& " + contextParam
2528       << "const " + delNameScoped + "Ptr& " + cbParam
2529       << cookieDecl << epar;
2530     H << sb;
2531     H << nl << "return _iceI_begin_" << name << spar << argsAMI << contextParam << cbParam << cookieParam << epar
2532       << ';';
2533     H << eb;
2534 
2535     H << sp;
2536     if(comment)
2537     {
2538         H << nl << "/**";
2539         H << nl << " * Completes an invocation of begin_" << name << ".";
2540         StringList postParams;
2541         postParams.push_back("@param " + resultParam + " " + resultDoc);
2542         writeOpDocParams(H, p, comment, OpDocOutParams, StringList(), postParams);
2543         if(!comment->returns().empty())
2544         {
2545             H << nl << " * @return ";
2546             writeDocLines(H, comment->returns(), false);
2547         }
2548         if(!comment->exceptions().empty())
2549         {
2550             writeOpDocExceptions(H, p, comment);
2551         }
2552         H << nl << " */";
2553     }
2554     H << nl << _dllMemberExport << retS << " end_" << name << spar << outParamsDeclAMI
2555       << "const ::Ice::AsyncResultPtr& " + resultParam << epar << ';';
2556     if(generatePrivateEnd)
2557     {
2558         H << nl << "/// \\cond INTERNAL";
2559         H << sp << nl << _dllMemberExport << "void _iceI_end_" << name << spar << outParamsDeclEndAMI;
2560         H << "const ::Ice::AsyncResultPtr&" << epar << ';';
2561         H << nl << "/// \\endcond";
2562     }
2563 
2564     H.dec();
2565     H << nl;
2566     H << nl << "private:";
2567     H.inc();
2568     H << sp << nl << _dllMemberExport << "::Ice::AsyncResultPtr _iceI_begin_" << name << spar
2569       << paramsAMI << "const ::Ice::Context&"
2570       << "const ::IceInternal::CallbackBasePtr&"
2571       << "const ::Ice::LocalObjectPtr& cookie = 0"
2572       << "bool sync = false" << epar << ';';
2573     H.dec();
2574     H << nl;
2575     H << nl << "public:";
2576     H.inc();
2577 
2578     C << sp << nl << "::Ice::AsyncResultPtr" << nl << "IceProxy" << scope << "_iceI_begin_" << name << spar
2579       << paramsDeclAMIBeginI
2580       << "const ::Ice::Context& context" << "const ::IceInternal::CallbackBasePtr& del"
2581       << "const ::Ice::LocalObjectPtr& cookie" << "bool sync" << epar;
2582     C << sb;
2583     if(p->returnsData())
2584     {
2585         C << nl << "_checkTwowayOnly(" << flatName <<  ", sync);";
2586     }
2587     C << nl << "::IceInternal::OutgoingAsyncPtr result = new ::IceInternal::CallbackOutgoing(this, " << flatName
2588         << ", del, cookie, sync);";
2589     C << nl << "try";
2590     C << sb;
2591     C << nl << "result->prepare(" << flatName << ", " << operationModeToString(p->sendMode()) << ", context);";
2592     if(inParams.empty())
2593     {
2594         C << nl << "result->writeEmptyParams();";
2595     }
2596     else
2597     {
2598         C << nl << "::Ice::OutputStream* ostr = result->startWriteParams(" << opFormatTypeToString(p, false) <<");";
2599         writeMarshalCode(C, inParams, 0, true, TypeContextInParam);
2600         if(p->sendsClasses(false))
2601         {
2602             C << nl << "ostr->writePendingValues();";
2603         }
2604         C << nl << "result->endWriteParams();";
2605     }
2606     C << nl << "result->invoke(" << flatName << ");";
2607     C << eb;
2608     C << nl << "catch(const ::Ice::Exception& ex)";
2609     C << sb;
2610     C << nl << "result->abort(ex);";
2611     C << eb;
2612     C << nl << "return result;";
2613     C << eb;
2614 
2615     C << sp << nl << retS << nl << "IceProxy" << scope << "end_" << name << spar << outParamsDeclImplAMI
2616       << "const ::Ice::AsyncResultPtr& result" << epar;
2617     C << sb;
2618     if(p->returnsData())
2619     {
2620         C << nl << "::Ice::AsyncResult::_check(result, this, " << flatName << ");";
2621 
2622         //
2623         // COMPILERFIX: It's necessary to generate the allocate code here before
2624         // this if(!result->wait()). If generated after this if block, we get
2625         // access violations errors with the test/Ice/slicing/objects test on VC9
2626         // and Windows 64 bits when compiled with optimization (see bug 4400).
2627         //
2628         writeAllocateCode(C, ParamDeclList(), p, true, "", _useWstring | TypeContextAMIEnd);
2629         C << nl << "if(!result->_waitForResponse())";
2630         C << sb;
2631         C << nl << "try";
2632         C << sb;
2633         C << nl << "result->_throwUserException();";
2634         C << eb;
2635         //
2636         // Generate a catch block for each legal user exception.
2637         //
2638         ExceptionList throws = p->throws();
2639         throws.sort();
2640         throws.unique();
2641 #if defined(__SUNPRO_CC)
2642         throws.sort(derivedToBaseCompare);
2643 #else
2644         throws.sort(Slice::DerivedToBaseCompare());
2645 #endif
2646         for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i)
2647         {
2648             C << nl << "catch(const " << fixKwd((*i)->scoped()) << "&)";
2649             C << sb;
2650             C << nl << "throw;";
2651             C << eb;
2652         }
2653         C << nl << "catch(const ::Ice::UserException& ex)";
2654         C << sb;
2655         C << nl << "throw ::Ice::UnknownUserException(__FILE__, __LINE__, ex.ice_id());";
2656         C << eb;
2657         C << eb;
2658         if(ret || !outParams.empty())
2659         {
2660             C << nl << "::Ice::InputStream* istr = result->_startReadParams();";
2661             writeUnmarshalCode(C, outParams, p, true, _useWstring | TypeContextAMIEnd);
2662             if(p->returnsClasses(false))
2663             {
2664                 C << nl << "istr->readPendingValues();";
2665             }
2666             C << nl << "result->_endReadParams();";
2667         }
2668         else
2669         {
2670             C << nl << "result->_readEmptyParams();";
2671         }
2672         if(ret)
2673         {
2674             C << nl << "return ret;";
2675         }
2676     }
2677     else
2678     {
2679         C << nl << "_end(result, " << flatName << ");";
2680     }
2681     C << eb;
2682 
2683     if(generatePrivateEnd)
2684     {
2685         assert(p->returnsData());
2686 
2687         C << sp << nl << "void IceProxy" << scope << "_iceI_end_" << name << spar << outParamsDeclEndAMI
2688           << "const ::Ice::AsyncResultPtr& result" << epar;
2689         C << sb;
2690         C << nl << "::Ice::AsyncResult::_check(result, this, " << flatName << ");";
2691         C << nl << "if(!result->_waitForResponse())";
2692         C << sb;
2693         C << nl << "try";
2694         C << sb;
2695         C << nl << "result->_throwUserException();";
2696         C << eb;
2697         //
2698         // Generate a catch block for each legal user exception.
2699         //
2700         ExceptionList throws = p->throws();
2701         throws.sort();
2702         throws.unique();
2703 #if defined(__SUNPRO_CC)
2704         throws.sort(derivedToBaseCompare);
2705 #else
2706         throws.sort(Slice::DerivedToBaseCompare());
2707 #endif
2708         for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i)
2709         {
2710             C << nl << "catch(const " << fixKwd((*i)->scoped()) << "&)";
2711             C << sb;
2712             C << nl << "throw;";
2713             C << eb;
2714         }
2715         C << nl << "catch(const ::Ice::UserException& ex)";
2716         C << sb;
2717         C << nl << "throw ::Ice::UnknownUserException(__FILE__, __LINE__, ex.ice_id());";
2718         C << eb;
2719         C << eb;
2720 
2721         if(ret || !outParams.empty())
2722         {
2723             C << nl << "::Ice::InputStream* istr = result->_startReadParams();";
2724             writeUnmarshalCode(C, outParams, p, true, _useWstring | TypeContextAMIPrivateEnd);
2725             if(p->returnsClasses(false))
2726             {
2727                 C << nl << "istr->readPendingValues();";
2728             }
2729             C << nl << "result->_endReadParams();";
2730         }
2731         else
2732         {
2733             C << nl << "result->_readEmptyParams();";
2734         }
2735         C << eb;
2736     }
2737 }
2738 
ObjectDeclVisitor(Output & h,Output & c,const string & dllExport)2739 Slice::Gen::ObjectDeclVisitor::ObjectDeclVisitor(Output& h, Output& c, const string& dllExport) :
2740     H(h), C(c), _dllExport(dllExport)
2741 {
2742 }
2743 
2744 bool
visitModuleStart(const ModulePtr & p)2745 Slice::Gen::ObjectDeclVisitor::visitModuleStart(const ModulePtr& p)
2746 {
2747     if(!p->hasClassDecls())
2748     {
2749         return false;
2750     }
2751 
2752     string name = fixKwd(p->name());
2753 
2754     H << sp << nl << "namespace " << name << nl << '{';
2755     C << sp << nl << "namespace" << nl << "{";
2756     return true;
2757 }
2758 
2759 void
visitModuleEnd(const ModulePtr &)2760 Slice::Gen::ObjectDeclVisitor::visitModuleEnd(const ModulePtr&)
2761 {
2762     H << sp << nl << '}';
2763     C << sp << nl << "}";
2764 }
2765 
2766 void
visitClassDecl(const ClassDeclPtr & p)2767 Slice::Gen::ObjectDeclVisitor::visitClassDecl(const ClassDeclPtr& p)
2768 {
2769     string name = fixKwd(p->name());
2770     string scope = fixKwd(p->scope());
2771     string scoped = fixKwd(p->scoped());
2772 
2773     H << sp << nl << "class " << name << ';';
2774     if(!p->isLocal())
2775     {
2776         //
2777         // upCast is not _upCast nor _iceUpCast for historical reasons. IceInternal::Handle
2778         // depends on this name
2779         //
2780         H << nl << "/// \\cond INTERNAL";
2781         H << nl << _dllExport << getUnqualified("::Ice::Object*", scope) << " upCast(" << name << "*);";
2782         H << nl << "/// \\endcond";
2783         H << nl << "typedef ::IceInternal::Handle< " << name << "> " << p->name() << "Ptr;";
2784         H << nl << "typedef ::IceInternal::ProxyHandle< ::IceProxy" << scoped << "> " << p->name() << "Prx;";
2785         H << nl << "typedef " << p->name() << "Prx " << p->name() << "PrxPtr;";
2786 
2787         //
2788         // _ice prefix because this function is in the Slice module namespace, where the user
2789         // is allowed to define classes, functions etc. that start with _.
2790         //
2791         H << nl << "/// \\cond INTERNAL";
2792         H << nl << _dllExport << "void _icePatchObjectPtr(" << p->name() << "Ptr&, const "
2793           << getUnqualified("::Ice::ObjectPtr&", scope) << ");";
2794         H << nl << "/// \\endcond";
2795     }
2796     else
2797     {
2798         H << nl << "/// \\cond INTERNAL";
2799         H << nl << _dllExport << getUnqualified("::Ice::LocalObject*", scope) << " upCast("
2800           << getUnqualified(scoped, scope) << "*);";
2801         H << nl << "/// \\endcond";
2802         H << nl << "typedef ::IceInternal::Handle< " << name << "> " << p->name() << "Ptr;";
2803     }
2804 }
2805 
2806 void
visitOperation(const OperationPtr & p)2807 Slice::Gen::ObjectDeclVisitor::visitOperation(const OperationPtr& p)
2808 {
2809     ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container());
2810     if(cl && !cl->isLocal())
2811     {
2812         string flatName = "iceC" + p->flattenedScope() + p->name() + "_name";
2813         C << sp << nl << "const ::std::string " << flatName << " = \"" << p->name() << "\";";
2814     }
2815 }
2816 
ObjectVisitor(Output & h,Output & c,const string & dllExport)2817 Slice::Gen::ObjectVisitor::ObjectVisitor(Output& h, Output& c, const string& dllExport) :
2818     H(h), C(c), _dllExport(dllExport), _doneStaticSymbol(false), _useWstring(false)
2819 {
2820 }
2821 
2822 bool
visitModuleStart(const ModulePtr & p)2823 Slice::Gen::ObjectVisitor::visitModuleStart(const ModulePtr& p)
2824 {
2825     if(!p->hasClassDefs())
2826     {
2827         return false;
2828     }
2829 
2830     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
2831 
2832     string name = fixKwd(p->name());
2833 
2834     H << sp << nl << "namespace " << name << nl << '{';
2835 
2836     return true;
2837 }
2838 
2839 void
visitModuleEnd(const ModulePtr &)2840 Slice::Gen::ObjectVisitor::visitModuleEnd(const ModulePtr&)
2841 {
2842     H << sp;
2843     H << nl << '}';
2844 
2845     _useWstring = resetUseWstring(_useWstringHist);
2846 }
2847 
2848 bool
visitClassDefStart(const ClassDefPtr & p)2849 Slice::Gen::ObjectVisitor::visitClassDefStart(const ClassDefPtr& p)
2850 {
2851     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
2852 
2853     string name = fixKwd(p->name());
2854     string scope = fixKwd(p->scope());
2855     string scoped = fixKwd(p->scoped());
2856     ClassList bases = p->bases();
2857     ClassDefPtr base;
2858     if(!bases.empty() && !bases.front()->isInterface())
2859     {
2860         base = bases.front();
2861     }
2862     DataMemberList dataMembers = p->dataMembers();
2863     DataMemberList allDataMembers = p->allDataMembers();
2864     bool basePreserved = p->inheritsMetaData("preserve-slice");
2865     bool preserved = basePreserved || p->hasMetaData("preserve-slice");
2866 
2867     H << sp;
2868     writeDocSummary(H, p);
2869     H << nl << "class " << _dllExport << name << " : ";
2870     H.useCurrentPosAsIndent();
2871     if(bases.empty())
2872     {
2873         H << "public virtual " << getUnqualified(p->isLocal() ? "::Ice::LocalObject" : "::Ice::Object", scope);
2874     }
2875     else
2876     {
2877         ClassList::const_iterator q = bases.begin();
2878         bool virtualInheritance = p->hasMetaData("cpp:virtual") || p->isInterface();
2879         while(q != bases.end())
2880         {
2881             if(virtualInheritance || (*q)->isInterface())
2882             {
2883                 H << "virtual ";
2884             }
2885 
2886             H << "public " << getUnqualified(fixKwd((*q)->scoped()), scope);
2887             if(++q != bases.end())
2888             {
2889                 H << ',' << nl;
2890             }
2891         }
2892     }
2893 
2894     bool hasBaseClass = !bases.empty() && !bases.front()->isInterface();
2895     bool override = !p->isLocal() && p->canBeCyclic() && (!hasBaseClass || !bases.front()->canBeCyclic());
2896     bool hasGCObjectBaseClass = basePreserved || override || preserved;
2897     if(!basePreserved && (override || preserved))
2898     {
2899         H << ", public ::IceInternal::GCObject";
2900     }
2901 
2902     H.restoreIndent();
2903     H << sb;
2904     H.dec();
2905     H << nl << "public:" << sp;
2906     H.inc();
2907 
2908     //
2909     // In C++, a nested type cannot have the same name as the enclosing type
2910     //
2911     if(!p->isLocal() && p->name() != "ProxyType")
2912     {
2913         H << nl << "typedef " << p->name() << "Prx ProxyType;";
2914     }
2915 
2916     if(p->name() != "PointerType")
2917     {
2918         H << nl << "typedef " << p->name() << "Ptr PointerType;";
2919     }
2920 
2921     H << sp << nl << "virtual ~" << name << "();";
2922     C << sp;
2923     C << nl << scoped.substr(2) << "::~" << name << "()";
2924     C << sb;
2925     C << eb;
2926 
2927     vector<string> params;
2928     vector<string> allParamDecls;
2929 
2930     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
2931     {
2932         params.push_back(fixKwd((*q)->name()));
2933     }
2934 
2935     for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
2936     {
2937         string typeName = inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring);
2938         allParamDecls.push_back(typeName + " " + fixKwd((*q)->name()));
2939     }
2940 
2941     if(!p->isInterface())
2942     {
2943         if(p->hasDefaultValues())
2944         {
2945             H << sp;
2946             H << nl << "/** Default constructor that assigns default values to members as specified in the "
2947               "Slice definition. */";
2948             H << nl << name << "() :";
2949             H.inc();
2950             writeDataMemberInitializers(H, dataMembers, _useWstring);
2951             H.dec();
2952             H << sb;
2953             H << eb;
2954         }
2955         else
2956         {
2957             H << sp << nl << name << "()";
2958             H << sb << eb;
2959         }
2960 
2961         emitOneShotConstructor(p);
2962     }
2963 
2964     if(!p->isLocal())
2965     {
2966         C << sp;
2967         C << nl << "/// \\cond INTERNAL";
2968         C << nl
2969           << _dllExport
2970           << "::Ice::Object* " << scope.substr(2) << "upCast(" << name << "* p) { return p; }"
2971           << nl;
2972         C << nl << "/// \\endcond";
2973 
2974         //
2975         // It would make sense to provide a covariant ice_clone(); unfortunately many compilers
2976         // (including VS2010) generate bad code for covariant types that use virtual inheritance
2977         //
2978 
2979         if(!p->isInterface())
2980         {
2981             H << sp;
2982             H << nl << "/**";
2983             H << nl << " * Polymporphically clones this object.";
2984             H << nl << " * @return A shallow copy of this object.";
2985             H << nl << " */";
2986             H << nl << "virtual " << getUnqualified("::Ice::ObjectPtr", scope) << " ice_clone() const;";
2987 
2988             if(hasGCObjectBaseClass)
2989             {
2990                 C.zeroIndent();
2991                 C << sp;
2992                 C << nl << "#if defined(_MSC_VER) && (_MSC_VER >= 1900)";
2993                 C << nl << "#   pragma warning(push)";
2994                 C << nl << "#   pragma warning(disable:4589)";
2995                 C << nl << "#endif";
2996                 C.restoreIndent();
2997             }
2998             C << nl << "::Ice::ObjectPtr";
2999             C << nl << scoped.substr(2) << "::ice_clone() const";
3000             C << sb;
3001             if(!p->isAbstract())
3002             {
3003                 C << nl << getUnqualified("::Ice::Object*", scope) << " p = new " << name << "(*this);";
3004                 C << nl << "return p;";
3005             }
3006             else
3007             {
3008                 //
3009                 // We need this ice_clone for abstract classes derived from concrete classes
3010                 //
3011                 C << nl << "throw " << getUnqualified("::Ice::CloneNotImplementedException", scope)
3012                   << "(__FILE__, __LINE__);";
3013             }
3014             C << eb;
3015             if(hasGCObjectBaseClass)
3016             {
3017                 C.zeroIndent();
3018                 C << nl << "#if defined(_MSC_VER) && (_MSC_VER >= 1900)";
3019                 C << nl << "#   pragma warning(pop)";
3020                 C << nl << "#endif";
3021                 C.restoreIndent();
3022             }
3023         }
3024 
3025         ClassList allBases = p->allBases();
3026         StringList ids;
3027         transform(allBases.begin(), allBases.end(), back_inserter(ids), ::IceUtil::constMemFun(&Contained::scoped));
3028         StringList other;
3029         other.push_back(p->scoped());
3030         other.push_back("::Ice::Object");
3031         other.sort();
3032         ids.merge(other);
3033         ids.unique();
3034         StringList::const_iterator firstIter = ids.begin();
3035         StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), p->scoped());
3036         assert(scopedIter != ids.end());
3037         StringList::difference_type scopedPos = IceUtilInternal::distance(firstIter, scopedIter);
3038 
3039         H << sp;
3040         H << nl << "/**";
3041         H << nl << " * Determines whether this object supports an interface with the given Slice type ID.";
3042         H << nl << " * @param id The fully-scoped Slice type ID.";
3043         H << nl << " * @param current The Current object for the invocation.";
3044         H << nl << " * @return True if this object supports the interface, false, otherwise.";
3045         H << nl << " */";
3046         H << nl << "virtual bool ice_isA(const ::std::string& id, const " << getUnqualified("::Ice::Current&", scope)
3047           << " current = " << getUnqualified("::Ice::emptyCurrent", scope) << ") const;";
3048         H << sp;
3049         H << nl << "/**";
3050         H << nl << " * Obtains a list of the Slice type IDs representing the interfaces supported by this object.";
3051         H << nl << " * @param current The Current object for the invocation.";
3052         H << nl << " * @return A list of fully-scoped type IDs.";
3053         H << nl << " */";
3054         H << nl << "virtual ::std::vector< ::std::string> ice_ids(const " << getUnqualified("::Ice::Current&", scope)
3055           << " current = " << getUnqualified("::Ice::emptyCurrent", scope) << ") const;";
3056         H << sp;
3057         H << nl << "/**";
3058         H << nl << " * Obtains a Slice type ID representing the most-derived interface supported by this object.";
3059         H << nl << " * @param current The Current object for the invocation.";
3060         H << nl << " * @return A fully-scoped type ID.";
3061         H << nl << " */";
3062         H << nl << "virtual const ::std::string& ice_id(const " << getUnqualified("::Ice::Current&", scope)
3063           << " current = " << getUnqualified("::Ice::emptyCurrent", scope) << ") const;";
3064         H << sp;
3065         H << nl << "/**";
3066         H << nl << " * Obtains the Slice type ID corresponding to this class.";
3067         H << nl << " * @return A fully-scoped type ID.";
3068         H << nl << " */";
3069         H << nl << "static const ::std::string& ice_staticId();";
3070 
3071         string flatName = "iceC" + p->flattenedScope() + p->name() + "_ids";
3072 
3073         C << sp << nl << "namespace";
3074         C << nl << "{";
3075         C << nl << "const ::std::string " << flatName << '[' << ids.size() << "] =";
3076         C << sb;
3077 
3078         for(StringList::const_iterator r = ids.begin(); r != ids.end();)
3079         {
3080             C << nl << '"' << *r << '"';
3081             if(++r != ids.end())
3082             {
3083                 C << ',';
3084             }
3085         }
3086         C << eb << ';';
3087         C << sp << nl << "}";
3088 
3089         C << sp;
3090         C << nl << "bool" << nl << scoped.substr(2)
3091           << "::ice_isA(const ::std::string& s, const " << getUnqualified("::Ice::Current&", scope) << ") const";
3092         C << sb;
3093         C << nl << "return ::std::binary_search(" << flatName << ", " << flatName << " + " << ids.size() << ", s);";
3094         C << eb;
3095 
3096         C << sp;
3097         C << nl << "::std::vector< ::std::string>" << nl << scoped.substr(2)
3098           << "::ice_ids(const " << getUnqualified("::Ice::Current&", scope) << ") const";
3099         C << sb;
3100         C << nl << "return ::std::vector< ::std::string>(&" << flatName << "[0], &" << flatName
3101           << '[' << ids.size() << "]);";
3102         C << eb;
3103 
3104         C << sp;
3105         C << nl << "const ::std::string&" << nl << scoped.substr(2)
3106           << "::ice_id(const " << getUnqualified("::Ice::Current&", scope) << ") const";
3107         C << sb;
3108         C << nl << "return ice_staticId();";
3109         C << eb;
3110 
3111         C << sp;
3112         C << nl << "const ::std::string&" << nl << scoped.substr(2) << "::ice_staticId()";
3113         C << sb;
3114         C.zeroIndent();
3115         C << nl << "#ifdef ICE_HAS_THREAD_SAFE_LOCAL_STATIC";
3116         C.restoreIndent();
3117         C << nl << "static const ::std::string typeId = \"" << *scopedIter << "\";";
3118         C << nl << "return typeId;";
3119         C.zeroIndent();
3120         C << nl << "#else";
3121         C.restoreIndent();
3122         C << nl << "return " << flatName << '[' << scopedPos << "];";
3123         C.zeroIndent();
3124         C << nl << "#endif";
3125         C.restoreIndent();
3126         C << eb;
3127 
3128         emitGCFunctions(p);
3129     }
3130     else
3131     {
3132         C << sp;
3133         C << nl << "/// \\cond INTERNAL";
3134         C << nl
3135           << _dllExport
3136           << "::Ice::LocalObject* " << scope.substr(2) << "upCast(" << getUnqualified(scoped, scope)
3137           << "* p) { return p; }";
3138         C << nl << "/// \\endcond";
3139     }
3140 
3141     return true;
3142 }
3143 
3144 void
visitClassDefEnd(const ClassDefPtr & p)3145 Slice::Gen::ObjectVisitor::visitClassDefEnd(const ClassDefPtr& p)
3146 {
3147     string name = fixKwd(p->name());
3148     string scoped = fixKwd(p->scoped());
3149     string scope = fixKwd(p->scope());
3150     ClassList bases = p->bases();
3151     ClassDefPtr base;
3152     if(!bases.empty() && !bases.front()->isInterface())
3153     {
3154         base = bases.front();
3155     }
3156     bool basePreserved = p->inheritsMetaData("preserve-slice");
3157     bool preserved = p->hasMetaData("preserve-slice");
3158 
3159     bool inProtected = false;
3160 
3161     if(!p->isLocal())
3162     {
3163         OperationList allOps = p->allOperations();
3164         if(!allOps.empty())
3165         {
3166             StringList allOpNames;
3167             transform(allOps.begin(), allOps.end(), back_inserter(allOpNames),
3168                       ::IceUtil::constMemFun(&Contained::name));
3169 
3170             allOpNames.push_back("ice_id");
3171             allOpNames.push_back("ice_ids");
3172             allOpNames.push_back("ice_isA");
3173             allOpNames.push_back("ice_ping");
3174             allOpNames.sort();
3175             allOpNames.unique();
3176 
3177             H << sp;
3178             H << nl << "/// \\cond INTERNAL";
3179             H << nl << "virtual bool _iceDispatch(::IceInternal::Incoming&, const "
3180               << getUnqualified("::Ice::Current&", scope) << ");";
3181             H << nl << "/// \\endcond";
3182 
3183             string flatName = "iceC" + p->flattenedScope() + p->name() + "_all";
3184             C << sp << nl << "namespace";
3185             C << nl << "{";
3186             C << nl << "const ::std::string " << flatName << "[] =";
3187             C << sb;
3188 
3189             for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();)
3190             {
3191                 C << nl << '"' << *q << '"';
3192                 if(++q != allOpNames.end())
3193                 {
3194                     C << ',';
3195                 }
3196             }
3197             C << eb << ';';
3198             C << sp << nl << "}";
3199             C << sp;
3200             C << nl << "/// \\cond INTERNAL";
3201             C << nl << "bool";
3202             C << nl << scoped.substr(2) << "::_iceDispatch(::IceInternal::Incoming& in, const "
3203               << getUnqualified("::Ice::Current&", scope) << " current)";
3204             C << sb;
3205 
3206             C << nl << "::std::pair<const ::std::string*, const ::std::string*> r = "
3207               << "::std::equal_range(" << flatName << ", " << flatName << " + " << allOpNames.size()
3208               << ", current.operation);";
3209             C << nl << "if(r.first == r.second)";
3210             C << sb;
3211             C << nl << "throw " << getUnqualified("::Ice::OperationNotExistException", scope)
3212               << "(__FILE__, __LINE__, current.id, " << "current.facet, current.operation);";
3213             C << eb;
3214             C << sp;
3215             C << nl << "switch(r.first - " << flatName << ')';
3216             C << sb;
3217             int i = 0;
3218             for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end(); ++q)
3219             {
3220                 C << nl << "case " << i++ << ':';
3221                 C << sb;
3222                 C << nl << "return _iceD_" << *q << "(in, current);";
3223                 C << eb;
3224             }
3225             C << nl << "default:";
3226             C << sb;
3227             C << nl << "assert(false);";
3228             C << nl << "throw " << getUnqualified("::Ice::OperationNotExistException", scope)
3229               << "(__FILE__, __LINE__, current.id, " << "current.facet, current.operation);";
3230             C << eb;
3231             C << eb;
3232             C << eb;
3233             C << nl << "/// \\endcond";
3234 
3235             //
3236             // Check if we need to generate ice_operationAttributes()
3237             //
3238             map<string, int> attributesMap;
3239             for(OperationList::iterator r = allOps.begin(); r != allOps.end(); ++r)
3240             {
3241                 int attributes = (*r)->attributes();
3242                 if(attributes != 0)
3243                 {
3244                     attributesMap.insert(map<string, int>::value_type((*r)->name(), attributes));
3245                 }
3246             }
3247 
3248             if(!attributesMap.empty())
3249             {
3250                 H << sp;
3251                 H << nl << "/// \\cond INTERNAL";
3252                 H << nl << "virtual " << getUnqualified("::Ice::Int", scope)
3253                   << " ice_operationAttributes(const ::std::string&) const;";
3254                 H << nl << "/// \\endcond";
3255 
3256                 string opAttrFlatName = "iceC" + p->flattenedScope() + p->name() + "_operationAttributes";
3257 
3258                 C << sp << nl << "namespace";
3259                 C << nl << "{";
3260                 C << nl << "const int " << opAttrFlatName << "[] = ";
3261                 C << sb;
3262 
3263                 for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();)
3264                 {
3265                     int attributes = 0;
3266                     string opName = *q;
3267                     map<string, int>::iterator it = attributesMap.find(opName);
3268                     if(it != attributesMap.end())
3269                     {
3270                         attributes = it->second;
3271                     }
3272                     C << nl << attributes;
3273 
3274                     if(++q != allOpNames.end())
3275                     {
3276                         C << ',';
3277                     }
3278                     C << " // " << opName;
3279                 }
3280 
3281                 C << eb << ';';
3282                 C << sp << nl << "}";
3283 
3284                 C << sp;
3285 
3286                 C << nl << "::Ice::Int" << nl << scoped.substr(2)
3287                   << "::ice_operationAttributes(const ::std::string& opName) const";
3288                 C << sb;
3289 
3290                 C << nl << "::std::pair<const ::std::string*, const ::std::string*> r = "
3291                   << "::std::equal_range(" << flatName << ", " << flatName << " + " << allOpNames.size()
3292                   << ", opName);";
3293                 C << nl << "if(r.first == r.second)";
3294                 C << sb;
3295                 C << nl << "return -1;";
3296                 C << eb;
3297 
3298                 C << nl << "return " << opAttrFlatName << "[r.first - " << flatName << "];";
3299                 C << eb;
3300             }
3301         }
3302 
3303         if(!p->isAbstract())
3304         {
3305             H << sp;
3306             H << nl << "/**";
3307             H << nl << " * Obtains a value factory that instantiates this class.";
3308             H << nl << " * @return The value factory.";
3309             H << nl << " */";
3310             H << nl << "static " << getUnqualified("::Ice::ValueFactoryPtr", scope) << " ice_factory();";
3311         }
3312 
3313         if(preserved && !basePreserved)
3314         {
3315             H << sp;
3316             H << nl << "/**";
3317             H << nl << " * Obtains the SlicedData object created when an unknown class type was marshaled";
3318             H << nl << " * in the sliced format and the Ice run time sliced it to a known type.";
3319             H << nl << " * @return The SlicedData object, or nil if the class was not sliced or was not";
3320             H << nl << " * marshaled in the sliced format.";
3321             H << nl << " */";
3322             H << nl << "virtual " << getUnqualified("::Ice::SlicedDataPtr", scope) << " ice_getSlicedData() const;";
3323 
3324             H << sp;
3325             H << nl << "/// \\cond STREAM";
3326             H << nl << "virtual void _iceWrite(" << getUnqualified("::Ice::OutputStream*", scope) << ") const;";
3327             H << nl << "virtual void _iceRead(" << getUnqualified("::Ice::InputStream*", scope) << ");";
3328             H << nl << "/// \\endcond";
3329         }
3330 
3331         H.dec();
3332         H << sp << nl << "protected:";
3333         inProtected = true;
3334         H.inc();
3335 
3336         H << sp;
3337         H << nl << "/// \\cond STREAM";
3338         H << nl << "virtual void _iceWriteImpl(" << getUnqualified("::Ice::OutputStream*", scope) << ") const;";
3339         H << nl << "virtual void _iceReadImpl(" << getUnqualified("::Ice::InputStream*", scope) << ");";
3340         H << nl << "/// \\endcond";
3341 
3342         if(preserved && !basePreserved)
3343         {
3344             C << sp;
3345             C << nl << "::Ice::SlicedDataPtr" << nl << scoped.substr(2) << "::ice_getSlicedData() const";
3346             C << sb;
3347             C << nl << "return _iceSlicedData;";
3348             C << eb;
3349 
3350             C << sp;
3351             C << nl << "void" << nl << scoped.substr(2) << "::_iceWrite(" << getUnqualified("::Ice::OutputStream*", scope)
3352               << "ostr) const";
3353             C << sb;
3354             C << nl << "ostr->startValue(_iceSlicedData);";
3355             C << nl << "_iceWriteImpl(ostr);";
3356             C << nl << "ostr->endValue();";
3357             C << eb;
3358 
3359             C << sp;
3360             C << nl << "void" << nl << scoped.substr(2) << "::_iceRead(" << getUnqualified("::Ice::InputStream*", scope)
3361               << " istr)";
3362             C << sb;
3363             C << nl << "istr->startValue();";
3364             C << nl << "_iceReadImpl(istr);";
3365             C << nl << "_iceSlicedData = istr->endValue(true);";
3366             C << eb;
3367         }
3368 
3369         C << sp;
3370         C << nl << "/// \\cond STREAM";
3371         C << nl << "void" << nl << scoped.substr(2) << "::_iceWriteImpl(" << getUnqualified("::Ice::OutputStream*", scope)
3372           << " ostr) const";
3373         C << sb;
3374         C << nl << "ostr->startSlice(ice_staticId(), " << p->compactId() << (!base ? ", true" : ", false") << ");";
3375         C << nl << getUnqualified("::Ice::StreamWriter", scope) << "< " << name << ", "
3376           << getUnqualified("::Ice::OutputStream", scope) << ">::write(ostr, *this);";
3377         C << nl << "ostr->endSlice();";
3378         if(base)
3379         {
3380             emitUpcall(base, "::_iceWriteImpl(ostr);", scope);
3381         }
3382         C << eb;
3383 
3384         C << sp;
3385         C << nl << "void" << nl << scoped.substr(2) << "::_iceReadImpl(" << getUnqualified("::Ice::InputStream*", scope)
3386           << " istr)";
3387         C << sb;
3388         C << nl << "istr->startSlice();";
3389         C << nl << getUnqualified("::Ice::StreamReader", scope) << "< " << name << ", "
3390           << getUnqualified("::Ice::InputStream", scope) << ">::read(istr, *this);";
3391         C << nl << "istr->endSlice();";
3392         if(base)
3393         {
3394             emitUpcall(base, "::_iceReadImpl(istr);", scope);
3395         }
3396         C << eb;
3397         C << nl << "/// \\endcond";
3398 
3399         if(!p->isAbstract() || p->compactId() >= 0)
3400         {
3401             C << sp << nl << "namespace";
3402             C << nl << "{";
3403 
3404             if(!p->isAbstract())
3405             {
3406                 string initName = "iceC" + p->flattenedScope() + p->name() + "_init";
3407                 C << nl << "const ::IceInternal::DefaultValueFactoryInit< " << scoped << "> "
3408                   << initName << "(\"" << p->scoped() << "\");";
3409             }
3410             if(p->compactId() >= 0)
3411             {
3412                 string initName = "iceC" + p->flattenedScope() + p->name() + "_compactIdInit";
3413                 C << nl << "const ::IceInternal::CompactIdInit "
3414                   << initName << "(\"" << p->scoped() << "\", " << p->compactId() << ");";
3415             }
3416             C << nl << "}";
3417 
3418             if(!p->isAbstract())
3419             {
3420                 C << sp << nl << "::Ice::ValueFactoryPtr" << nl << scoped.substr(2) << "::ice_factory()";
3421                 C << sb;
3422                 C << nl << "return ::IceInternal::factoryTable->getValueFactory(" << scoped << "::ice_staticId());";
3423                 C << eb;
3424             }
3425         }
3426     }
3427 
3428     //
3429     // Emit data members. Access visibility may be specified by metadata.
3430     //
3431     bool generateFriend = false;
3432     DataMemberList dataMembers = p->dataMembers();
3433     bool prot = p->hasMetaData("protected");
3434     bool needSp = true;
3435     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
3436     {
3437         if(prot || (*q)->hasMetaData("protected"))
3438         {
3439             if(!inProtected)
3440             {
3441                 H.dec();
3442                 H << sp << nl << "protected:" << sp;
3443                 H.inc();
3444                 inProtected = true;
3445                 needSp = false;
3446             }
3447             generateFriend = true;
3448         }
3449         else
3450         {
3451             if(inProtected)
3452             {
3453                 H.dec();
3454                 H << sp << nl << "public:" << sp;
3455                 H.inc();
3456                 inProtected = false;
3457                 needSp = false;
3458             }
3459         }
3460 
3461         if(needSp)
3462         {
3463             H << sp;
3464             needSp = false;
3465         }
3466 
3467         emitDataMember(*q);
3468     }
3469 
3470     if(!p->isLocal() && preserved && !basePreserved)
3471     {
3472         if(!inProtected)
3473         {
3474             H.dec();
3475             H << sp << nl << "protected:";
3476             H.inc();
3477             inProtected = true;
3478         }
3479         H << sp;
3480         H << nl << "/// \\cond STREAM";
3481         H << nl << "::Ice::SlicedDataPtr _iceSlicedData;";
3482         H << nl << "/// \\endcond";
3483     }
3484 
3485     if(generateFriend)
3486     {
3487         if(!inProtected)
3488         {
3489             H.dec();
3490             H << sp << nl << "protected:";
3491             H.inc();
3492             inProtected = true;
3493         }
3494 
3495         H << sp;
3496         H << nl << "template<typename T, typename S>";
3497         H << nl << "friend struct Ice::StreamWriter;";
3498         H << nl << "template<typename T, typename S>";
3499         H << nl << "friend struct Ice::StreamReader;";
3500     }
3501 
3502     H << eb << ';';
3503 
3504     if(!p->isAbstract() && !p->isLocal() && !_doneStaticSymbol)
3505     {
3506         //
3507         // We need an instance here to trigger initialization if the implementation is in a static library.
3508         // But we do this only once per source file, because a single instance is sufficient to initialize
3509         // all of the globals in a compilation unit.
3510         //
3511         H << nl << "/// \\cond INTERNAL";
3512         H << nl << "static ::Ice::ValueFactoryPtr _iceS_" << p->name() << "_init = " << fixKwd(p->scoped())
3513           << "::ice_factory();";
3514         H << nl << "/// \\endcond";
3515     }
3516 
3517     if(p->isLocal())
3518     {
3519         H << sp;
3520         H << nl << "/// \\cond INTERNAL";
3521         H << nl << "inline bool operator==(const " << fixKwd(p->name()) << "& lhs, const " << fixKwd(p->name())
3522           << "& rhs)";
3523         H << sb;
3524         H << nl << "return static_cast<const " << getUnqualified("::Ice::LocalObject&", scope)
3525           << ">(lhs) == static_cast<const " << getUnqualified("::Ice::LocalObject&", scope) << ">(rhs);";
3526         H << eb;
3527         H << sp;
3528         H << nl << "inline bool operator<(const " << fixKwd(p->name()) << "& lhs, const " << fixKwd(p->name())
3529           << "& rhs)";
3530         H << sb;
3531         H << nl << "return static_cast<const " << getUnqualified("::Ice::LocalObject&", scope)
3532           << ">(lhs) < static_cast<const " << getUnqualified("::Ice::LocalObject&", scope) << ">(rhs);";
3533         H << eb;
3534         H << nl << "/// \\endcond";
3535     }
3536     else
3537     {
3538         C << sp;
3539         C << nl << "/// \\cond INTERNAL";
3540         C << nl << "void";
3541         C << nl << scope.substr(2) << "_icePatchObjectPtr(" << p->name() << "Ptr& handle, const "
3542           << getUnqualified("::Ice::ObjectPtr&", scope) << " v)";
3543         C << sb;
3544         C << nl << "handle = " << p->name() << "Ptr::dynamicCast(v);";
3545         C << nl << "if(v && !handle)";
3546         C << sb;
3547         C << nl << "IceInternal::Ex::throwUOE(" << name << "::ice_staticId(), v);";
3548         C << eb;
3549         C << eb;
3550         C << nl << "/// \\endcond";
3551 
3552         H << sp;
3553         H << nl << "/// \\cond INTERNAL";
3554         H << nl << "inline bool operator==(const " << fixKwd(p->name()) << "& lhs, const " << fixKwd(p->name())
3555           << "& rhs)";
3556         H << sb;
3557         H << nl << "return static_cast<const " << getUnqualified("::Ice::Object&", scope)
3558           << ">(lhs) == static_cast<const " << getUnqualified("::Ice::Object&", scope) << ">(rhs);";
3559         H << eb;
3560         H << sp;
3561         H << nl << "inline bool operator<(const " << fixKwd(p->name()) << "& lhs, const " << fixKwd(p->name())
3562           << "& rhs)";
3563         H << sb;
3564         H << nl << "return static_cast<const " << getUnqualified("::Ice::Object&", scope)
3565           << ">(lhs) < static_cast<const " << getUnqualified("::Ice::Object&", scope) << ">(rhs);";
3566         H << eb;
3567         H << nl << "/// \\endcond";
3568     }
3569 
3570     _useWstring = resetUseWstring(_useWstringHist);
3571 }
3572 
3573 bool
visitExceptionStart(const ExceptionPtr &)3574 Slice::Gen::ObjectVisitor::visitExceptionStart(const ExceptionPtr&)
3575 {
3576     return false;
3577 }
3578 
3579 bool
visitStructStart(const StructPtr &)3580 Slice::Gen::ObjectVisitor::visitStructStart(const StructPtr&)
3581 {
3582     return false;
3583 }
3584 
3585 void
visitOperation(const OperationPtr & p)3586 Slice::Gen::ObjectVisitor::visitOperation(const OperationPtr& p)
3587 {
3588     string name = p->name();
3589     string scoped = fixKwd(p->scoped());
3590     string scope = fixKwd(p->scope());
3591 
3592     ContainerPtr container = p->container();
3593     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
3594     string classNameAMD = "AMD_" + cl->name();
3595     string classScope = fixKwd(cl->scope());
3596     string classScopedAMD = classScope + classNameAMD;
3597 
3598     TypePtr ret = p->returnType();
3599     string retS = returnTypeToString(ret, p->returnIsOptional(), classScope, p->getMetaData(), _useWstring);
3600 
3601     ParamDeclList inParams = p->inParameters();
3602     ParamDeclList outParams = p->outParameters();
3603     ParamDeclList paramList = p->parameters();
3604 
3605     const string cbParam = escapeParam(paramList, "cb");
3606     const string cookieParam = escapeParam(paramList, "cookie");
3607     const string resultParam = escapeParam(outParams, "result");
3608     const string currentParam = escapeParam(paramList, "current");
3609 
3610     string params = "(";
3611     string paramsDecl = "(";
3612     string args = "(";
3613 
3614     string paramsAMD = "(const " + classScopedAMD + '_' + name + "Ptr& " + cbParam + ", ";
3615     string argsAMD = "(new IceAsync" + classScopedAMD + '_' + name + "(inS), ";
3616 
3617     vector< string> outDecls;
3618     for(ParamDeclList::iterator q = paramList.begin(); q != paramList.end(); ++q)
3619     {
3620         string paramName = fixKwd((*q)->name());
3621         TypePtr type = (*q)->type();
3622         bool isOutParam = (*q)->isOutParam();
3623         string typeString;
3624         if(isOutParam)
3625         {
3626             typeString = outputTypeToString(type, (*q)->optional(), classScope, (*q)->getMetaData(), _useWstring);
3627         }
3628         else
3629         {
3630             typeString =
3631                 inputTypeToString((*q)->type(), (*q)->optional(), classScope, (*q)->getMetaData(), _useWstring);
3632         }
3633 
3634         if(q != paramList.begin())
3635         {
3636             params += ", ";
3637             paramsDecl += ", ";
3638             args += ", ";
3639         }
3640 
3641         params += typeString;
3642         params += ' ';
3643         params += paramName;
3644         paramsDecl += typeString;
3645         paramsDecl += ' ';
3646         paramsDecl += paramName;
3647         args += paramPrefix + (*q)->name();
3648 
3649         if(!isOutParam)
3650         {
3651             paramsAMD += typeString;
3652             paramsAMD += " ";
3653             paramsAMD += paramName;
3654             paramsAMD += ", ";
3655             argsAMD += paramPrefix + (*q)->name();
3656             argsAMD += ", ";
3657         }
3658         else
3659         {
3660             outDecls.push_back(inputTypeToString((*q)->type(), (*q)->optional(), classScope, (*q)->getMetaData(),
3661                                                  _useWstring));
3662         }
3663     }
3664 
3665     if(!cl->isLocal())
3666     {
3667         if(!paramList.empty())
3668         {
3669             params += ", ";
3670             paramsDecl += ", ";
3671             args += ", ";
3672         }
3673 
3674         params += "const " + getUnqualified("::Ice::Current&", classScope) + " " + currentParam + " = " +
3675             getUnqualified("::Ice::emptyCurrent", classScope) + ")";
3676         paramsDecl += "const " + getUnqualified("::Ice::Current&", classScope) + " " + currentParam + ")";
3677         args += "current)";
3678     }
3679     else
3680     {
3681         params += ')';
3682         paramsDecl += ')';
3683         args += ')';
3684     }
3685 
3686     paramsAMD += "const " + getUnqualified("::Ice::Current&", classScope) + " " + currentParam + " = " +
3687         getUnqualified("::Ice::emptyCurrent", classScope) + ")";
3688     argsAMD += "current)";
3689 
3690     string isConst = ((p->mode() == Operation::Nonmutating) || p->hasMetaData("cpp:const")) ? " const" : "";
3691     string noExcept = (cl->isLocal() && p->hasMetaData("cpp:noexcept")) ? " ICE_NOEXCEPT" : "";
3692     bool amd = !cl->isLocal() && (cl->hasMetaData("amd") || p->hasMetaData("amd"));
3693 
3694     string deprecateSymbol = getDeprecateSymbol(p, cl);
3695 
3696     CommentPtr comment = p->parseComment(false);
3697     const string cbDoc = "@param " + cbParam + " The AMD callback object for the invocation.";
3698     const string currentDoc = "@param " + currentParam + " The Current object for the invocation.";
3699     const string cookieDoc = "@param " + cookieParam + " Extra data to associate with the invocation.";
3700     const string returnDoc = "The asynchronous result object for the invocation.";
3701 
3702     H << sp;
3703     if(!amd)
3704     {
3705         if(comment)
3706         {
3707             StringList postParams;
3708             if(!cl->isLocal())
3709             {
3710                 postParams.push_back(currentDoc);
3711             }
3712             writeOpDocSummary(H, p, comment, OpDocAllParams, true, StringList(), postParams, comment->returns());
3713         }
3714 
3715         H << nl << deprecateSymbol
3716           << "virtual " << retS << ' ' << fixKwd(name) << params << isConst << noExcept << " = 0;";
3717     }
3718     else
3719     {
3720         if(comment)
3721         {
3722             StringList preParams, postParams;
3723             preParams.push_back(cbDoc);
3724             postParams.push_back(currentDoc);
3725             StringList noReturns; // Leave empty - the AMD method has a void return type.
3726             writeOpDocSummary(H, p, comment, OpDocInParams, true, preParams, postParams, noReturns);
3727         }
3728 
3729         H << nl << deprecateSymbol
3730           << "virtual void " << name << "_async" << paramsAMD << isConst << noExcept << " = 0;";
3731     }
3732 
3733     if(!cl->isLocal())
3734     {
3735         H << nl << "/// \\cond INTERNAL";
3736         H << nl << "bool _iceD_" << name << "(::IceInternal::Incoming&, const " << getUnqualified("::Ice::Current&", scope)
3737           << ")" << isConst << ';';
3738         H << nl << "/// \\endcond";
3739 
3740         C << sp;
3741         //
3742         // inS, ret, current etc. may shadow class-with-operations data members in C++98
3743         //
3744         C << nl << "/// \\cond INTERNAL";
3745         C << nl << "bool" << nl << scope.substr(2) << "_iceD_" << name << "(::IceInternal::Incoming& inS"
3746           << ", const " << getUnqualified("::Ice::Current&", classScope) << " current)" << isConst;
3747         C << sb;
3748         C << nl << "_iceCheckMode(" << operationModeToString(p->mode()) << ", current.mode);";
3749 
3750         if(!inParams.empty())
3751         {
3752             C << nl << getUnqualified("::Ice::InputStream*", classScope) << " istr = inS.startReadParams();";
3753             writeAllocateCode(C, inParams, 0, true, classScope, _useWstring | TypeContextInParam);
3754             writeUnmarshalCode(C, inParams, 0, true, TypeContextInParam);
3755             if(p->sendsClasses(false))
3756             {
3757                 C << nl << "istr->readPendingValues();";
3758             }
3759             C << nl << "inS.endReadParams();";
3760         }
3761         else
3762         {
3763             C << nl << "inS.readEmptyParams();";
3764         }
3765         if(p->format() != DefaultFormat)
3766         {
3767             C << nl << "inS.setFormat(" << opFormatTypeToString(p, false) << ");";
3768         }
3769 
3770         if(!amd)
3771         {
3772             writeAllocateCode(C, outParams, 0, true, classScope, _useWstring, "ret");
3773             C << nl;
3774             if(ret)
3775             {
3776                 C << retS << " ret = ";
3777             }
3778             C << "this->" << fixKwd(name) << args << ';';
3779             if(ret || !outParams.empty())
3780             {
3781                 C << nl << getUnqualified("::Ice::OutputStream*", classScope) << " ostr = inS.startWriteParams();";
3782                 writeMarshalCode(C, outParams, p, true, 0);
3783                 if(p->returnsClasses(false))
3784                 {
3785                     C << nl << "ostr->writePendingValues();";
3786                 }
3787                 C << nl << "inS.endWriteParams();";
3788             }
3789             else
3790             {
3791                 C << nl << "inS.writeEmptyParams();";
3792             }
3793             C << nl << "return true;";
3794         }
3795         else
3796         {
3797             C << nl << "this->" << name << "_async" << argsAMD << ';';
3798             C << nl << "return false;";
3799         }
3800         C << eb;
3801         C << nl << "/// \\endcond";
3802     }
3803 
3804     if(cl->isLocal() && (cl->hasMetaData("async-oneway") || p->hasMetaData("async-oneway")))
3805     {
3806         vector<string> paramsDeclAMI;
3807         vector<string> outParamsDeclAMI;
3808 
3809         for(ParamDeclList::const_iterator r = paramList.begin(); r != paramList.end(); ++r)
3810         {
3811             string paramName = fixKwd((*r)->name());
3812 
3813             StringList metaData = (*r)->getMetaData();
3814             string typeString;
3815             if((*r)->isOutParam())
3816             {
3817                 typeString = outputTypeToString((*r)->type(), (*r)->optional(), classScope, metaData,
3818                                                 _useWstring | TypeContextAMIEnd);
3819             }
3820             else
3821             {
3822                 typeString = inputTypeToString((*r)->type(), (*r)->optional(), classScope, metaData, _useWstring);
3823             }
3824 
3825             if(!(*r)->isOutParam())
3826             {
3827                 paramsDeclAMI.push_back(typeString + ' ' + paramName);
3828             }
3829             else
3830             {
3831                 outParamsDeclAMI.push_back(typeString + ' ' + paramName);
3832             }
3833         }
3834 
3835         H << sp;
3836         if(comment)
3837         {
3838             StringList returns;
3839             returns.push_back(returnDoc);
3840             writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), StringList(), returns);
3841         }
3842         H << nl << "virtual " << getUnqualified("::Ice::AsyncResultPtr", classScope) << " begin_" << name << spar
3843           << paramsDeclAMI << epar << " = 0;";
3844 
3845         H << sp;
3846         if(comment)
3847         {
3848             StringList postParams, returns;
3849             postParams.push_back("@param " + cbParam + " Callback to be invoked when the invocation completes");
3850             postParams.push_back(cookieDoc);
3851             returns.push_back(returnDoc);
3852             writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
3853         }
3854         H << nl << "virtual " << getUnqualified("::Ice::AsyncResultPtr", classScope) << " begin_" << name << spar
3855           << paramsDeclAMI
3856           << ("const " + getUnqualified("::Ice::CallbackPtr&", classScope) + " " + cbParam)
3857           << ("const " + getUnqualified("::Ice::LocalObjectPtr&", classScope) + " " + cookieParam + " = 0")
3858           << epar << " = 0;";
3859 
3860         string delName = "Callback_" + cl->name() + "_" + name;
3861 
3862         H << sp;
3863         if(comment)
3864         {
3865             StringList postParams, returns;
3866             postParams.push_back("@param " + cbParam + " Callback to be invoked when the invocation completes");
3867             postParams.push_back(cookieDoc);
3868             returns.push_back(returnDoc);
3869             writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
3870         }
3871         H << nl << "virtual " << getUnqualified("::Ice::AsyncResultPtr", classScope) << " begin_" << name << spar
3872           << paramsDeclAMI
3873           << ("const " + delName + "Ptr& " + cbParam)
3874           << ("const " + getUnqualified("::Ice::LocalObjectPtr&", classScope) + " " + cookieParam + " = 0") << epar
3875           << " = 0;";
3876 
3877         H << sp;
3878         if(comment)
3879         {
3880             StringList postParams, returns;
3881             postParams.push_back("@param " + resultParam +
3882                                  " The asynchronous result object returned by the begin_ method.");
3883             writeOpDocSummary(H, p, comment, OpDocOutParams, true, StringList(), postParams, comment->returns());
3884         }
3885         H << nl << "virtual " << retS << " end_" << name << spar << outParamsDeclAMI
3886           << ("const " + getUnqualified("::Ice::AsyncResultPtr&", classScope) + " " + resultParam) << epar << " = 0;";
3887     }
3888 }
3889 
3890 void
emitDataMember(const DataMemberPtr & p)3891 Slice::Gen::ObjectVisitor::emitDataMember(const DataMemberPtr& p)
3892 {
3893     string name = fixKwd(p->name());
3894     ContainerPtr container = p->container();
3895     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
3896     int typeContext = cl->isLocal() ? TypeContextLocal | _useWstring : _useWstring;
3897     writeDocSummary(H, p);
3898     H << nl << typeToString(p->type(), p->optional(), fixKwd(cl->scope()), p->getMetaData(), typeContext) << ' '
3899       << name << ';';
3900 }
3901 
3902 void
emitGCFunctions(const ClassDefPtr & p)3903 Slice::Gen::ObjectVisitor::emitGCFunctions(const ClassDefPtr& p)
3904 {
3905     string scoped = fixKwd(p->scoped());
3906     string scope = fixKwd(p->scope());
3907     ClassList bases = p->bases();
3908     ClassDefPtr base;
3909     if(!bases.empty() && !bases.front()->isInterface())
3910     {
3911         base = bases.front();
3912     }
3913     DataMemberList dataMembers = p->dataMembers();
3914 
3915     //
3916     // A class can potentially be part of a cycle if it (recursively) contains class
3917     // members.
3918     //
3919     bool canBeCyclic = p->canBeCyclic();
3920     bool basePreserved = p->inheritsMetaData("preserve-slice");
3921     bool preserved = basePreserved || p->hasMetaData("preserve-slice");
3922 
3923     //
3924     // _iceGcVisit() is overridden by the basemost class that can be
3925     // cyclic, plus all classes derived from that class.
3926     //
3927     // We also override these methods for the initial preserved class in a
3928     // hierarchy, regardless of whether the class itself is cyclic.
3929     //
3930     if(canBeCyclic || (preserved && !basePreserved))
3931     {
3932         H << nl << "/// \\cond INTERNAL";
3933         H << nl << "virtual void _iceGcVisitMembers(::IceInternal::GCVisitor&);";
3934         H << nl << "/// \\endcond";
3935 
3936         C << sp << nl << "void" << nl << scoped.substr(2) << "::_iceGcVisitMembers(::IceInternal::GCVisitor& v_)";
3937         C << sb;
3938 
3939         bool hasCyclicBase = base && base->canBeCyclic();
3940         if(hasCyclicBase || basePreserved)
3941         {
3942             emitUpcall(bases.front(), "::_iceGcVisitMembers(v_);", scope);
3943         }
3944 
3945         if(preserved && !basePreserved)
3946         {
3947             C << nl << "if(_iceSlicedData)";
3948             C << sb;
3949             C << nl << "_iceSlicedData->_iceGcVisitMembers(v_);";
3950             C << eb;
3951         }
3952 
3953         for(DataMemberList::const_iterator i = dataMembers.begin(); i != dataMembers.end(); ++i)
3954         {
3955             if((*i)->type()->usesClasses())
3956             {
3957                 if((*i)->optional())
3958                 {
3959                     C << nl << "if(" << fixKwd((*i)->name()) << ')';
3960                     C << sb;
3961                     emitGCVisitCode((*i)->type(), getDataMemberRef(*i), "", 0);
3962                     C << eb;
3963                 }
3964                 else
3965                 {
3966                     emitGCVisitCode((*i)->type(), getDataMemberRef(*i), "", 0);
3967                 }
3968             }
3969         }
3970         C << eb;
3971     }
3972 }
3973 
3974 void
emitGCVisitCode(const TypePtr & p,const string & prefix,const string & name,int level)3975 Slice::Gen::ObjectVisitor::emitGCVisitCode(const TypePtr& p, const string& prefix, const string& name, int level)
3976 {
3977     BuiltinPtr builtin = BuiltinPtr::dynamicCast(p);
3978     if((builtin &&
3979        (BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindObject || BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindValue)) ||
3980        ClassDeclPtr::dynamicCast(p))
3981     {
3982         C << nl << "if(" << prefix << name << ')';
3983         C << sb;
3984         ClassDeclPtr decl = ClassDeclPtr::dynamicCast(p);
3985         if(decl)
3986         {
3987             string scope = fixKwd(decl->scope());
3988             C << nl << "if((" << scope << "upCast(" << prefix << name << ".get())->_iceGcVisit(v_)))";
3989         }
3990         else
3991         {
3992             C << nl << "if((" << prefix << name << ".get())->_iceGcVisit(v_))";
3993         }
3994         C << sb;
3995         C << nl << prefix << name << " = 0;";
3996         C << eb;
3997         C << eb;
3998     }
3999     else if(StructPtr::dynamicCast(p))
4000     {
4001         StructPtr s = StructPtr::dynamicCast(p);
4002         DataMemberList dml = s->dataMembers();
4003         for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i)
4004         {
4005             if((*i)->type()->usesClasses())
4006             {
4007                 emitGCVisitCode((*i)->type(), prefix + name + ".", fixKwd((*i)->name()), ++level);
4008             }
4009         }
4010     }
4011     else if(DictionaryPtr::dynamicCast(p))
4012     {
4013         DictionaryPtr d = DictionaryPtr::dynamicCast(p);
4014         string scoped = fixKwd(d->scoped());
4015         ostringstream tmp;
4016         tmp << "_i" << level;
4017         string iterName = tmp.str();
4018         C << sb;
4019         C << nl << "for(" << scoped << "::iterator " << iterName << " = " << prefix + name
4020           << ".begin(); " << iterName << " != " << prefix + name << ".end(); ++" << iterName << ")";
4021         C << sb;
4022         emitGCVisitCode(d->valueType(), "", string("(*") + iterName + ").second", ++level);
4023         C << eb;
4024         C << eb;
4025     }
4026     else if(SequencePtr::dynamicCast(p))
4027     {
4028         SequencePtr s = SequencePtr::dynamicCast(p);
4029         string scoped = fixKwd(s->scoped());
4030         ostringstream tmp;
4031         tmp << "_i" << level;
4032         string iterName = tmp.str();
4033         C << sb;
4034         C << nl << "for(" << scoped << "::iterator " << iterName << " = " << prefix + name
4035           << ".begin(); " << iterName << " != " << prefix + name << ".end(); ++" << iterName << ")";
4036         C << sb;
4037         emitGCVisitCode(s->type(), string("(*") + iterName + ")", "", ++level);
4038         C << eb;
4039         C << eb;
4040     }
4041 }
4042 
4043 bool
emitVirtualBaseInitializers(const ClassDefPtr & p,bool virtualInheritance,bool direct)4044 Slice::Gen::ObjectVisitor::emitVirtualBaseInitializers(const ClassDefPtr& p, bool virtualInheritance, bool direct)
4045 {
4046     DataMemberList allDataMembers = p->allDataMembers();
4047     if(allDataMembers.empty())
4048     {
4049         return false;
4050     }
4051 
4052     ClassList bases = p->bases();
4053     if(!bases.empty() && !bases.front()->isInterface())
4054     {
4055         if(emitVirtualBaseInitializers(bases.front(), p->hasMetaData("cpp:virtual"), false))
4056         {
4057             H << ',';
4058         }
4059     }
4060 
4061     //
4062     // Do not call non direct base classes constructor if not using virtual inheritance.
4063     //
4064     if(!direct && !virtualInheritance)
4065     {
4066         return false;
4067     }
4068 
4069     string upcall = "(";
4070     for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
4071     {
4072         if(q != allDataMembers.begin())
4073         {
4074             upcall += ", ";
4075         }
4076         upcall += fixKwd((*q)->name());
4077     }
4078     upcall += ")";
4079 
4080     H << nl << fixKwd(p->scoped()) << upcall;
4081 
4082     return true;
4083 }
4084 
4085 void
emitOneShotConstructor(const ClassDefPtr & p)4086 Slice::Gen::ObjectVisitor::emitOneShotConstructor(const ClassDefPtr& p)
4087 {
4088     DataMemberList allDataMembers = p->allDataMembers();
4089     string scope = fixKwd(p->scope());
4090 
4091     if(!allDataMembers.empty())
4092     {
4093         vector<string> allParamDecls;
4094         map<string, CommentPtr> allComments;
4095 
4096         bool virtualInheritance = p->hasMetaData("cpp:virtual");
4097         bool callBaseConstructors = !(p->isAbstract() && virtualInheritance);
4098         DataMemberList dataMembers = p->dataMembers();
4099 
4100         int typeContext = p->isLocal() ? (_useWstring | TypeContextLocal) : _useWstring;
4101 
4102         for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
4103         {
4104             string typeName =
4105                 inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), typeContext);
4106             bool dataMember = std::find(dataMembers.begin(), dataMembers.end(), (*q)) != dataMembers.end();
4107             allParamDecls.push_back(typeName + ((dataMember || callBaseConstructors) ?
4108                                                     (" " + fixKwd((*q)->name())) :
4109                                                     (" /*" + fixKwd((*q)->name()) + "*/")));
4110             CommentPtr comment = (*q)->parseComment(false);
4111             if(comment)
4112             {
4113                 allComments[(*q)->name()] = comment;
4114             }
4115         }
4116 
4117         H << sp;
4118         H << nl << "/**";
4119         H << nl << " * One-shot constructor to initialize all data members.";
4120         for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
4121         {
4122             map<string, CommentPtr>::iterator r = allComments.find((*q)->name());
4123             if(r != allComments.end())
4124             {
4125                 H << nl << " * @param " << fixKwd(r->first) << " " << getDocSentence(r->second->overview());
4126             }
4127         }
4128         H << nl << " */";
4129         H << nl;
4130         if(allParamDecls.size() == 1)
4131         {
4132             H << "explicit ";
4133         }
4134         H << fixKwd(p->name()) << spar << allParamDecls << epar;
4135         if(callBaseConstructors || !dataMembers.empty())
4136         {
4137             H << " :";
4138         }
4139         H.inc();
4140 
4141         ClassList bases = p->bases();
4142         ClassDefPtr base;
4143 
4144         if(!bases.empty() && !bases.front()->isInterface() && callBaseConstructors)
4145         {
4146             if(emitVirtualBaseInitializers(bases.front(), virtualInheritance, true))
4147             {
4148                 if(!dataMembers.empty())
4149                 {
4150                     H << ',';
4151                 }
4152             }
4153         }
4154 
4155         if(!dataMembers.empty())
4156         {
4157             H << nl;
4158         }
4159         for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
4160         {
4161             if(q != dataMembers.begin())
4162             {
4163                 H << ',' << nl;
4164             }
4165             string memberName = fixKwd((*q)->name());
4166             H << memberName << '(' << memberName << ')';
4167         }
4168 
4169         H.dec();
4170         H << sb;
4171         H << eb;
4172     }
4173 }
4174 
4175 void
emitUpcall(const ClassDefPtr & base,const string & call,const string & scope)4176 Slice::Gen::ObjectVisitor::emitUpcall(const ClassDefPtr& base, const string& call, const string& scope)
4177 {
4178     C << nl;
4179     if(base)
4180     {
4181         C << getUnqualified(fixKwd(base->scoped()), scope);
4182     }
4183     else
4184     {
4185         C << getUnqualified("::Ice::Object", scope);
4186     }
4187     C << call;
4188 }
4189 
AsyncCallbackVisitor(Output & h,Output &,const string & dllExport)4190 Slice::Gen::AsyncCallbackVisitor::AsyncCallbackVisitor(Output& h, Output&, const string& dllExport) :
4191     H(h), _dllExport(dllExport), _useWstring(false)
4192 {
4193 }
4194 
4195 bool
visitModuleStart(const ModulePtr & p)4196 Slice::Gen::AsyncCallbackVisitor::visitModuleStart(const ModulePtr& p)
4197 {
4198     if(!p->hasNonLocalClassDefs() && !p->hasContentsWithMetaData("async-oneway"))
4199     {
4200         return false;
4201     }
4202 
4203     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4204 
4205     H << sp << nl << "namespace " << fixKwd(p->name())  << nl << '{';
4206 
4207     return true;
4208 }
4209 
4210 void
visitModuleEnd(const ModulePtr &)4211 Slice::Gen::AsyncCallbackVisitor::visitModuleEnd(const ModulePtr&)
4212 {
4213     _useWstring = resetUseWstring(_useWstringHist);
4214 
4215     H << sp << nl << '}';
4216 }
4217 
4218 bool
visitClassDefStart(const ClassDefPtr & p)4219 Slice::Gen::AsyncCallbackVisitor::visitClassDefStart(const ClassDefPtr& p)
4220 {
4221     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4222     return true;
4223 }
4224 
4225 void
visitClassDefEnd(const ClassDefPtr &)4226 Slice::Gen::AsyncCallbackVisitor::visitClassDefEnd(const ClassDefPtr&)
4227 {
4228     _useWstring = resetUseWstring(_useWstringHist);
4229 }
4230 
4231 void
visitOperation(const OperationPtr & p)4232 Slice::Gen::AsyncCallbackVisitor::visitOperation(const OperationPtr& p)
4233 {
4234     ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container());
4235 
4236     if(cl->isLocal() && !(cl->hasMetaData("async-oneway") || p->hasMetaData("async-oneway")))
4237     {
4238         return;
4239     }
4240 
4241     //
4242     // Write the callback base class and callback smart pointer.
4243     //
4244     string delName = "Callback_" + cl->name() + "_" + p->name();
4245     H << sp;
4246     H << nl << "/**";
4247     H << nl << " * Base class for asynchronous callback wrapper classes used for calls to";
4248     H << nl << " * IceProxy" << fixKwd(cl->scoped()) << "::begin_" << p->name() << ".";
4249     H << nl << " * Create a wrapper instance by calling " << fixKwd(cl->scope()) << "new" << delName << ".";
4250     H << nl << " */";
4251     H << nl << "class " << delName << "_Base : public virtual ::IceInternal::CallbackBase { };";
4252     H << nl << "typedef ::IceUtil::Handle< " << delName << "_Base> " << delName << "Ptr;";
4253 }
4254 
AsyncCallbackTemplateVisitor(Output & h,Output &,const string & dllExport)4255 Slice::Gen::AsyncCallbackTemplateVisitor::AsyncCallbackTemplateVisitor(Output& h, Output&, const string& dllExport)
4256     : H(h), _dllExport(dllExport), _useWstring(false)
4257 {
4258 }
4259 
4260 bool
visitUnitStart(const UnitPtr & p)4261 Slice::Gen::AsyncCallbackTemplateVisitor::visitUnitStart(const UnitPtr& p)
4262 {
4263     return p->hasNonLocalClassDefs();
4264 }
4265 
4266 void
visitUnitEnd(const UnitPtr &)4267 Slice::Gen::AsyncCallbackTemplateVisitor::visitUnitEnd(const UnitPtr&)
4268 {
4269 }
4270 
4271 bool
visitModuleStart(const ModulePtr & p)4272 Slice::Gen::AsyncCallbackTemplateVisitor::visitModuleStart(const ModulePtr& p)
4273 {
4274     if(!p->hasNonLocalClassDefs())
4275     {
4276         return false;
4277     }
4278 
4279     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4280 
4281     H << sp << nl << "namespace " << fixKwd(p->name())  << nl << '{';
4282     return true;
4283 }
4284 
4285 void
visitModuleEnd(const ModulePtr &)4286 Slice::Gen::AsyncCallbackTemplateVisitor::visitModuleEnd(const ModulePtr&)
4287 {
4288     _useWstring = resetUseWstring(_useWstringHist);
4289     H << sp << nl << '}';
4290 }
4291 
4292 bool
visitClassDefStart(const ClassDefPtr & p)4293 Slice::Gen::AsyncCallbackTemplateVisitor::visitClassDefStart(const ClassDefPtr& p)
4294 {
4295     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4296     return true;
4297 }
4298 
4299 void
visitClassDefEnd(const ClassDefPtr &)4300 Slice::Gen::AsyncCallbackTemplateVisitor::visitClassDefEnd(const ClassDefPtr&)
4301 {
4302     _useWstring = resetUseWstring(_useWstringHist);
4303 }
4304 
4305 void
visitOperation(const OperationPtr & p)4306 Slice::Gen::AsyncCallbackTemplateVisitor::visitOperation(const OperationPtr& p)
4307 {
4308     generateOperation(p, false);
4309     generateOperation(p, true);
4310 }
4311 
4312 void
generateOperation(const OperationPtr & p,bool withCookie)4313 Slice::Gen::AsyncCallbackTemplateVisitor::generateOperation(const OperationPtr& p, bool withCookie)
4314 {
4315     ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container());
4316     if(cl->isLocal() || cl->operations().empty())
4317     {
4318         return;
4319     }
4320 
4321     string clName = cl->name();
4322     string clScope = fixKwd(cl->scope());
4323     string delName = "Callback_" + clName + "_" + p->name();
4324     string delTmplName = (withCookie ? "Callback_" : "CallbackNC_") + clName + "_" + p->name();
4325 
4326     TypePtr ret = p->returnType();
4327     string retS = inputTypeToString(ret, p->returnIsOptional(), clScope, p->getMetaData(), _useWstring);
4328     string retEndArg = getEndArg(ret, p->getMetaData(), "ret");
4329 
4330     ParamDeclList outParams;
4331     vector<string> outArgs;
4332     vector<string> outDecls;
4333     vector<string> outDeclsEnd;
4334     vector<string> outEndArgs;
4335 
4336     ParamDeclList paramList = p->parameters();
4337     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4338     {
4339         if((*q)->isOutParam())
4340         {
4341             outParams.push_back(*q);
4342             outArgs.push_back("iceP_" + (*q)->name());
4343             outEndArgs.push_back(getEndArg((*q)->type(), (*q)->getMetaData(), outArgs.back()));
4344             outDecls.push_back(
4345                 inputTypeToString((*q)->type(), (*q)->optional(), clScope, (*q)->getMetaData(), _useWstring));
4346         }
4347     }
4348 
4349     H << sp;
4350     string baseD;
4351     string inheritD;
4352     if(withCookie)
4353     {
4354         baseD = "::IceInternal::Callback<T, CT>";
4355         H << nl << "/**";
4356         H << nl << " * Type-safe asynchronous callback wrapper class with cookie support used for calls to";
4357         H << nl << " * IceProxy" << fixKwd(cl->scoped()) << "::begin_" << p->name() << ".";
4358         H << nl << " * Create a wrapper instance by calling " << fixKwd(cl->scope()) << "new" << delName << ".";
4359         H << nl << " */";
4360         H << nl << "template<class T, typename CT>";
4361         inheritD = p->returnsData() ? "::IceInternal::TwowayCallback<T, CT>" : "::IceInternal::OnewayCallback<T, CT>";
4362     }
4363     else
4364     {
4365         baseD = "::IceInternal::CallbackNC<T>";
4366         H << nl << "/**";
4367         H << nl << " * Type-safe asynchronous callback wrapper class used for calls to";
4368         H << nl << " * IceProxy" << fixKwd(cl->scoped()) << "::begin_" << p->name() << ".";
4369         H << nl << " * Create a wrapper instance by calling " << fixKwd(cl->scope()) << "new" << delName << ".";
4370         H << nl << " */";
4371         H << nl << "template<class T>";
4372         inheritD = p->returnsData() ? "::IceInternal::TwowayCallbackNC<T>" : "::IceInternal::OnewayCallbackNC<T>";
4373     }
4374 
4375     H << nl << "class " << delTmplName << " : public " << delName << "_Base, public " << inheritD;
4376     H << sb;
4377     H.dec();
4378     H << nl << "public:";
4379     H.inc();
4380 
4381     H << sp << nl << "typedef IceUtil::Handle<T> TPtr;";
4382 
4383     string cookieT;
4384     string comCookieT;
4385     if(withCookie)
4386     {
4387         cookieT = "const CT&";
4388         comCookieT = " , const CT&";
4389     }
4390 
4391     H << sp << nl << "typedef void (T::*Exception)(const ::Ice::Exception&" << comCookieT << ");";
4392     H << nl << "typedef void (T::*Sent)(bool" << comCookieT << ");";
4393     if(p->returnsData())
4394     {
4395         //
4396         // typedefs for callbacks.
4397         //
4398         H << nl << "typedef void (T::*Response)" << spar;
4399         if(ret)
4400         {
4401             H << retS;
4402         }
4403         H << outDecls;
4404         if(withCookie)
4405         {
4406             H << cookieT;
4407         }
4408         H << epar << ';';
4409     }
4410     else
4411     {
4412         H << nl << "typedef void (T::*Response)(" << cookieT << ");";
4413     }
4414 
4415     //
4416     // constructor.
4417     //
4418     H << sp;
4419     H << nl << delTmplName << spar << "const TPtr& obj";
4420     H << "Response cb";
4421     H << "Exception excb";
4422     H << "Sent sentcb" << epar;
4423     H.inc();
4424     if(p->returnsData())
4425     {
4426         H << nl << ": " << inheritD + "(obj, cb != 0, excb, sentcb), _response(cb)";
4427     }
4428     else
4429     {
4430         H << nl << ": " << inheritD + "(obj, cb, excb, sentcb)";
4431     }
4432     H.dec();
4433     H << sb;
4434     H << eb;
4435 
4436     if(p->returnsData())
4437     {
4438         //
4439         // completed.
4440         //
4441         H << sp;
4442         H << nl << "/// \\cond INTERNAL";
4443         H << nl << "virtual void completed(const " << getUnqualified("::Ice::AsyncResultPtr&", clScope)
4444           << " result) const";
4445         H << sb;
4446         H << nl << clName << "Prx proxy = " << clName << "Prx::uncheckedCast(result->getProxy());";
4447         writeAllocateCode(H, outParams, p, true, clScope,
4448                           _useWstring | TypeContextInParam | TypeContextAMICallPrivateEnd);
4449         H << nl << "try";
4450         H << sb;
4451         H << nl;
4452         if(!usePrivateEnd(p))
4453         {
4454             if(ret)
4455             {
4456                 H << retEndArg << " = ";
4457             }
4458             H << "proxy->end_" << p->name() << spar << outEndArgs << "result" << epar << ';';
4459         }
4460         else
4461         {
4462             H << "proxy->_iceI_end_" << p->name() << spar << outEndArgs;
4463             if(ret)
4464             {
4465                 H << retEndArg;
4466             }
4467             H << "result" << epar << ';';
4468         }
4469         writeEndCode(H, outParams, p, true);
4470         H << eb;
4471         H << nl << "catch(const ::Ice::Exception& ex)";
4472         H << sb;
4473 
4474         H << nl << "" << baseD << "::exception(result, ex);";
4475         H << nl << "return;";
4476         H << eb;
4477         H << nl << "if(_response)";
4478         H << sb;
4479         H << nl << "(" << baseD << "::_callback.get()->*_response)" << spar;
4480         if(ret)
4481         {
4482             H << "ret";
4483         }
4484         H << outArgs;
4485         if(withCookie)
4486         {
4487             H << "CT::dynamicCast(result->getCookie())";
4488         }
4489         H << epar << ';';
4490         H << eb;
4491         H << eb;
4492         H << nl << "/// \\endcond";
4493         H.dec();
4494         H << sp << nl << "private:";
4495         H.inc();
4496         H << sp << nl << "Response _response;";
4497     }
4498     H << eb << ';';
4499 
4500     // Factory method
4501     for(int i = 0; i < 2; i++)
4502     {
4503         string callbackT = i == 0 ? "const IceUtil::Handle<T>&" : "T*";
4504 
4505         H << sp;
4506         H << nl << "/**";
4507         H << nl << " * Creates a callback wrapper instance that delegates to your object.";
4508         if(withCookie)
4509         {
4510             H << nl << " * Use this overload when your callback methods receive a cookie value.";
4511         }
4512         H << nl << " * @param instance The callback object.";
4513         H << nl << " * @param cb The success method of the callback object.";
4514         H << nl << " * @param excb The exception method of the callback object.";
4515         H << nl << " * @param sentcb The sent method of the callback object.";
4516         H << nl << " * @return An object that can be passed to an asynchronous invocation of IceProxy"
4517           << clScope << clName << "::begin_" << p->name() << ".";
4518         H << nl << " */";
4519         if(withCookie)
4520         {
4521             cookieT = "const CT&";
4522             comCookieT = ", const CT&";
4523             H << nl << "template<class T, typename CT> " << delName << "Ptr";
4524         }
4525         else
4526         {
4527             H << nl << "template<class T> " << delName << "Ptr";
4528         }
4529 
4530         H << nl << "new" << delName << "(" << callbackT << " instance, ";
4531         if(p->returnsData())
4532         {
4533             H  << "void (T::*cb)" << spar;
4534             if(ret)
4535             {
4536                 H << retS;
4537             }
4538             H << outDecls;
4539             if(withCookie)
4540             {
4541                 H << cookieT;
4542             }
4543             H << epar << ", ";
4544         }
4545         else
4546         {
4547             H  << "void (T::*cb)(" << cookieT << "), ";
4548         }
4549         H << "void (T::*excb)(" << "const ::Ice::Exception&" << comCookieT << "), ";
4550         H << "void (T::*sentcb)(bool" << comCookieT << ") = 0)";
4551         H << sb;
4552         if(withCookie)
4553         {
4554             H << nl << "return new " << delTmplName << "<T, CT>(instance, cb, excb, sentcb);";
4555         }
4556         else
4557         {
4558             H << nl << "return new " << delTmplName << "<T>(instance, cb, excb, sentcb);";
4559         }
4560         H << eb;
4561 
4562         if(!ret && outParams.empty())
4563         {
4564             H << sp;
4565             H << nl << "/**";
4566             H << nl << " * Creates a callback wrapper instance that delegates to your object.";
4567             if(withCookie)
4568             {
4569                 H << nl << " * Use this overload when your callback methods receive a cookie value.";
4570             }
4571             H << nl << " * @param instance The callback object.";
4572             H << nl << " * @param excb The exception method of the callback object.";
4573             H << nl << " * @param sentcb The sent method of the callback object.";
4574             H << nl << " * @return An object that can be passed to an asynchronous invocation of IceProxy"
4575               << clScope << clName << "::begin_" << p->name() << ".";
4576             H << nl << " */";
4577             if(withCookie)
4578             {
4579                 H << nl << "template<class T, typename CT> " << delName << "Ptr";
4580             }
4581             else
4582             {
4583                 H << nl << "template<class T> " << delName << "Ptr";
4584             }
4585             H << nl << "new" << delName << "(" << callbackT << " instance, ";
4586             H << "void (T::*excb)(" << "const ::Ice::Exception&" << comCookieT << "), ";
4587             H << "void (T::*sentcb)(bool" << comCookieT << ") = 0)";
4588             H << sb;
4589             if(withCookie)
4590             {
4591                 H << nl << "return new " << delTmplName << "<T, CT>(instance, 0, excb, sentcb);";
4592             }
4593             else
4594             {
4595                 H << nl << "return new " << delTmplName << "<T>(instance, 0, excb, sentcb);";
4596             }
4597             H << eb;
4598         }
4599     }
4600 }
4601 
ImplVisitor(Output & h,Output & c,const string & dllExport)4602 Slice::Gen::ImplVisitor::ImplVisitor(Output& h, Output& c, const string& dllExport) :
4603     H(h), C(c), _dllExport(dllExport), _useWstring(false)
4604 {
4605 }
4606 
4607 string
defaultValue(const TypePtr & type,const string & scope,const StringList & metaData) const4608 Slice::Gen::ImplVisitor::defaultValue(const TypePtr& type, const string& scope, const StringList& metaData) const
4609 {
4610     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
4611     if(builtin)
4612     {
4613         switch(builtin->kind())
4614         {
4615             case Builtin::KindBool:
4616             {
4617                 return "false";
4618             }
4619             case Builtin::KindByte:
4620             case Builtin::KindShort:
4621             case Builtin::KindInt:
4622             case Builtin::KindLong:
4623             {
4624                 return "0";
4625             }
4626             case Builtin::KindFloat:
4627             case Builtin::KindDouble:
4628             {
4629                 return "0.0";
4630             }
4631             case Builtin::KindString:
4632             {
4633                 return "::std::string()";
4634             }
4635             case Builtin::KindValue:
4636             case Builtin::KindObject:
4637             case Builtin::KindObjectProxy:
4638             case Builtin::KindLocalObject:
4639             {
4640                 return "0";
4641             }
4642         }
4643     }
4644     else
4645     {
4646         ProxyPtr prx = ProxyPtr::dynamicCast(type);
4647 
4648         if(ProxyPtr::dynamicCast(type) || ClassDeclPtr::dynamicCast(type))
4649         {
4650             return "0";
4651         }
4652 
4653         StructPtr st = StructPtr::dynamicCast(type);
4654         if(st)
4655         {
4656             return getUnqualified(fixKwd(st->scoped()), scope) + "()";
4657         }
4658 
4659         EnumPtr en = EnumPtr::dynamicCast(type);
4660         if(en)
4661         {
4662             EnumeratorList enumerators = en->enumerators();
4663             return getUnqualified(fixKwd(en->scope() + enumerators.front()->name()), scope);
4664         }
4665 
4666         SequencePtr seq = SequencePtr::dynamicCast(type);
4667         if(seq)
4668         {
4669             return typeToString(seq, scope, metaData, _useWstring | TypeContextCpp11) + "()";
4670         }
4671 
4672         DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
4673         if(dict)
4674         {
4675             return getUnqualified(fixKwd(dict->scoped()), scope) + "()";
4676         }
4677     }
4678 
4679     assert(false);
4680     return "???";
4681 }
4682 
4683 bool
visitModuleStart(const ModulePtr & p)4684 Slice::Gen::ImplVisitor::visitModuleStart(const ModulePtr& p)
4685 {
4686     if(!p->hasClassDefs())
4687     {
4688         return false;
4689     }
4690     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4691     H << sp << nl << "namespace " << fixKwd(p->name()) << nl << '{';
4692     return true;
4693 }
4694 
4695 void
visitModuleEnd(const ModulePtr &)4696 Slice::Gen::ImplVisitor::visitModuleEnd(const ModulePtr&)
4697 {
4698     H << sp;
4699     H << nl << '}';
4700 
4701     _useWstring = resetUseWstring(_useWstringHist);
4702 }
4703 
4704 bool
visitClassDefStart(const ClassDefPtr & p)4705 Slice::Gen::ImplVisitor::visitClassDefStart(const ClassDefPtr& p)
4706 {
4707     if(!p->isAbstract())
4708     {
4709         return false;
4710     }
4711 
4712     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4713 
4714     string name = p->name();
4715     string scope = fixKwd(p->scope());
4716     string cls = scope.substr(2) + name + "I";
4717     ClassList bases = p->bases();
4718 
4719     H << sp;
4720     H << nl << "class " << name << "I : public virtual " << fixKwd(name);
4721 
4722     H << sb;
4723     H.dec();
4724     H << nl << "public:";
4725     H.inc();
4726 
4727     OperationList ops = p->allOperations();
4728 
4729     for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r)
4730     {
4731         OperationPtr op = (*r);
4732         string opName = op->name();
4733         string isConst = ((op->mode() == Operation::Nonmutating) || op->hasMetaData("cpp:const")) ? " const" : "";
4734 
4735         string classScopedAMD = "AMD_" + ClassDefPtr::dynamicCast(op->container())->name();
4736 
4737         TypePtr ret = op->returnType();
4738         string retS = returnTypeToString(ret, op->returnIsOptional(), "", op->getMetaData(), _useWstring);
4739 
4740         if(!p->isLocal() && (p->hasMetaData("amd") || op->hasMetaData("amd")))
4741         {
4742             H << sp << nl << "virtual void " << opName << "_async(";
4743             H.useCurrentPosAsIndent();
4744             H << "const " << classScopedAMD << '_' << opName << "Ptr&";
4745             ParamDeclList paramList = op->parameters();
4746 
4747             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4748             {
4749                 if(!(*q)->isOutParam())
4750                 {
4751                     H << ',' << nl << inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(),
4752                                                         _useWstring);
4753                 }
4754             }
4755             H << ',' << nl << "const Ice::Current&";
4756             H.restoreIndent();
4757             H << ")" << isConst << ';';
4758 
4759             C << sp << nl << "void" << nl << scope << name << "I::" << opName << "_async(";
4760             C.useCurrentPosAsIndent();
4761             C << "const " << classScopedAMD << '_' << opName << "Ptr& " << opName << "CB";
4762             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4763             {
4764                 if(!(*q)->isOutParam())
4765                 {
4766                     C << ',' << nl << inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(),
4767                                                         _useWstring) << ' ' << fixKwd((*q)->name());
4768                 }
4769             }
4770             C << ',' << nl << "const Ice::Current& current";
4771             C.restoreIndent();
4772             C << ")" << isConst;
4773             C << sb;
4774 
4775             string result = "r";
4776             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4777             {
4778                 if((*q)->name() == result)
4779                 {
4780                     result = "_" + result;
4781                     break;
4782                 }
4783             }
4784 
4785             C << nl << opName << "CB->ice_response(";
4786             if(ret)
4787             {
4788                 C << defaultValue(ret, scope, op->getMetaData());
4789             }
4790             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4791             {
4792                 if((*q)->isOutParam())
4793                 {
4794                     if(ret || q != paramList.begin())
4795                     {
4796                         C << ", ";
4797                     }
4798                     C << defaultValue((*q)->type(), scope, op->getMetaData());
4799                 }
4800             }
4801             C << ");";
4802 
4803             C << eb;
4804         }
4805         else
4806         {
4807             H << sp << nl << "virtual " << getUnqualified(retS, scope) << ' ' << fixKwd(opName) << '(';
4808             H.useCurrentPosAsIndent();
4809             ParamDeclList paramList = op->parameters();
4810             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4811             {
4812                 if(q != paramList.begin())
4813                 {
4814                     H << ',' << nl;
4815                 }
4816                 if((*q)->isOutParam())
4817                 {
4818                     H << outputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring);
4819                 }
4820                 else
4821                 {
4822                     H << inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring);
4823                 }
4824             }
4825             if(!p->isLocal())
4826             {
4827                 if(!paramList.empty())
4828                 {
4829                     H << ',' << nl;
4830                 }
4831                 H << "const Ice::Current&";
4832             }
4833             H.restoreIndent();
4834 
4835             H << ")" << isConst << ';';
4836 
4837             C << sp << nl << retS << nl;
4838             C << scope.substr(2) << name << "I::" << fixKwd(opName) << '(';
4839             C.useCurrentPosAsIndent();
4840             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4841             {
4842                 if(q != paramList.begin())
4843                 {
4844                     C << ',' << nl;
4845                 }
4846                 if((*q)->isOutParam())
4847                 {
4848                     C << outputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring) << " "
4849                       << fixKwd((*q)->name());
4850                 }
4851                 else
4852                 {
4853                     C << inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), _useWstring) << " /*"
4854                       << fixKwd((*q)->name()) << "*/";
4855                 }
4856             }
4857             if(!p->isLocal())
4858             {
4859                 if(!paramList.empty())
4860                 {
4861                     C << ',' << nl;
4862                 }
4863                 C << "const Ice::Current& current";
4864             }
4865             C.restoreIndent();
4866             C << ')';
4867             C << isConst;
4868             C << sb;
4869 
4870             if(ret)
4871             {
4872                 C << nl << "return " << defaultValue(ret, scope, op->getMetaData()) << ";";
4873             }
4874 
4875             C << eb;
4876         }
4877     }
4878 
4879     H << eb << ';';
4880 
4881     _useWstring = resetUseWstring(_useWstringHist);
4882 
4883     return true;
4884 }
4885 
AsyncVisitor(Output & h,Output & c,const string & dllExport)4886 Slice::Gen::AsyncVisitor::AsyncVisitor(Output& h, Output& c, const string& dllExport) :
4887     H(h), C(c), _dllExport(dllExport), _useWstring(false)
4888 {
4889 }
4890 
4891 bool
visitModuleStart(const ModulePtr & p)4892 Slice::Gen::AsyncVisitor::visitModuleStart(const ModulePtr& p)
4893 {
4894     if(!p->hasNonLocalClassDecls() || !p->hasContentsWithMetaData("amd"))
4895     {
4896         return false;
4897     }
4898 
4899     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4900 
4901     string name = fixKwd(p->name());
4902 
4903     H << sp << nl << "namespace " << name << nl << '{';
4904 
4905     return true;
4906 }
4907 
4908 void
visitModuleEnd(const ModulePtr &)4909 Slice::Gen::AsyncVisitor::visitModuleEnd(const ModulePtr&)
4910 {
4911     H << sp << nl << '}';
4912 
4913     _useWstring = resetUseWstring(_useWstringHist);
4914 }
4915 
4916 bool
visitClassDefStart(const ClassDefPtr & p)4917 Slice::Gen::AsyncVisitor::visitClassDefStart(const ClassDefPtr& p)
4918 {
4919     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
4920     return true;
4921 }
4922 
4923 void
visitClassDefEnd(const ClassDefPtr &)4924 Slice::Gen::AsyncVisitor::visitClassDefEnd(const ClassDefPtr&)
4925 {
4926     _useWstring = resetUseWstring(_useWstringHist);
4927 }
4928 
4929 void
visitOperation(const OperationPtr & p)4930 Slice::Gen::AsyncVisitor::visitOperation(const OperationPtr& p)
4931 {
4932     ContainerPtr container = p->container();
4933     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
4934 
4935     if(cl->isLocal() || (!cl->hasMetaData("amd") && !p->hasMetaData("amd")))
4936     {
4937         return;
4938     }
4939 
4940     string name = p->name();
4941 
4942     string className = cl->name();
4943     string classNameAMD = "AMD_" + className;
4944     string classScope = fixKwd(cl->scope());
4945     string classScopedAMD = classScope + classNameAMD;
4946 
4947     TypePtr ret = p->returnType();
4948     string retS = inputTypeToString(ret, p->returnIsOptional(), classScope, p->getMetaData(), _useWstring);
4949 
4950     string resultParam = "result";
4951     ParamDeclList paramList = p->outParameters();
4952     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4953     {
4954         if((*q)->name() == "result")
4955         {
4956             resultParam = "result_";
4957             break;
4958         }
4959     }
4960 
4961     vector<string> paramsAMD;
4962 
4963     if(ret)
4964     {
4965         paramsAMD.push_back(inputTypeToString(ret, p->returnIsOptional(), classScope, p->getMetaData(), _useWstring) +
4966                             " " + resultParam);
4967     }
4968 
4969     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
4970     {
4971         string paramName = fixKwd((*q)->name());
4972         TypePtr type = (*q)->type();
4973         string typeString = inputTypeToString(type, (*q)->optional(), classScope, (*q)->getMetaData(), _useWstring);
4974         paramsAMD.push_back(typeString + " " + paramName);
4975     }
4976 
4977     string cbName = classNameAMD + '_' + name;
4978 
4979     CommentPtr comment = p->parseComment(false);
4980 
4981     H << sp;
4982     H << nl << "/**";
4983     H << nl << " * AMD callback class for " << fixKwd(p->scoped()).substr(2) << "_async.";
4984     H << nl << " * Call the ice_response method for a successful completion, or the ice_exception";
4985     H << nl << " * method in the case of an error.";
4986     H << nl << " */";
4987     H << nl << "class " << _dllExport << cbName << " : public virtual "
4988       << getUnqualified("::Ice::AMDCallback", classScope);
4989     H << sb;
4990     H.dec();
4991     H << nl << "public:";
4992     H.inc();
4993 
4994     // Out of line dtor to avoid weak vtable
4995     H << sp << nl << "virtual ~" << cbName << "();";
4996     C << sp;
4997     C << nl << classScope.substr(2) << cbName << "::~" << cbName << "()";
4998     C << sb;
4999     C << eb;
5000 
5001     H << sp;
5002     H << nl << "/**";
5003     H << nl << " * Call ice_response for a successful completion.";
5004     if(comment)
5005     {
5006         StringList preParams;
5007         StringList returns = comment->returns();
5008         if(ret && !returns.empty())
5009         {
5010             preParams = returns;
5011             preParams.pop_front();
5012             preParams.push_front("@param " + resultParam + " " + returns.front());
5013         }
5014         writeOpDocParams(H, p, comment, OpDocOutParams, preParams);
5015     }
5016     H << nl << " */";
5017     H << nl << "virtual void ice_response" << spar << paramsAMD << epar << " = 0;";
5018     H << eb << ';';
5019     H << sp << nl << "typedef ::IceUtil::Handle< " << classScopedAMD << '_' << name << "> "
5020       << classNameAMD << '_' << name  << "Ptr;";
5021 }
5022 
AsyncImplVisitor(Output & h,Output & c,const string & dllExport)5023 Slice::Gen::AsyncImplVisitor::AsyncImplVisitor(Output& h, Output& c, const string& dllExport) :
5024     H(h), C(c), _dllExport(dllExport), _useWstring(false)
5025 {
5026 }
5027 
5028 bool
visitUnitStart(const UnitPtr & p)5029 Slice::Gen::AsyncImplVisitor::visitUnitStart(const UnitPtr& p)
5030 {
5031     if(!p->hasNonLocalClassDecls() || !p->hasContentsWithMetaData("amd"))
5032     {
5033         return false;
5034     }
5035 
5036     H << sp;
5037     H << nl << "/// \\cond INTERNAL";
5038     H << nl << "namespace IceAsync" << nl << '{';
5039 
5040     return true;
5041 }
5042 
5043 void
visitUnitEnd(const UnitPtr &)5044 Slice::Gen::AsyncImplVisitor::visitUnitEnd(const UnitPtr&)
5045 {
5046     H << sp << nl << '}';
5047     H << nl << "/// \\endcond";
5048 }
5049 
5050 bool
visitModuleStart(const ModulePtr & p)5051 Slice::Gen::AsyncImplVisitor::visitModuleStart(const ModulePtr& p)
5052 {
5053     if(!p->hasNonLocalClassDecls() || !p->hasContentsWithMetaData("amd"))
5054     {
5055         return false;
5056     }
5057 
5058     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
5059 
5060     string name = fixKwd(p->name());
5061 
5062     H << sp << nl << "namespace " << name << nl << '{';
5063 
5064     return true;
5065 }
5066 
5067 void
visitModuleEnd(const ModulePtr &)5068 Slice::Gen::AsyncImplVisitor::visitModuleEnd(const ModulePtr&)
5069 {
5070     H << sp << nl << '}';
5071 
5072     _useWstring = resetUseWstring(_useWstringHist);
5073 }
5074 
5075 bool
visitClassDefStart(const ClassDefPtr & p)5076 Slice::Gen::AsyncImplVisitor::visitClassDefStart(const ClassDefPtr& p)
5077 {
5078     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
5079     return true;
5080 }
5081 
5082 void
visitClassDefEnd(const ClassDefPtr &)5083 Slice::Gen::AsyncImplVisitor::visitClassDefEnd(const ClassDefPtr&)
5084 {
5085     _useWstring = resetUseWstring(_useWstringHist);
5086 }
5087 
5088 void
visitOperation(const OperationPtr & p)5089 Slice::Gen::AsyncImplVisitor::visitOperation(const OperationPtr& p)
5090 {
5091     ContainerPtr container = p->container();
5092     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
5093 
5094     if(cl->isLocal() || (!cl->hasMetaData("amd") && !p->hasMetaData("amd")))
5095     {
5096         return;
5097     }
5098 
5099     string name = p->name();
5100 
5101     string classNameAMD = "AMD_" + cl->name();
5102     string classScope = fixKwd(cl->scope());
5103     string classScopedAMD = classScope + classNameAMD;
5104 
5105     string params;
5106     string paramsDecl;
5107     string args;
5108 
5109     TypePtr ret = p->returnType();
5110     string retS = inputTypeToString(ret, p->returnIsOptional(), "", p->getMetaData(), _useWstring);
5111 
5112     if(ret)
5113     {
5114         params += retS;
5115         paramsDecl += retS;
5116         paramsDecl += ' ';
5117         paramsDecl += "ret";
5118         args += "ret";
5119     }
5120 
5121     ParamDeclList outParams;
5122     ParamDeclList paramList = p->parameters();
5123     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
5124     {
5125         if((*q)->isOutParam())
5126         {
5127             string paramName = fixKwd((*q)->name());
5128             TypePtr type = (*q)->type();
5129             string typeString = inputTypeToString(type, (*q)->optional(), "", (*q)->getMetaData(), _useWstring);
5130 
5131             if(ret || !outParams.empty())
5132             {
5133                 params += ", ";
5134                 paramsDecl += ", ";
5135                 args += ", ";
5136             }
5137 
5138             params += typeString;
5139             paramsDecl += typeString;
5140             paramsDecl += ' ';
5141             paramsDecl += paramName;
5142             args += paramName;
5143 
5144             outParams.push_back(*q);
5145         }
5146     }
5147 
5148     H.zeroIndent();
5149     H << sp;
5150     H << nl << "#if defined(_MSC_VER) && (_MSC_VER >= 1900)";
5151     H << nl << "#   pragma warning(push)";
5152     H << nl << "#   pragma warning(disable:4239)";
5153     H << nl << "#endif";
5154     H.restoreIndent();
5155 
5156     H << sp << nl << "class " << _dllExport << classNameAMD << '_' << name
5157       << " : public " << classScopedAMD  << '_' << name << ", public ::IceInternal::IncomingAsync";
5158     H << sb;
5159     H.dec();
5160     H << nl << "public:";
5161     H.inc();
5162 
5163     H << sp;
5164     H << nl << classNameAMD << '_' << name << "(::IceInternal::Incoming&);";
5165 
5166     H << sp;
5167     H << nl << "virtual void ice_response(" << params << ");";
5168     H << eb << ';';
5169 
5170     H.zeroIndent();
5171     H << sp;
5172     H << nl << "#if defined(_MSC_VER) && (_MSC_VER >= 1900)";
5173     H << nl << "#   pragma warning(pop)";
5174     H << nl << "#endif";
5175     H.restoreIndent();
5176 
5177     C << sp;
5178     C << nl << "/// \\cond INTERNAL";
5179     C << nl << "IceAsync" << classScopedAMD << '_' << name << "::" << classNameAMD << '_' << name
5180       << "(::IceInternal::Incoming& in) :";
5181     C.inc();
5182     C << nl << "::IceInternal::IncomingAsync(in)";
5183     C.dec();
5184     C << sb;
5185     C << eb;
5186 
5187     C << sp << nl << "void";
5188     C << nl << "IceAsync" << classScopedAMD << '_' << name << "::ice_response(" << paramsDecl << ')';
5189     C << sb;
5190     if(ret || !outParams.empty())
5191     {
5192         C << nl << "::Ice::OutputStream* ostr = startWriteParams();";
5193         writeMarshalCode(C, outParams, p, false, TypeContextInParam);
5194         if(p->returnsClasses(false))
5195         {
5196             C << nl << "ostr->writePendingValues();";
5197         }
5198         C << nl << "endWriteParams();";
5199     }
5200     else
5201     {
5202         C << nl << "writeEmptyParams();";
5203     }
5204     C << nl << "completed();";
5205     C << eb;
5206     C << nl << "/// \\endcond";
5207 }
5208 
StreamVisitor(Output & h,Output & c,const string & dllExport)5209 Slice::Gen::StreamVisitor::StreamVisitor(Output& h, Output& c, const string& dllExport) :
5210     H(h),
5211     C(c),
5212     _dllExport(dllExport)
5213 {
5214 }
5215 
5216 bool
visitModuleStart(const ModulePtr & m)5217 Slice::Gen::StreamVisitor::visitModuleStart(const ModulePtr& m)
5218 {
5219     if(!m->hasNonLocalContained(Contained::ContainedTypeStruct) &&
5220        !m->hasNonLocalContained(Contained::ContainedTypeEnum) &&
5221        !m->hasNonLocalContained(Contained::ContainedTypeClass) &&
5222        !m->hasNonLocalContained(Contained::ContainedTypeException))
5223     {
5224         return false;
5225     }
5226 
5227     if(UnitPtr::dynamicCast(m->container()))
5228     {
5229         //
5230         // Only emit this for the top-level module.
5231         //
5232         H << sp;
5233         H << nl << "/// \\cond STREAM";
5234         H << nl << "namespace Ice" << nl << '{' << sp;
5235 
5236         C << sp;
5237         C << nl << "namespace Ice" << nl << '{';
5238     }
5239 
5240     return true;
5241 }
5242 
5243 void
visitModuleEnd(const ModulePtr & m)5244 Slice::Gen::StreamVisitor::visitModuleEnd(const ModulePtr& m)
5245 {
5246     if(UnitPtr::dynamicCast(m->container()))
5247     {
5248         //
5249         // Only emit this for the top-level module.
5250         //
5251         H << nl << '}';
5252         H << nl << "/// \\endcond";
5253         C << nl << '}';
5254     }
5255 }
5256 
5257 bool
visitClassDefStart(const ClassDefPtr & c)5258 Slice::Gen::StreamVisitor::visitClassDefStart(const ClassDefPtr& c)
5259 {
5260     if(!c->isLocal())
5261     {
5262         writeStreamHelpers(H, c, c->dataMembers(), c->hasBaseDataMembers(), true, false);
5263     }
5264     return false;
5265 }
5266 
5267 bool
visitExceptionStart(const ExceptionPtr & p)5268 Slice::Gen::StreamVisitor::visitExceptionStart(const ExceptionPtr& p)
5269 {
5270     if(!p->isLocal())
5271     {
5272         string scoped = p->scoped();
5273         H << nl << "template<>";
5274         H << nl << "struct StreamableTraits< " << fixKwd(scoped) << ">";
5275         H << sb;
5276         H << nl << "static const StreamHelperCategory helper = StreamHelperCategoryUserException;";
5277         H << eb << ";" << nl;
5278 
5279         writeStreamHelpers(H, p, p->dataMembers(), p->hasBaseDataMembers(), true, false);
5280     }
5281     return false;
5282 }
5283 
5284 bool
visitStructStart(const StructPtr & p)5285 Slice::Gen::StreamVisitor::visitStructStart(const StructPtr& p)
5286 {
5287     if(!p->isLocal())
5288     {
5289         bool classMetaData = findMetaData(p->getMetaData(), false) == "%class";
5290         string scoped = p->scoped();
5291 
5292         string fullStructName = classMetaData ? fixKwd(scoped + "Ptr") : fixKwd(scoped);
5293 
5294         H << nl << "template<>";
5295 
5296         H << nl << "struct StreamableTraits< " << fullStructName << ">";
5297 
5298         H << sb;
5299         if(classMetaData)
5300         {
5301             H << nl << "static const StreamHelperCategory helper = StreamHelperCategoryStructClass;";
5302         }
5303         else
5304         {
5305             H << nl << "static const StreamHelperCategory helper = StreamHelperCategoryStruct;";
5306         }
5307         H << nl << "static const int minWireSize = " << p->minWireSize() << ";";
5308         if(p->isVariableLength())
5309         {
5310             H << nl << "static const bool fixedLength = false;";
5311         }
5312         else
5313         {
5314             H << nl << "static const bool fixedLength = true;";
5315         }
5316         H << eb << ";" << nl;
5317 
5318         writeStreamHelpers(H, p, p->dataMembers(), false, true, false);
5319     }
5320     return false;
5321 }
5322 
5323 void
visitEnum(const EnumPtr & p)5324 Slice::Gen::StreamVisitor::visitEnum(const EnumPtr& p)
5325 {
5326     if(!p->isLocal())
5327     {
5328         string scoped = fixKwd(p->scoped());
5329         H << nl << "template<>";
5330         H << nl << "struct StreamableTraits< " << scoped << ">";
5331         H << sb;
5332         H << nl << "static const StreamHelperCategory helper = StreamHelperCategoryEnum;";
5333         H << nl << "static const int minValue = " << p->minValue() << ";";
5334         H << nl << "static const int maxValue = " << p->maxValue() << ";";
5335         H << nl << "static const int minWireSize = " << p->minWireSize() << ";";
5336         H << nl << "static const bool fixedLength = false;";
5337         H << eb << ";" << nl;
5338     }
5339 }
5340 
5341 void
validateMetaData(const UnitPtr & u)5342 Slice::Gen::validateMetaData(const UnitPtr& u)
5343 {
5344     MetaDataVisitor visitor;
5345     u->visit(&visitor, false);
5346 }
5347 
5348 bool
visitUnitStart(const UnitPtr & p)5349 Slice::Gen::MetaDataVisitor::visitUnitStart(const UnitPtr& p)
5350 {
5351     static const string prefix = "cpp:";
5352 
5353     //
5354     // Validate global metadata in the top-level file and all included files.
5355     // Note that these metadata can only be cpp:, never cpp98: or cpp11:
5356     //
5357     StringList files = p->allFiles();
5358 
5359     for(StringList::iterator q = files.begin(); q != files.end(); ++q)
5360     {
5361         string file = *q;
5362         DefinitionContextPtr dc = p->findDefinitionContext(file);
5363         assert(dc);
5364         StringList globalMetaData = dc->getMetaData();
5365         int headerExtension = 0;
5366         int sourceExtension = 0;
5367         int dllExport = 0;
5368         for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end();)
5369         {
5370             string s = *r++;
5371             if(s.find(prefix) == 0)
5372             {
5373                 static const string cppIncludePrefix = "cpp:include:";
5374                 static const string cppHeaderExtPrefix = "cpp:header-ext:";
5375                 static const string cppSourceExtPrefix = "cpp:source-ext:";
5376                 static const string cppDllExportPrefix = "cpp:dll-export:";
5377                 static const string cppDoxygenIncludePrefix = "cpp:doxygen:include:";
5378 
5379                 if(s.find(cppIncludePrefix) == 0 && s.size() > cppIncludePrefix.size())
5380                 {
5381                     continue;
5382                 }
5383                 else if(s.find(cppHeaderExtPrefix) == 0 && s.size() > cppHeaderExtPrefix.size())
5384                 {
5385                     headerExtension++;
5386                     if(headerExtension > 1)
5387                     {
5388                         ostringstream ostr;
5389                         ostr << "ignoring invalid global metadata `" << s
5390                              << "': directive can appear only once per file";
5391                         dc->warning(InvalidMetaData, file, -1, ostr.str());
5392                         globalMetaData.remove(s);
5393                     }
5394                     continue;
5395                 }
5396                 else if(s.find(cppSourceExtPrefix) == 0 && s.size() > cppSourceExtPrefix.size())
5397                 {
5398                     sourceExtension++;
5399                     if(sourceExtension > 1)
5400                     {
5401                         ostringstream ostr;
5402                         ostr << "ignoring invalid global metadata `" << s
5403                              << "': directive can appear only once per file";
5404                         dc->warning(InvalidMetaData, file, -1, ostr.str());
5405                         globalMetaData.remove(s);
5406                     }
5407                     continue;
5408                 }
5409                 else if(s.find(cppDllExportPrefix) == 0 && s.size() > cppDllExportPrefix.size())
5410                 {
5411                     dllExport++;
5412                     if(dllExport > 1)
5413                     {
5414                         ostringstream ostr;
5415                         ostr << "ignoring invalid global metadata `" << s
5416                              << "': directive can appear only once per file";
5417                         dc->warning(InvalidMetaData, file, -1, ostr.str());
5418 
5419                         globalMetaData.remove(s);
5420                     }
5421                     continue;
5422                 }
5423                 else if(s.find(cppDoxygenIncludePrefix) == 0 && s.size() > cppDoxygenIncludePrefix.size())
5424                 {
5425                     continue;
5426                 }
5427 
5428                 ostringstream ostr;
5429                 ostr << "ignoring invalid global metadata `" << s << "'";
5430                 dc->warning(InvalidMetaData, file, -1, ostr.str());
5431                 globalMetaData.remove(s);
5432             }
5433 
5434         }
5435         dc->setMetaData(globalMetaData);
5436     }
5437 
5438     return true;
5439 }
5440 
5441 bool
visitModuleStart(const ModulePtr & p)5442 Slice::Gen::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
5443 {
5444     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5445     p->setMetaData(metaData);
5446     return true;
5447 }
5448 
5449 void
visitModuleEnd(const ModulePtr &)5450 Slice::Gen::MetaDataVisitor::visitModuleEnd(const ModulePtr&)
5451 {
5452 }
5453 
5454 void
visitClassDecl(const ClassDeclPtr & p)5455 Slice::Gen::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
5456 {
5457     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5458     p->setMetaData(metaData);
5459 }
5460 
5461 bool
visitClassDefStart(const ClassDefPtr & p)5462 Slice::Gen::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
5463 {
5464     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5465     p->setMetaData(metaData);
5466     return true;
5467 }
5468 
5469 void
visitClassDefEnd(const ClassDefPtr &)5470 Slice::Gen::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
5471 {
5472 }
5473 
5474 bool
visitExceptionStart(const ExceptionPtr & p)5475 Slice::Gen::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
5476 {
5477     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5478     p->setMetaData(metaData);
5479     return true;
5480 }
5481 
5482 void
visitExceptionEnd(const ExceptionPtr &)5483 Slice::Gen::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
5484 {
5485 }
5486 
5487 bool
visitStructStart(const StructPtr & p)5488 Slice::Gen::MetaDataVisitor::visitStructStart(const StructPtr& p)
5489 {
5490     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5491     p->setMetaData(metaData);
5492     return true;
5493 }
5494 
5495 void
visitStructEnd(const StructPtr &)5496 Slice::Gen::MetaDataVisitor::visitStructEnd(const StructPtr&)
5497 {
5498 }
5499 
5500 void
visitOperation(const OperationPtr & p)5501 Slice::Gen::MetaDataVisitor::visitOperation(const OperationPtr& p)
5502 {
5503     ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container());
5504 
5505     StringList metaData = p->getMetaData();
5506 
5507     const UnitPtr ut = p->unit();
5508     const DefinitionContextPtr dc = ut->findDefinitionContext(p->file());
5509     assert(dc);
5510     if(!cl->isLocal() && p->hasMetaData("cpp:noexcept"))
5511     {
5512         dc->warning(InvalidMetaData, p->file(), p->line(), "ignoring metadata `cpp:noexcept' for non local interface");
5513         metaData.remove("cpp:noexcept");
5514     }
5515 
5516     TypePtr returnType = p->returnType();
5517     if(!returnType)
5518     {
5519         for(StringList::const_iterator q = metaData.begin(); q != metaData.end();)
5520         {
5521             string s = *q++;
5522             if(s.find("cpp:type:") == 0 || s.find("cpp:view-type:") == 0 ||
5523                s.find("cpp:range") == 0 || s == "cpp:array")
5524             {
5525                 dc->warning(InvalidMetaData, p->file(), p->line(),
5526                             "ignoring invalid metadata `" + s + "' for operation with void return type");
5527                 metaData.remove(s);
5528             }
5529         }
5530     }
5531     else
5532     {
5533         metaData = validate(returnType, metaData, p->file(), p->line(), true);
5534     }
5535 
5536     p->setMetaData(metaData);
5537 
5538     ParamDeclList params = p->parameters();
5539     for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q)
5540     {
5541         metaData = validate((*q)->type(), (*q)->getMetaData(), p->file(), (*q)->line(), true);
5542         (*q)->setMetaData(metaData);
5543     }
5544 }
5545 
5546 void
visitDataMember(const DataMemberPtr & p)5547 Slice::Gen::MetaDataVisitor::visitDataMember(const DataMemberPtr& p)
5548 {
5549     StringList metaData = validate(p->type(), p->getMetaData(), p->file(), p->line());
5550     p->setMetaData(metaData);
5551 }
5552 
5553 void
visitSequence(const SequencePtr & p)5554 Slice::Gen::MetaDataVisitor::visitSequence(const SequencePtr& p)
5555 {
5556     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5557     p->setMetaData(metaData);
5558 }
5559 
5560 void
visitDictionary(const DictionaryPtr & p)5561 Slice::Gen::MetaDataVisitor::visitDictionary(const DictionaryPtr& p)
5562 {
5563     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5564     p->setMetaData(metaData);
5565 }
5566 
5567 void
visitEnum(const EnumPtr & p)5568 Slice::Gen::MetaDataVisitor::visitEnum(const EnumPtr& p)
5569 {
5570     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5571     p->setMetaData(metaData);
5572 }
5573 
5574 void
visitConst(const ConstPtr & p)5575 Slice::Gen::MetaDataVisitor::visitConst(const ConstPtr& p)
5576 {
5577     StringList metaData = validate(p, p->getMetaData(), p->file(), p->line());
5578     p->setMetaData(metaData);
5579 }
5580 
5581 StringList
validate(const SyntaxTreeBasePtr & cont,const StringList & metaData,const string & file,const string & line,bool operation)5582 Slice::Gen::MetaDataVisitor::validate(const SyntaxTreeBasePtr& cont, const StringList& metaData,
5583                                       const string& file, const string& line, bool operation)
5584 {
5585     static const string cppPrefix = "cpp:";
5586     static const string cpp11Prefix = "cpp11:";
5587     static const string cpp98Prefix  = "cpp98:";
5588 
5589     const UnitPtr ut = cont->unit();
5590     const DefinitionContextPtr dc = ut->findDefinitionContext(file);
5591     assert(dc);
5592     StringList newMetaData = metaData;
5593     for(StringList::const_iterator p = newMetaData.begin(); p != newMetaData.end();)
5594     {
5595         string s = *p++;
5596 
5597         string prefix;
5598         bool cpp98 = false;
5599         bool cpp11 = false;
5600 
5601         if(s.find(cppPrefix) == 0)
5602         {
5603             prefix = cppPrefix;
5604         }
5605         else if(s.find(cpp98Prefix) == 0)
5606         {
5607             prefix = cpp98Prefix;
5608             cpp98 = true;
5609         }
5610         else if(s.find(cpp11Prefix) == 0)
5611         {
5612             prefix = cpp11Prefix;
5613             cpp11 = true;
5614         }
5615 
5616         if(operation && (s == "cpp:const" || s == "cpp:noexcept"))
5617         {
5618             continue;
5619         }
5620 
5621         if(!prefix.empty())
5622         {
5623             string ss = s.substr(prefix.size());
5624             if(ss == "type:wstring" || ss == "type:string")
5625             {
5626                 BuiltinPtr builtin = BuiltinPtr::dynamicCast(cont);
5627                 ModulePtr module = ModulePtr::dynamicCast(cont);
5628                 ClassDefPtr clss = ClassDefPtr::dynamicCast(cont);
5629                 StructPtr strct = StructPtr::dynamicCast(cont);
5630                 ExceptionPtr exception = ExceptionPtr::dynamicCast(cont);
5631                 if((builtin && builtin->kind() == Builtin::KindString) || module || clss || strct || exception)
5632                 {
5633                     continue;
5634                 }
5635             }
5636             if(BuiltinPtr::dynamicCast(cont) && (ss.find("type:") == 0 || ss.find("view-type:") == 0))
5637             {
5638                 if(BuiltinPtr::dynamicCast(cont)->kind() == Builtin::KindString)
5639                 {
5640                     continue;
5641                 }
5642             }
5643             if(SequencePtr::dynamicCast(cont))
5644             {
5645                 if(ss.find("type:") == 0 || ss.find("view-type:") == 0 || ss == "array" || ss.find("range") == 0)
5646                 {
5647                     continue;
5648                 }
5649             }
5650             if(DictionaryPtr::dynamicCast(cont) && (ss.find("type:") == 0 || ss.find("view-type:") == 0))
5651             {
5652                 continue;
5653             }
5654             if(!cpp11 && StructPtr::dynamicCast(cont) && (ss == "class" || ss == "comparable"))
5655             {
5656                 continue;
5657             }
5658 
5659             {
5660                 ClassDefPtr cl = ClassDefPtr::dynamicCast(cont);
5661                 if(cl && ((!cpp11 && ss == "virtual") ||
5662                           (cl->isLocal() && ss.find("type:") == 0) ||
5663                           (!cpp11 && cl->isLocal() && ss == "comparable")))
5664                 {
5665                     continue;
5666                 }
5667             }
5668             if(ExceptionPtr::dynamicCast(cont) && ss == "ice_print")
5669             {
5670                 continue;
5671             }
5672             if(!cpp11 && EnumPtr::dynamicCast(cont) && ss == "scoped")
5673             {
5674                 continue;
5675             }
5676             if(!cpp98 && EnumPtr::dynamicCast(cont) && ss == "unscoped")
5677             {
5678                 continue;
5679             }
5680 
5681             {
5682                 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(cont);
5683                 if(cl && cl->isLocal() && ss.find("type:") == 0)
5684                 {
5685                     continue;
5686                 }
5687             }
5688 
5689             dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + s + "'");
5690             newMetaData.remove(s);
5691             continue;
5692         }
5693 
5694         if(s.find("delegate") == 0)
5695         {
5696             ClassDefPtr cl = ClassDefPtr::dynamicCast(cont);
5697             if(cl && cl->isDelegate())
5698             {
5699                 continue;
5700             }
5701 
5702             dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + s + "'");
5703             newMetaData.remove(s);
5704             continue;
5705         }
5706     }
5707     return newMetaData;
5708 }
5709 
5710 void
normalizeMetaData(const UnitPtr & u,bool cpp11)5711 Slice::Gen::normalizeMetaData(const UnitPtr& u, bool cpp11)
5712 {
5713     NormalizeMetaDataVisitor visitor(cpp11);
5714     u->visit(&visitor, false);
5715 }
5716 
NormalizeMetaDataVisitor(bool cpp11)5717 Slice::Gen::NormalizeMetaDataVisitor::NormalizeMetaDataVisitor(bool cpp11) :
5718     _cpp11(cpp11)
5719 {
5720 }
5721 
5722 bool
visitUnitStart(const UnitPtr &)5723 Slice::Gen::NormalizeMetaDataVisitor::visitUnitStart(const UnitPtr&)
5724 {
5725     return true;
5726 }
5727 
5728 bool
visitModuleStart(const ModulePtr & p)5729 Slice::Gen::NormalizeMetaDataVisitor::visitModuleStart(const ModulePtr& p)
5730 {
5731     p->setMetaData(normalize(p->getMetaData()));
5732     return true;
5733 }
5734 
5735 void
visitModuleEnd(const ModulePtr &)5736 Slice::Gen::NormalizeMetaDataVisitor::visitModuleEnd(const ModulePtr&)
5737 {
5738 }
5739 
5740 void
visitClassDecl(const ClassDeclPtr & p)5741 Slice::Gen::NormalizeMetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
5742 {
5743     p->setMetaData(normalize(p->getMetaData()));
5744 }
5745 
5746 bool
visitClassDefStart(const ClassDefPtr & p)5747 Slice::Gen::NormalizeMetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
5748 {
5749     p->setMetaData(normalize(p->getMetaData()));
5750     return true;
5751 }
5752 
5753 void
visitClassDefEnd(const ClassDefPtr &)5754 Slice::Gen::NormalizeMetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
5755 {
5756 }
5757 
5758 bool
visitExceptionStart(const ExceptionPtr & p)5759 Slice::Gen::NormalizeMetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
5760 {
5761     p->setMetaData(normalize(p->getMetaData()));
5762     return true;
5763 }
5764 
5765 void
visitExceptionEnd(const ExceptionPtr &)5766 Slice::Gen::NormalizeMetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
5767 {
5768 }
5769 
5770 bool
visitStructStart(const StructPtr & p)5771 Slice::Gen::NormalizeMetaDataVisitor::visitStructStart(const StructPtr& p)
5772 {
5773     p->setMetaData(normalize(p->getMetaData()));
5774     return true;
5775 }
5776 
5777 void
visitStructEnd(const StructPtr &)5778 Slice::Gen::NormalizeMetaDataVisitor::visitStructEnd(const StructPtr&)
5779 {
5780 }
5781 
5782 void
visitOperation(const OperationPtr & p)5783 Slice::Gen::NormalizeMetaDataVisitor::visitOperation(const OperationPtr& p)
5784 {
5785     p->setMetaData(normalize(p->getMetaData()));
5786 
5787     ParamDeclList params = p->parameters();
5788     for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q)
5789     {
5790         (*q)->setMetaData(normalize((*q)->getMetaData()));
5791     }
5792 }
5793 
5794 void
visitDataMember(const DataMemberPtr & p)5795 Slice::Gen::NormalizeMetaDataVisitor::visitDataMember(const DataMemberPtr& p)
5796 {
5797     p->setMetaData(normalize(p->getMetaData()));
5798 }
5799 
5800 void
visitSequence(const SequencePtr & p)5801 Slice::Gen::NormalizeMetaDataVisitor::visitSequence(const SequencePtr& p)
5802 {
5803     p->setMetaData(normalize(p->getMetaData()));
5804 }
5805 
5806 void
visitDictionary(const DictionaryPtr & p)5807 Slice::Gen::NormalizeMetaDataVisitor::visitDictionary(const DictionaryPtr& p)
5808 {
5809     p->setMetaData(normalize(p->getMetaData()));
5810 }
5811 
5812 void
visitEnum(const EnumPtr & p)5813 Slice::Gen::NormalizeMetaDataVisitor::visitEnum(const EnumPtr& p)
5814 {
5815     p->setMetaData(normalize(p->getMetaData()));
5816 }
5817 
5818 void
visitConst(const ConstPtr & p)5819 Slice::Gen::NormalizeMetaDataVisitor::visitConst(const ConstPtr& p)
5820 {
5821     p->setMetaData(normalize(p->getMetaData()));
5822 }
5823 
5824 StringList
normalize(const StringList & metaData)5825 Slice::Gen::NormalizeMetaDataVisitor::normalize(const StringList& metaData)
5826 {
5827     //
5828     // if _cpp11: transform "cpp:" into "cpp-all:" and "cpp"
5829     //            + transform "cpp11:" into "cpp:" in front
5830     //
5831     // if !_cpp11: remove "cpp:", transform "cpp-all:" into "cpp"
5832     //             + transform "cpp98:" into "cpp:" in front
5833 
5834     //
5835     // Note: global metadata like header-ext exists only in cpp:
5836     // form and are not processed at all
5837     //
5838 
5839     StringList result;
5840 
5841     static const string cppPrefixTable[] =
5842     {
5843         "array",
5844         "class",
5845         "comparable",
5846         "const",
5847         "ice_print",
5848         "range",
5849         "scoped",
5850         "type:",
5851         "unscoped",
5852         "view-type:",
5853         "virtual",
5854         ""
5855     };
5856 
5857     static const string cppPrefix = "cpp:";
5858     static const string cppAllPrefix = "cpp-all:";
5859 
5860     //
5861     // First look for the higher priority cpp98/cpp11, that go to the
5862     // front of result
5863     //
5864 
5865     static const string cpp11Prefix = "cpp11:";
5866     static const string cpp98Prefix = "cpp98:";
5867 
5868     const string altCppPrefix = _cpp11 ? cpp11Prefix : cpp98Prefix;
5869 
5870     for(StringList::const_iterator p = metaData.begin(); p != metaData.end(); ++p)
5871     {
5872         string s = *p;
5873 
5874         unsigned int i = 0;
5875         bool found = false;
5876         while(!found)
5877         {
5878             string m = cppPrefixTable[i++];
5879             if(m.empty())
5880             {
5881                 break;
5882             }
5883             if(s.find(altCppPrefix + m) == 0)
5884             {
5885                 found = true;
5886             }
5887         }
5888 
5889         if(found)
5890         {
5891             s.replace(0, altCppPrefix.length(), cppPrefix);
5892             result.push_back(s);
5893         }
5894     }
5895 
5896     //
5897     // Then look for the lower-priority "cpp:" / "cpp-all:", pushed back later
5898     //
5899 
5900     const string prefix = _cpp11 ? cppPrefix : cppAllPrefix;
5901 
5902     for(StringList::const_iterator p = metaData.begin(); p != metaData.end(); ++p)
5903     {
5904         string s = *p;
5905 
5906         unsigned int i = 0;
5907         bool foundPrefix = false;
5908         bool foundOld = false;
5909         while(!foundPrefix && !foundOld)
5910         {
5911             string m = cppPrefixTable[i++];
5912             if(m.empty())
5913             {
5914                 break; // while
5915             }
5916             if(s.find(prefix + m) == 0)
5917             {
5918                 foundPrefix = true;
5919             }
5920             else if(!_cpp11 && s.find(cppPrefix + m) == 0)
5921             {
5922                 //
5923                 // We want to filter-out "cpp:" when !_cpp11
5924                 //
5925                 foundOld = true;
5926             }
5927         }
5928 
5929         if(foundPrefix)
5930         {
5931             if(_cpp11)
5932             {
5933                 result.push_back(s);
5934                 s.replace(0, prefix.length(), cppAllPrefix);
5935                 result.push_back(s);
5936             }
5937             else
5938             {
5939                 s.replace(0, prefix.length(), cppPrefix);
5940                 result.push_back(s);
5941             }
5942         }
5943         else if(_cpp11 || !foundOld)
5944         {
5945             result.push_back(s);
5946         }
5947     }
5948 
5949     return result;
5950 }
5951 
5952 int
setUseWstring(ContainedPtr p,list<int> & hist,int use)5953 Slice::Gen::setUseWstring(ContainedPtr p, list<int>& hist, int use)
5954 {
5955     hist.push_back(use);
5956     StringList metaData = p->getMetaData();
5957     if(find(metaData.begin(), metaData.end(), "cpp:type:wstring") != metaData.end())
5958     {
5959         use = TypeContextUseWstring;
5960     }
5961     else if(find(metaData.begin(), metaData.end(), "cpp:type:string") != metaData.end())
5962     {
5963         use = 0;
5964     }
5965     return use;
5966 }
5967 
5968 int
resetUseWstring(list<int> & hist)5969 Slice::Gen::resetUseWstring(list<int>& hist)
5970 {
5971     int use = hist.back();
5972     hist.pop_back();
5973     return use;
5974 }
5975 
5976 string
getHeaderExt(const string & file,const UnitPtr & ut)5977 Slice::Gen::getHeaderExt(const string& file, const UnitPtr& ut)
5978 {
5979     string ext;
5980     static const string headerExtPrefix = "cpp:header-ext:";
5981     DefinitionContextPtr dc = ut->findDefinitionContext(file);
5982     assert(dc);
5983     string meta = dc->findMetaData(headerExtPrefix);
5984     if(meta.size() > headerExtPrefix.size())
5985     {
5986         ext = meta.substr(headerExtPrefix.size());
5987     }
5988     return ext;
5989 }
5990 
5991 string
getSourceExt(const string & file,const UnitPtr & ut)5992 Slice::Gen::getSourceExt(const string& file, const UnitPtr& ut)
5993 {
5994     string ext;
5995     static const string sourceExtPrefix = "cpp:source-ext:";
5996     DefinitionContextPtr dc = ut->findDefinitionContext(file);
5997     assert(dc);
5998     string meta = dc->findMetaData(sourceExtPrefix);
5999     if(meta.size() > sourceExtPrefix.size())
6000     {
6001         ext = meta.substr(sourceExtPrefix.size());
6002     }
6003     return ext;
6004 }
6005 
6006 // C++11 visitors
Cpp11DeclVisitor(Output & h,Output & c,const string & dllExport)6007 Slice::Gen::Cpp11DeclVisitor::Cpp11DeclVisitor(Output& h, Output& c, const string& dllExport) :
6008     H(h), C(c), _dllExport(dllExport)
6009 {
6010 }
6011 
6012 bool
visitUnitStart(const UnitPtr & p)6013 Slice::Gen::Cpp11DeclVisitor::visitUnitStart(const UnitPtr& p)
6014 {
6015     if(!p->hasClassDecls() && !p->hasNonLocalExceptions())
6016     {
6017         return false;
6018     }
6019     C << sp << nl << "namespace" << nl << "{";
6020     return true;
6021 }
6022 
6023 void
visitUnitEnd(const UnitPtr &)6024 Slice::Gen::Cpp11DeclVisitor::visitUnitEnd(const UnitPtr&)
6025 {
6026     C << sp << nl << "}";
6027 }
6028 
6029 bool
visitModuleStart(const ModulePtr & p)6030 Slice::Gen::Cpp11DeclVisitor::visitModuleStart(const ModulePtr& p)
6031 {
6032     if(p->hasClassDecls())
6033     {
6034         H << sp << nl << "namespace " << fixKwd(p->name()) << nl << '{' << sp;
6035     }
6036     return true;
6037 }
6038 
6039 void
visitModuleEnd(const ModulePtr & p)6040 Slice::Gen::Cpp11DeclVisitor::visitModuleEnd(const ModulePtr& p)
6041 {
6042     if(p->hasClassDecls())
6043     {
6044         H << sp << nl << '}';
6045     }
6046 }
6047 
6048 void
visitClassDecl(const ClassDeclPtr & p)6049 Slice::Gen::Cpp11DeclVisitor::visitClassDecl(const ClassDeclPtr& p)
6050 {
6051     ClassDefPtr def = p->definition();
6052     if(def && def->isDelegate())
6053     {
6054         return;
6055     }
6056 
6057     H << nl << "class " << fixKwd(p->name()) << ';';
6058     if(!p->isLocal() && (p->isInterface() || (def && !def->allOperations().empty())))
6059     {
6060         H << nl << "class " << p->name() << "Prx;";
6061     }
6062 }
6063 
6064 bool
visitClassDefStart(const ClassDefPtr & p)6065 Slice::Gen::Cpp11DeclVisitor::visitClassDefStart(const ClassDefPtr& p)
6066 {
6067     if(p->isLocal())
6068     {
6069         return false;
6070     }
6071 
6072     if(!p->isInterface())
6073     {
6074         C << sp;
6075 
6076         C << nl << "const ::IceInternal::DefaultValueFactoryInit<" << fixKwd(p->scoped()) << "> ";
6077         C << "iceC" + p->flattenedScope() + p->name() + "_init" << "(\"" << p->scoped() << "\");";
6078 
6079         if(p->compactId() >= 0)
6080         {
6081             string n = "iceC" + p->flattenedScope() + p->name() + "_compactIdInit ";
6082             C << nl << "const ::IceInternal::CompactIdInit " << n << "(\"" << p->scoped() << "\", " << p->compactId()
6083               << ");";
6084         }
6085     }
6086 
6087     OperationList allOps = p->allOperations();
6088     if(p->isInterface() || !allOps.empty())
6089     {
6090         C << sp;
6091 
6092         ClassList allBases = p->allBases();
6093         StringList ids;
6094         transform(allBases.begin(), allBases.end(), back_inserter(ids), ::IceUtil::constMemFun(&Contained::scoped));
6095         StringList other;
6096         other.push_back(p->scoped());
6097         other.push_back("::Ice::Object");
6098         other.sort();
6099         ids.merge(other);
6100         ids.unique();
6101 
6102         C << nl << "const ::std::string iceC" << p->flattenedScope() << p->name() << "_ids[" << ids.size() << "] =";
6103         C << sb;
6104         for(StringList::const_iterator r = ids.begin(); r != ids.end();)
6105         {
6106             C << nl << '"' << *r << '"';
6107             if(++r != ids.end())
6108             {
6109                 C << ',';
6110             }
6111         }
6112         C << eb << ';';
6113 
6114         StringList allOpNames;
6115         transform(allOps.begin(), allOps.end(), back_inserter(allOpNames), ::IceUtil::constMemFun(&Contained::name));
6116         allOpNames.push_back("ice_id");
6117         allOpNames.push_back("ice_ids");
6118         allOpNames.push_back("ice_isA");
6119         allOpNames.push_back("ice_ping");
6120         allOpNames.sort();
6121         allOpNames.unique();
6122 
6123         C << nl << "const ::std::string iceC" << p->flattenedScope() << p->name() << "_ops[] =";
6124         C << sb;
6125         for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end();)
6126         {
6127             C << nl << '"' << *q << '"';
6128             if(++q != allOpNames.end())
6129             {
6130                 C << ',';
6131             }
6132         }
6133         C << eb << ';';
6134     }
6135 
6136     return true;
6137 }
6138 
6139 bool
visitExceptionStart(const ExceptionPtr & p)6140 Slice::Gen::Cpp11DeclVisitor::visitExceptionStart(const ExceptionPtr& p)
6141 {
6142     if(p->isLocal())
6143     {
6144         return false;
6145     }
6146 
6147     C << sp;
6148     C << nl << "const ::IceInternal::DefaultUserExceptionFactoryInit<" << fixKwd(p->scoped()) << "> ";
6149     C << "iceC" + p->flattenedScope() + p->name() + "_init" << "(\"" << p->scoped() << "\");";
6150     return false;
6151 }
6152 
6153 void
visitOperation(const OperationPtr & p)6154 Slice::Gen::Cpp11DeclVisitor::visitOperation(const OperationPtr& p)
6155 {
6156     ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container());
6157     if(cl && !cl->isLocal())
6158     {
6159         string flatName = "iceC" + p->flattenedScope() + p->name() + "_name";
6160         C << nl << "const ::std::string " << flatName << " = \"" << p->name() << "\";";
6161     }
6162 }
6163 
Cpp11TypesVisitor(Output & h,Output & c,const string & dllExport)6164 Slice::Gen::Cpp11TypesVisitor::Cpp11TypesVisitor(Output& h, Output& c, const string& dllExport) :
6165     H(h), C(c), _dllExport(dllExport), _dllClassExport(toDllClassExport(dllExport)),
6166     _dllMemberExport(toDllMemberExport(dllExport)), _doneStaticSymbol(false), _useWstring(false)
6167 {
6168 }
6169 
6170 bool
visitModuleStart(const ModulePtr & p)6171 Slice::Gen::Cpp11TypesVisitor::visitModuleStart(const ModulePtr& p)
6172 {
6173     if(!p->hasOtherConstructedOrExceptions())
6174     {
6175         return false;
6176     }
6177 
6178     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
6179     H << sp << nl << "namespace " << fixKwd(p->name()) << nl << '{';
6180     return true;
6181 }
6182 
6183 void
visitModuleEnd(const ModulePtr & p)6184 Slice::Gen::Cpp11TypesVisitor::visitModuleEnd(const ModulePtr& p)
6185 {
6186     if(p->hasStructs())
6187     {
6188         H << sp << nl << "using Ice::operator<;";
6189         H << nl << "using Ice::operator<=;";
6190         H << nl << "using Ice::operator>;";
6191         H << nl << "using Ice::operator>=;";
6192         H << nl << "using Ice::operator==;";
6193         H << nl << "using Ice::operator!=;";
6194     }
6195     H << sp << nl << '}';
6196     _useWstring = resetUseWstring(_useWstringHist);
6197 }
6198 
6199 bool
visitClassDefStart(const ClassDefPtr &)6200 Slice::Gen::Cpp11TypesVisitor::visitClassDefStart(const ClassDefPtr&)
6201 {
6202     return false;
6203 }
6204 
6205 bool
visitExceptionStart(const ExceptionPtr & p)6206 Slice::Gen::Cpp11TypesVisitor::visitExceptionStart(const ExceptionPtr& p)
6207 {
6208     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
6209 
6210     string name = fixKwd(p->name());
6211     string scope = fixKwd(p->scope());
6212     string scoped = fixKwd(p->scoped());
6213     ExceptionPtr base = p->base();
6214     DataMemberList dataMembers = p->dataMembers();
6215     DataMemberList allDataMembers = p->allDataMembers();
6216     DataMemberList baseDataMembers;
6217 
6218     vector<string> params;
6219     vector<string> allParamDecls;
6220     vector<string> baseParams;
6221     map<string, CommentPtr> allComments;
6222 
6223     string fileParam = "file";
6224     string lineParam = "line";
6225 
6226     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
6227     {
6228         params.push_back(fixKwd((*q)->name()));
6229     }
6230 
6231     for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
6232     {
6233         string typeName = inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(),
6234                                             _useWstring | TypeContextCpp11);
6235         allParamDecls.push_back(typeName + " " + fixKwd((*q)->name()));
6236 
6237         CommentPtr comment = (*q)->parseComment(false);
6238         if(comment)
6239         {
6240             allComments[(*q)->name()] = comment;
6241         }
6242 
6243         if((*q)->name() == "file")
6244         {
6245             fileParam = "file_";
6246         }
6247         else if((*q)->name() == "line")
6248         {
6249             fileParam = "line_";
6250         }
6251     }
6252 
6253     if(base)
6254     {
6255         baseDataMembers = base->allDataMembers();
6256         for(DataMemberList::const_iterator q = baseDataMembers.begin(); q != baseDataMembers.end(); ++q)
6257         {
6258             baseParams.push_back(fixKwd((*q)->name()));
6259         }
6260     }
6261 
6262     string helperClass =
6263         getUnqualified(p->isLocal() ? "::Ice::LocalExceptionHelper" : "::Ice::UserExceptionHelper", scope);
6264     string baseClass = base ?
6265         getUnqualified(fixKwd(base->scoped()), scope) :
6266         getUnqualified(p->isLocal() ? "::Ice::LocalException" : "::Ice::UserException", scope);
6267     string templateParameters = name + ", " + baseClass;
6268 
6269     H << sp;
6270     writeDocSummary(H, p);
6271     H << nl << "class " << _dllClassExport << name << " : public " << helperClass << "<" << templateParameters << ">";
6272     H << sb;
6273 
6274     H.dec();
6275     H << nl << "public:";
6276     H.inc();
6277 
6278     // Out of line dtor to avoid weak vtable
6279     H << sp << nl << _dllMemberExport << "virtual ~" << name << "();";
6280 
6281     // Default copy ctor
6282     H << sp << nl << name << "(const " << name << "&) = default;";
6283 
6284     C << sp;
6285     C << nl << scoped.substr(2) << "::~" << name << "()";
6286     C << sb;
6287     C << eb;
6288 
6289     if(p->isLocal())
6290     {
6291         H << sp;
6292         H << nl << "/**";
6293         H << nl << " * The file and line number are required for all local exceptions.";
6294         H << nl << " * @param " << fileParam
6295           << " The file name in which the exception was raised, typically __FILE__.";
6296         H << nl << " * @param " << lineParam
6297           << " The line number at which the exception was raised, typically __LINE__.";
6298         H << nl << " */";
6299         H << nl << name << "(const char* " << fileParam << ", int " << lineParam << ") : ";
6300         H << getUnqualified("::Ice::LocalExceptionHelper", scope) << "<" << templateParameters << ">";
6301         H << "(" << fileParam << ", " << lineParam << ")";
6302         H << sb;
6303         H << eb;
6304     }
6305     else
6306     {
6307         H << sp << nl << name << "() = default;";
6308     }
6309 
6310     if(!allDataMembers.empty())
6311     {
6312         H << sp;
6313         H << nl << "/**";
6314         H << nl << " * One-shot constructor to initialize all data members.";
6315         if(p->isLocal())
6316         {
6317             H << nl << " * The file and line number are required for all local exceptions.";
6318             H << nl << " * @param " << fileParam
6319               << " The file name in which the exception was raised, typically __FILE__.";
6320             H << nl << " * @param " << lineParam
6321               << " The line number at which the exception was raised, typically __LINE__.";
6322         }
6323         for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
6324         {
6325             map<string, CommentPtr>::iterator r = allComments.find((*q)->name());
6326             if(r != allComments.end())
6327             {
6328                 H << nl << " * @param " << fixKwd(r->first) << " " << getDocSentence(r->second->overview());
6329             }
6330         }
6331         H << nl << " */";
6332         H << nl << name << "(";
6333         if(p->isLocal())
6334         {
6335             H << "const char* " << fileParam << ", int " << lineParam;
6336             if(!allParamDecls.empty())
6337             {
6338                 H << ", ";
6339             }
6340         }
6341 
6342         for(vector<string>::const_iterator q = allParamDecls.begin(); q != allParamDecls.end(); ++q)
6343         {
6344             if(q != allParamDecls.begin())
6345             {
6346                 H << ", ";
6347             }
6348             H << (*q);
6349         }
6350         H << ") :";
6351         H.inc();
6352         if(base && (p->isLocal() || !baseDataMembers.empty()))
6353         {
6354             H << nl << helperClass << "<" << templateParameters << ">" << "(";
6355             if(p->isLocal())
6356             {
6357                 H << fileParam << ", " << lineParam;
6358                 if(!baseDataMembers.empty())
6359                 {
6360                     H << ", ";
6361                 }
6362             }
6363 
6364             for(DataMemberList::const_iterator q = baseDataMembers.begin(); q != baseDataMembers.end(); ++q)
6365             {
6366                 if(q != baseDataMembers.begin())
6367                 {
6368                     H << ", ";
6369                 }
6370                 if(isMovable((*q)->type()))
6371                 {
6372                     H << "::std::move(" << fixKwd((*q)->name()) << ")";
6373                 }
6374                 else
6375                 {
6376                     H << fixKwd((*q)->name());
6377                 }
6378             }
6379 
6380             H << ")";
6381             if(!dataMembers.empty())
6382             {
6383                 H << ",";
6384             }
6385         }
6386         else if(p->isLocal())
6387         {
6388             H << " " << getUnqualified("::Ice::LocalExceptionHelper", scope) << "<" << templateParameters << ">";
6389             H << "(" << fileParam << ", " << lineParam << ")";
6390             if(!dataMembers.empty())
6391             {
6392                 H << ",";
6393             }
6394         }
6395 
6396         for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
6397         {
6398             string memberName = fixKwd((*q)->name());
6399             if(q != dataMembers.begin())
6400             {
6401                 H << ",";
6402             }
6403             if(isMovable((*q)->type()))
6404             {
6405                 H << nl << memberName << "(::std::move(" << memberName << "))";
6406             }
6407             else
6408             {
6409                 H << nl << memberName << "(" << memberName << ")";
6410             }
6411         }
6412 
6413         H.dec();
6414         H << sb;
6415         H << eb;
6416     }
6417 
6418     H << sp;
6419     H << nl << "/**";
6420     H << nl << " * Obtains a tuple containing all of the exception's data members.";
6421     H << nl << " * @return The data members in a tuple.";
6422     H << nl << " */";
6423     writeIceTuple(H, scope, p->allDataMembers(), _useWstring);
6424 
6425     H << sp;
6426     H << nl << "/**";
6427     H << nl << " * Obtains the Slice type ID of this exception.";
6428     H << nl << " * @return The fully-scoped type ID.";
6429     H << nl << " */";
6430     H << nl << _dllMemberExport << "static const ::std::string& ice_staticId();";
6431 
6432     C << sp << nl << "const ::std::string&" << nl << scoped.substr(2) << "::ice_staticId()";
6433     C << sb;
6434     //
6435     // Use local static so that ice_staticId() is usable during static construction.
6436     //
6437     C << nl << "static const ::std::string typeId = \"" << p->scoped() << "\";";
6438     C << nl << "return typeId;";
6439     C << eb;
6440 
6441     StringList metaData = p->getMetaData();
6442     if(find(metaData.begin(), metaData.end(), "cpp:ice_print") != metaData.end())
6443     {
6444         H << nl << "/**";
6445         H << nl << " * Prints this exception to the given stream.";
6446         H << nl << " * @param stream The target stream.";
6447         H << nl << " */";
6448         H << nl << _dllMemberExport << "virtual void ice_print(::std::ostream& stream) const override;";
6449     }
6450 
6451     if(!p->isLocal() && p->usesClasses(false))
6452     {
6453         if(!base || (base && !base->usesClasses(false)))
6454         {
6455             H << sp;
6456             H << nl << "/// \\cond STREAM";
6457             H << nl << _dllMemberExport << "virtual bool _usesClasses() const override;";
6458             H << nl << "/// \\endcond";
6459 
6460             C << sp;
6461             C << nl << "/// \\cond STREAM";
6462             C << nl << "bool";
6463             C << nl << scoped.substr(2) << "::_usesClasses() const";
6464             C << sb;
6465             C << nl << "return true;";
6466             C << eb;
6467             C << nl << "/// \\endcond";
6468         }
6469     }
6470 
6471     if(!dataMembers.empty())
6472     {
6473         H << sp;
6474     }
6475     return true;
6476 }
6477 
6478 void
visitExceptionEnd(const ExceptionPtr & p)6479 Slice::Gen::Cpp11TypesVisitor::visitExceptionEnd(const ExceptionPtr& p)
6480 {
6481     string name = fixKwd(p->name());
6482     string scope = fixKwd(p->scope());
6483     string scoped = fixKwd(p->scoped());
6484     string factoryName;
6485 
6486     if(!p->isLocal())
6487     {
6488         ExceptionPtr base = p->base();
6489         bool basePreserved = p->inheritsMetaData("preserve-slice");
6490         bool preserved = p->hasMetaData("preserve-slice");
6491 
6492         if(preserved && !basePreserved)
6493         {
6494             H << sp;
6495             H << nl << "/**";
6496             H << nl << " * Obtains the SlicedData object created when an unknown exception type was marshaled";
6497             H << nl << " * in the sliced format and the Ice run time sliced it to a known type.";
6498             H << nl << " * @return The SlicedData object, or nil if the exception was not sliced or was not";
6499             H << nl << " * marshaled in the sliced format.";
6500             H << nl << " */";
6501             H << nl << _dllMemberExport << "virtual ::std::shared_ptr<" << getUnqualified("::Ice::SlicedData", scope)
6502               << "> ice_getSlicedData() const override;";
6503             H << sp;
6504             H << nl << "/// \\cond STREAM";
6505             H << nl << _dllMemberExport << "virtual void _write(" << getUnqualified("::Ice::OutputStream*", scope)
6506               << ") const override;";
6507             H << nl << _dllMemberExport << "virtual void _read(" << getUnqualified("::Ice::InputStream*", scope)
6508               << ") override;";
6509 
6510             H << sp << nl << "::std::shared_ptr<" << getUnqualified("::Ice::SlicedData", scope) << "> _slicedData;";
6511             H << nl << "/// \\endcond";
6512 
6513             C << sp;
6514             C << nl << "::std::shared_ptr<::Ice::SlicedData>" << nl << scoped.substr(2)
6515               << "::ice_getSlicedData() const";
6516             C << sb;
6517             C << nl << "return _slicedData;";
6518             C << eb;
6519 
6520             C << sp;
6521             C << nl << "/// \\cond STREAM";
6522             C << nl << "void" << nl << scoped.substr(2) << "::_write("
6523               << getUnqualified("::Ice::OutputStream*", scope) << " ostr) const";
6524             C << sb;
6525             C << nl << "ostr->startException(_slicedData);";
6526             C << nl << "_writeImpl(ostr);";
6527             C << nl << "ostr->endException();";
6528             C << eb;
6529 
6530             C << sp << nl << "void" << nl << scoped.substr(2) << "::_read("
6531               << getUnqualified("::Ice::InputStream*", scope) << " istr)";
6532             C << sb;
6533             C << nl << "istr->startException();";
6534             C << nl << "_readImpl(istr);";
6535             C << nl << "_slicedData = istr->endException(true);";
6536             C << eb;
6537             C << nl << "/// \\endcond";
6538         }
6539     }
6540     H << eb << ';';
6541 
6542     if(!p->isLocal())
6543     {
6544         //
6545         // We need an instance here to trigger initialization if the implementation is in a shared libarry.
6546         // But we do this only once per source file, because a single instance is sufficient to initialize
6547         // all of the globals in a shared library.
6548         //
6549         if(!_doneStaticSymbol)
6550         {
6551             _doneStaticSymbol = true;
6552             H << sp;
6553             H << nl << "/// \\cond INTERNAL";
6554             H << nl << "static " << name << " _iceS_" << p->name() << "_init;";
6555             H << nl << "/// \\endcond";
6556         }
6557     }
6558 
6559     _useWstring = resetUseWstring(_useWstringHist);
6560 }
6561 
6562 bool
visitStructStart(const StructPtr & p)6563 Slice::Gen::Cpp11TypesVisitor::visitStructStart(const StructPtr& p)
6564 {
6565     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
6566 
6567     H << sp;
6568     writeDocSummary(H, p);
6569     H << nl << "struct " << fixKwd(p->name());
6570     H << sb;
6571 
6572     return true;
6573 }
6574 
6575 void
visitStructEnd(const StructPtr & p)6576 Slice::Gen::Cpp11TypesVisitor::visitStructEnd(const StructPtr& p)
6577 {
6578     H << sp;
6579     H << nl << "/**";
6580     H << nl << " * Obtains a tuple containing all of the exception's data members.";
6581     H << nl << " * @return The data members in a tuple.";
6582     H << nl << " */";
6583     writeIceTuple(H, fixKwd(p->scope()), p->dataMembers(), _useWstring);
6584     H << eb << ';';
6585     _useWstring = resetUseWstring(_useWstringHist);
6586 }
6587 
6588 void
visitDataMember(const DataMemberPtr & p)6589 Slice::Gen::Cpp11TypesVisitor::visitDataMember(const DataMemberPtr& p)
6590 {
6591     string scope = fixKwd(ContainedPtr::dynamicCast(p->container())->scope());
6592     string name = fixKwd(p->name());
6593     writeDocSummary(H, p);
6594     H << nl << typeToString(p->type(), p->optional(), scope, p->getMetaData(), _useWstring | TypeContextCpp11)
6595       << ' ' << name;
6596 
6597     string defaultValue = p->defaultValue();
6598     if(!defaultValue.empty())
6599     {
6600         BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type());
6601         if(p->optional() && builtin->kind() == Builtin::KindString)
6602         {
6603             //
6604             // = "<string literal>" doesn't work for optional<std::string>
6605             //
6606             H << '{';
6607             writeConstantValue(H, p->type(), p->defaultValueType(), defaultValue, _useWstring | TypeContextCpp11,
6608                                p->getMetaData(), scope);
6609             H << '}';
6610         }
6611         else
6612         {
6613             H << " = ";
6614             writeConstantValue(H, p->type(), p->defaultValueType(), defaultValue, _useWstring | TypeContextCpp11,
6615                                p->getMetaData(), scope);
6616         }
6617     }
6618 
6619     H << ';';
6620 }
6621 
6622 void
visitSequence(const SequencePtr & p)6623 Slice::Gen::Cpp11TypesVisitor::visitSequence(const SequencePtr& p)
6624 {
6625     string name = fixKwd(p->name());
6626     string scope = fixKwd(p->scope());
6627     TypePtr type = p->type();
6628     int typeCtx = p->isLocal() ? (_useWstring | TypeContextLocal) : _useWstring;
6629     string s = typeToString(type, scope, p->typeMetaData(), typeCtx | TypeContextCpp11);
6630     StringList metaData = p->getMetaData();
6631 
6632     string seqType = findMetaData(metaData, _useWstring);
6633     H << sp;
6634     writeDocSummary(H, p);
6635 
6636     if(!seqType.empty())
6637     {
6638         H << nl << "using " << name << " = " << seqType << ';';
6639     }
6640     else
6641     {
6642         H << nl << "using " << name << " = ::std::vector<" << s << ">;";
6643     }
6644 }
6645 
6646 void
visitDictionary(const DictionaryPtr & p)6647 Slice::Gen::Cpp11TypesVisitor::visitDictionary(const DictionaryPtr& p)
6648 {
6649     string name = fixKwd(p->name());
6650     string scope = fixKwd(p->scope());
6651     string dictType = findMetaData(p->getMetaData());
6652     int typeCtx = p->isLocal() ? (_useWstring | TypeContextLocal) : _useWstring;
6653 
6654     H << sp;
6655     writeDocSummary(H, p);
6656 
6657     if(dictType.empty())
6658     {
6659         //
6660         // A default std::map dictionary
6661         //
6662         TypePtr keyType = p->keyType();
6663         TypePtr valueType = p->valueType();
6664         string ks = typeToString(keyType, scope, p->keyMetaData(), typeCtx | TypeContextCpp11);
6665         string vs = typeToString(valueType, scope, p->valueMetaData(), typeCtx | TypeContextCpp11);
6666 
6667         H << nl << "using " << name << " = ::std::map<" << ks << ", " << vs << ">;";
6668     }
6669     else
6670     {
6671         //
6672         // A custom dictionary
6673         //
6674         H << nl << "using " << name << " = " << dictType << ';';
6675     }
6676 }
6677 
Cpp11ProxyVisitor(Output & h,Output & c,const string & dllExport)6678 Slice::Gen::Cpp11ProxyVisitor::Cpp11ProxyVisitor(Output& h, Output& c, const string& dllExport) :
6679     H(h), C(c), _dllClassExport(toDllClassExport(dllExport)),
6680     _dllMemberExport(toDllMemberExport(dllExport)),
6681     _useWstring(false)
6682 {
6683 }
6684 
6685 bool
visitUnitStart(const UnitPtr &)6686 Slice::Gen::Cpp11ProxyVisitor::visitUnitStart(const UnitPtr&)
6687 {
6688     return true;
6689 }
6690 
6691 void
visitUnitEnd(const UnitPtr &)6692 Slice::Gen::Cpp11ProxyVisitor::visitUnitEnd(const UnitPtr&)
6693 {
6694 }
6695 
6696 bool
visitModuleStart(const ModulePtr & p)6697 Slice::Gen::Cpp11ProxyVisitor::visitModuleStart(const ModulePtr& p)
6698 {
6699     if(!p->hasNonLocalClassDefs())
6700     {
6701         return false;
6702     }
6703 
6704     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
6705 
6706     H << sp << nl << "namespace " << fixKwd(p->name()) << nl << '{';
6707     return true;
6708 }
6709 
6710 void
visitModuleEnd(const ModulePtr &)6711 Slice::Gen::Cpp11ProxyVisitor::visitModuleEnd(const ModulePtr&)
6712 {
6713     H << sp << nl << '}';
6714 
6715     _useWstring = resetUseWstring(_useWstringHist);
6716 }
6717 
6718 bool
visitClassDefStart(const ClassDefPtr & p)6719 Slice::Gen::Cpp11ProxyVisitor::visitClassDefStart(const ClassDefPtr& p)
6720 {
6721     if(p->isLocal() || (!p->isInterface() && p->allOperations().empty()))
6722     {
6723         return false;
6724     }
6725 
6726     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
6727 
6728     string name = fixKwd(p->name());
6729     string scope = fixKwd(p->scope());
6730     string scoped = fixKwd(p->scoped());
6731     ClassList bases = p->bases();
6732 
6733     ClassDefPtr base;
6734     if(!bases.empty() && !bases.front()->isInterface())
6735     {
6736         base = bases.front();
6737     }
6738 
6739     H << sp;
6740     writeDocSummary(H, p);
6741     H << nl << "class " << _dllClassExport << p->name() << "Prx : public virtual "
6742       << getUnqualified("::Ice::Proxy", scope) << "<" << fixKwd(p->name() + "Prx") << ", ";
6743     if(bases.empty() || (base && base->allOperations().empty()))
6744     {
6745         H << getUnqualified("::Ice::ObjectPrx", scope);
6746     }
6747     else
6748     {
6749         ClassList::const_iterator q = bases.begin();
6750         while(q != bases.end())
6751         {
6752             H << getUnqualified(fixKwd((*q)->scoped() + "Prx"), scope);
6753             if(++q != bases.end())
6754             {
6755                 H << ", ";
6756             }
6757         }
6758     }
6759     H << ">";
6760 
6761     H << sb;
6762     H.dec();
6763     H << nl << "public:";
6764     H.inc();
6765     return true;
6766 }
6767 
6768 void
visitClassDefEnd(const ClassDefPtr & p)6769 Slice::Gen::Cpp11ProxyVisitor::visitClassDefEnd(const ClassDefPtr& p)
6770 {
6771     string prx = fixKwd(p->name() + "Prx");
6772     const string suffix = p->isInterface() ? "" : "Disp";
6773     const string scoped = fixKwd(p->scoped() + "Prx");
6774     const string scope = fixKwd(p->scope());
6775 
6776     H << sp;
6777     H << nl << "/**";
6778     H << nl << " * Obtains the Slice type ID of this " << (p->isInterface() ? "interface" : "class") << ".";
6779     H << nl << " * @return The fully-scoped type ID.";
6780     H << nl << " */";
6781     H << nl << _dllMemberExport << "static const ::std::string& ice_staticId();";
6782 
6783     H.dec();
6784     H << sp << nl << "protected:";
6785     H.inc();
6786     H << sp;
6787     H << nl << "/// \\cond INTERNAL";
6788     H << nl << getUnqualified(prx, scope) << "() = default;";
6789     H << nl << "friend ::std::shared_ptr<" << getUnqualified(prx, scope) << "> IceInternal::createProxy<"
6790       << getUnqualified(prx, scope) << ">();";
6791     H << sp;
6792     H << nl << _dllMemberExport << "virtual ::std::shared_ptr<" << getUnqualified("::Ice::ObjectPrx", scope)
6793       << "> _newInstance() const override;";
6794     H << nl << "/// \\endcond";
6795     H << eb << ';';
6796 
6797     C << sp;
6798     C << nl << "/// \\cond INTERNAL";
6799     C << nl << "::std::shared_ptr<::Ice::ObjectPrx>";
6800     C << nl << scoped.substr(2) << "::_newInstance() const";
6801     C << sb;
6802     C << nl << "return ::IceInternal::createProxy<" << getUnqualified(prx, scope) << ">();";
6803     C << eb;
6804     C << nl << "/// \\endcond";
6805     C << sp;
6806     C << nl << "const ::std::string&" << nl << scoped.substr(2) << "::ice_staticId()";
6807     C << sb;
6808     C << nl << "return "<< fixKwd(p->name() + suffix) << "::ice_staticId();";
6809     C << eb;
6810 
6811     _useWstring = resetUseWstring(_useWstringHist);
6812 }
6813 
6814 void
visitOperation(const OperationPtr & p)6815 Slice::Gen::Cpp11ProxyVisitor::visitOperation(const OperationPtr& p)
6816 {
6817     string name = p->name();
6818     string flatName = "iceC" + p->flattenedScope() + p->name() + "_name";
6819 
6820     ContainerPtr container = p->container();
6821     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
6822     string clScope = fixKwd(cl->scope());
6823 
6824     TypePtr ret = p->returnType();
6825 
6826     bool retIsOpt = p->returnIsOptional();
6827     string retS = returnTypeToString(ret, retIsOpt, clScope, p->getMetaData(), _useWstring | TypeContextCpp11);
6828 
6829     vector<string> params;
6830     vector<string> paramsDecl;
6831 
6832     vector<string> inParamsS;
6833     vector<string> inParamsDecl;
6834     vector<string> inParamsImplDecl;
6835 
6836     vector<string> futureOutParams;
6837     vector<string> lambdaOutParams;
6838 
6839     ParamDeclList paramList = p->parameters();
6840     ParamDeclList inParams = p->inParameters();
6841     ParamDeclList outParams = p->outParameters();
6842 
6843     string returnValueS = "returnValue";
6844     bool outParamsHasOpt = false;
6845 
6846     if(ret)
6847     {
6848         futureOutParams.push_back(typeToString(ret, retIsOpt, clScope, p->getMetaData(), _useWstring |
6849                                                TypeContextCpp11));
6850 
6851         lambdaOutParams.push_back(typeToString(ret, retIsOpt, clScope, p->getMetaData(), _useWstring |
6852                                                TypeContextInParam | TypeContextCpp11));
6853 
6854         outParamsHasOpt |= p->returnIsOptional();
6855     }
6856 
6857     for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
6858     {
6859         string paramName = fixKwd((*q)->name());
6860         StringList metaData = (*q)->getMetaData();
6861 
6862         if((*q)->isOutParam())
6863         {
6864             futureOutParams.push_back(typeToString((*q)->type(), (*q)->optional(), clScope, metaData,
6865                                                    _useWstring | TypeContextCpp11));
6866             lambdaOutParams.push_back(typeToString((*q)->type(), (*q)->optional(), clScope, metaData,
6867                                                    _useWstring | TypeContextInParam | TypeContextCpp11));
6868 
6869             string outputTypeString = outputTypeToString((*q)->type(), (*q)->optional(), clScope, metaData,
6870                                                          _useWstring | TypeContextCpp11);
6871 
6872             params.push_back(outputTypeString);
6873             paramsDecl.push_back(outputTypeString + ' ' + paramName);
6874 
6875             outParamsHasOpt |= (*q)->optional();
6876 
6877             if((*q)->name() == "returnValue")
6878             {
6879                 returnValueS = "_returnValue";
6880             }
6881         }
6882         else
6883         {
6884             string typeString = inputTypeToString((*q)->type(), (*q)->optional(), clScope, metaData,
6885                                                   _useWstring | TypeContextCpp11);
6886 
6887             params.push_back(typeString);
6888             paramsDecl.push_back(typeString + ' ' + paramName);
6889 
6890             inParamsS.push_back(typeString);
6891             inParamsDecl.push_back(typeString + ' ' + paramName);
6892             inParamsImplDecl.push_back(typeString + ' ' + paramPrefix + (*q)->name());
6893         }
6894     }
6895 
6896     string scoped = fixKwd(cl->scope() + cl->name() + "Prx" + "::").substr(2);
6897 
6898     const string contextParam = escapeParam(paramList, "context");
6899     const string contextDecl = "const " + getUnqualified("::Ice::Context&", clScope) + " " + contextParam + " = " +
6900         getUnqualified("::Ice::noExplicitContext", clScope);
6901 
6902     string futureT;
6903     if(futureOutParams.empty())
6904     {
6905         futureT = "void";
6906     }
6907     else if(futureOutParams.size() == 1)
6908     {
6909         futureT = futureOutParams[0];
6910     }
6911     else
6912     {
6913         futureT = resultStructName(name, fixKwd(cl->name()));
6914     }
6915 
6916     const string deprecateSymbol = getDeprecateSymbol(p, cl);
6917 
6918     CommentPtr comment = p->parseComment(false);
6919     const string contextDoc = "@param " + contextParam + " The Context map to send with the invocation.";
6920     const string futureDoc = "The future object for the invocation.";
6921 
6922     //
6923     // Synchronous operation
6924     //
6925     H << sp;
6926     if(comment)
6927     {
6928         StringList postParams;
6929         postParams.push_back(contextDoc);
6930         writeOpDocSummary(H, p, comment, OpDocAllParams, true, StringList(), postParams, comment->returns());
6931     }
6932     H << nl << deprecateSymbol << retS << ' ' << fixKwd(name) << spar << paramsDecl << contextDecl << epar;
6933     H << sb;
6934     H << nl;
6935     if(futureOutParams.size() == 1)
6936     {
6937         if(ret)
6938         {
6939             H << "return ";
6940         }
6941         else
6942         {
6943             H << fixKwd((*outParams.begin())->name()) << " = ";
6944         }
6945     }
6946     else if(futureOutParams.size() > 1)
6947     {
6948         H << "auto _result = ";
6949     }
6950 
6951     H << "_makePromiseOutgoing<" << getUnqualified(futureT, cl->scoped()) << ">";
6952 
6953     H << spar << "true, this" << "&" + cl->name() + "Prx::_iceI_" + name;
6954     for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q)
6955     {
6956         H << fixKwd((*q)->name());
6957     }
6958     H << contextParam << epar << ".get();";
6959     if(futureOutParams.size() > 1)
6960     {
6961         for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q)
6962         {
6963             H << nl << fixKwd((*q)->name()) << " = ";
6964             H << condMove(isMovable((*q)->type()), "_result." + fixKwd((*q)->name())) + ";";
6965         }
6966         if(ret)
6967         {
6968             H << nl << "return " + condMove(isMovable(ret), "_result." + returnValueS) + ";";
6969         }
6970     }
6971     H << eb;
6972 
6973     //
6974     // Promise based asynchronous operation
6975     //
6976     H << sp;
6977     if(comment)
6978     {
6979         StringList postParams, returns;
6980         postParams.push_back(contextDoc);
6981         returns.push_back(futureDoc);
6982         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
6983     }
6984     H << nl << "template<template<typename> class P = ::std::promise>";
6985     H << nl << deprecateSymbol << "auto " << name << "Async" << spar << inParamsDecl << contextDecl << epar;
6986     H.inc();
6987     H << nl << "-> decltype(::std::declval<P<" << futureT << ">>().get_future())";
6988     H.dec();
6989     H << sb;
6990 
6991     H << nl << "return _makePromiseOutgoing<" << futureT << ", P>" << spar;
6992 
6993     H << "false, this" << string("&" + cl->name() + "Prx::_iceI_" + name);
6994     for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q)
6995     {
6996         H << fixKwd((*q)->name());
6997     }
6998     H << contextParam << epar << ";";
6999     H << eb;
7000 
7001     //
7002     // Lambda based asynchronous operation
7003     //
7004     bool lambdaCustomOut = (lambdaOutParams != futureOutParams);
7005 
7006     const string responseParam = escapeParam(inParams, "response");
7007     const string exParam = escapeParam(inParams, "ex");
7008     const string sentParam = escapeParam(inParams, "sent");
7009 
7010     H << sp;
7011     if(comment)
7012     {
7013         StringList postParams, returns;
7014         postParams.push_back("@param " + responseParam + " The response callback.");
7015         postParams.push_back("@param " + exParam + " The exception callback.");
7016         postParams.push_back("@param " + sentParam + " The sent callback.");
7017         postParams.push_back(contextDoc);
7018         returns.push_back("A function that can be called to cancel the invocation locally.");
7019         writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
7020     }
7021     H << nl;
7022     if(lambdaCustomOut)
7023     {
7024         H << _dllMemberExport;
7025     }
7026     H << "::std::function<void()>";
7027     H << nl << name << "Async(";
7028     H.useCurrentPosAsIndent();
7029     if(!inParamsDecl.empty())
7030     {
7031         if(lambdaCustomOut)
7032         {
7033             for(vector<string>::const_iterator q = inParamsS.begin(); q != inParamsS.end(); ++q)
7034             {
7035                 if(q != inParamsS.begin())
7036                 {
7037                     H << " ";
7038                 }
7039 
7040                 H << *q << ",";
7041             }
7042         }
7043         else
7044         {
7045             for(vector<string>::const_iterator q = inParamsDecl.begin(); q != inParamsDecl.end(); ++q)
7046             {
7047                 if(q != inParamsDecl.begin())
7048                 {
7049                     H << " ";
7050                 }
7051 
7052                 H << *q << ",";
7053             }
7054         }
7055         H << nl;
7056     }
7057 
7058     H << "::std::function<void" << spar << lambdaOutParams << epar << "> " << responseParam << ",";
7059     H << nl << "::std::function<void(::std::exception_ptr)> " << exParam << " = nullptr,";
7060     H << nl << "::std::function<void(bool)> " << sentParam << " = nullptr,";
7061     H << nl << contextDecl << ")" << string(lambdaCustomOut ? ";" : "");
7062 
7063     H.restoreIndent();
7064     if(lambdaCustomOut)
7065     {
7066         //
7067         // "Custom" implementation in .cpp file
7068         //
7069 
7070         C << sp;
7071         C << nl << "::std::function<void()>";
7072         C << nl << scoped << name << "Async(";
7073         C.useCurrentPosAsIndent();
7074         if(!inParamsImplDecl.empty())
7075         {
7076             for(vector<string>::const_iterator q = inParamsImplDecl.begin(); q != inParamsImplDecl.end(); ++q)
7077             {
7078                 if(q != inParamsImplDecl.begin())
7079                 {
7080                     C << " ";
7081                 }
7082                 C << *q << ",";
7083             }
7084             C << nl;
7085         }
7086         C << "::std::function<void " << spar << lambdaOutParams << epar << "> response,";
7087         C << nl << "::std::function<void(::std::exception_ptr)> ex,";
7088         C << nl << "::std::function<void(bool)> sent,";
7089         C << nl << "const ::Ice::Context& context)";
7090         C.restoreIndent();
7091         C << sb;
7092         if(p->returnsData())
7093         {
7094             C << nl << "_checkTwowayOnly(" << flatName << ");";
7095         }
7096 
7097         C << nl << "::std::function<void(::Ice::InputStream*)> read;";
7098         C << nl << "if(response)";
7099         C << sb;
7100         C << nl << "read = [response](::Ice::InputStream* istr)";
7101         C << sb;
7102         C << nl << "istr->startEncapsulation();";
7103         writeAllocateCode(C, outParams, p, true, clScope, _useWstring | TypeContextInParam | TypeContextCpp11);
7104         writeUnmarshalCode(C, outParams, p, true, _useWstring | TypeContextInParam | TypeContextCpp11);
7105 
7106         if(p->returnsClasses(false))
7107         {
7108             C << nl << "istr->readPendingValues();";
7109         }
7110         C << nl << "istr->endEncapsulation();";
7111         C << nl << "try" << sb;
7112         C << nl << "response" << spar;
7113         if(ret)
7114         {
7115             C << "ret";
7116         }
7117         for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q)
7118         {
7119             C << fixKwd(paramPrefix + (*q)->name());
7120         }
7121         C << epar << ";";
7122         C << eb;
7123         C << nl << "catch(...)";
7124         C << sb;
7125         C << nl << "throw ::std::current_exception();";
7126         C << eb;
7127         C << eb << ";";
7128         C << eb;
7129         C << nl << "auto outAsync = ::std::make_shared<::IceInternal::CustomLambdaOutgoing>(";
7130         C << "shared_from_this(), read, ex, sent);";
7131         C << sp;
7132 
7133         C << nl << "outAsync->invoke(" << flatName << ", ";
7134         C << operationModeToString(p->sendMode(), true) << ", " << opFormatTypeToString(p, true) << ", context,";
7135         C.inc();
7136         C << nl;
7137 
7138         writeInParamsLambda(C, p, inParams, clScope);
7139         C << "," << nl;
7140         throwUserExceptionLambda(C, p->throws(), clScope);
7141 
7142         C.dec();
7143         C << ");";
7144         C << nl << "return [outAsync]() { outAsync->cancel(); };";
7145         C << eb;
7146     }
7147     else
7148     {
7149         //
7150         // Simple implementation directly in header file
7151         //
7152 
7153         H << sb;
7154         if(futureOutParams.size() > 1)
7155         {
7156             H << nl << "auto _responseCb = [response](" << futureT << "&& _result)";
7157             H << sb;
7158             H << nl << responseParam << spar;
7159 
7160             if(ret)
7161             {
7162                 H << condMove(isMovable(ret), string("_result.") + returnValueS);
7163             }
7164             for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q)
7165             {
7166                 H << condMove(isMovable((*q)->type()), "_result." + fixKwd((*q)->name()));
7167             }
7168             H << epar << ";" << eb << ";";
7169         }
7170 
7171         H << nl << "return _makeLamdaOutgoing<" << futureT << ">" << spar;
7172 
7173         H << (futureOutParams.size() > 1 ? "_responseCb" : responseParam) << exParam << sentParam << "this";
7174         H << string("&" + getUnqualified(scoped, clScope.substr(2)) + "_iceI_" + name);
7175         for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q)
7176         {
7177             H << fixKwd((*q)->name());
7178         }
7179         H << contextParam << epar << ";";
7180         H << eb;
7181     }
7182 
7183     //
7184     // Private implementation
7185     //
7186 
7187     H << sp;
7188     H << nl << "/// \\cond INTERNAL";
7189     H << nl << _dllMemberExport << "void _iceI_" << name << spar;
7190     H << "const ::std::shared_ptr<::IceInternal::OutgoingAsyncT<" + futureT + ">>&";
7191     H << inParamsS;
7192     H << ("const " + getUnqualified("::Ice::Context&", clScope));
7193     H << epar << ";";
7194     H << nl << "/// \\endcond";
7195 
7196     C << sp;
7197     C << nl << "/// \\cond INTERNAL";
7198     C << nl << "void" << nl << scoped << "_iceI_" << name << spar;
7199     C << "const ::std::shared_ptr<::IceInternal::OutgoingAsyncT<" + futureT + ">>& outAsync";
7200     C << inParamsImplDecl << ("const " + getUnqualified("::Ice::Context&", clScope) + " context");
7201     C << epar;
7202     C << sb;
7203     if(p->returnsData())
7204     {
7205         C << nl << "_checkTwowayOnly(" << flatName << ");";
7206     }
7207     C << nl << "outAsync->invoke(" << flatName << ", ";
7208     C << getUnqualified(operationModeToString(p->sendMode(), true), clScope) << ", "
7209       << getUnqualified(opFormatTypeToString(p, true), clScope) << ", context,";
7210     C.inc();
7211     C << nl;
7212 
7213     writeInParamsLambda(C, p, inParams, clScope);
7214     C << "," << nl;
7215     throwUserExceptionLambda(C, p->throws(), clScope);
7216 
7217     if(futureOutParams.size() > 1)
7218     {
7219         //
7220         // Generate a read method if there are more than one ret/out parameter. If there's
7221         // only one, we rely on the default read method from LambdaOutgoing
7222         // except if the unique ret/out is optional or is an array/range.
7223         //
7224         C << "," << nl << "[](" << getUnqualified("::Ice::InputStream*", clScope) << " istr)";
7225         C << sb;
7226         C << nl << futureT << " v;";
7227         writeUnmarshalCode(C, outParams, p, false, _useWstring | TypeContextCpp11, "", returnValueS, "v");
7228 
7229         if(p->returnsClasses(false))
7230         {
7231             C << nl << "istr->readPendingValues();";
7232         }
7233         C << nl << "return v;";
7234         C << eb;
7235     }
7236     else if(outParamsHasOpt || p->returnsClasses(false))
7237     {
7238         //
7239         // If there's only one optional ret/out parameter, we still need to generate
7240         // a read method, we can't rely on the default read method which wouldn't
7241         // known which tag to use.
7242         //
7243         C << "," << nl << "[](" << getUnqualified("::Ice::InputStream*", clScope) << " istr)";
7244         C << sb;
7245 
7246         writeAllocateCode(C, outParams, p, true, clScope, _useWstring | TypeContextCpp11);
7247         writeUnmarshalCode(C, outParams, p, true, _useWstring | TypeContextCpp11);
7248 
7249         if(p->returnsClasses(false))
7250         {
7251             C << nl << "istr->readPendingValues();";
7252         }
7253 
7254         if(ret)
7255         {
7256             C << nl << "return ret;";
7257         }
7258         else
7259         {
7260             C << nl << "return " << fixKwd(paramPrefix + outParams.front()->name()) << ";";
7261         }
7262         C << eb;
7263     }
7264 
7265     C.dec();
7266     C << ");" << eb;
7267     C << nl << "/// \\endcond";
7268 }
7269 
7270 void
visitEnum(const EnumPtr & p)7271 Slice::Gen::Cpp11TypesVisitor::visitEnum(const EnumPtr& p)
7272 {
7273     bool unscoped = findMetaData(p->getMetaData(), TypeContextCpp11) == "%unscoped";
7274     H << sp;
7275     writeDocSummary(H, p);
7276     H << nl << "enum ";
7277     if(!unscoped)
7278     {
7279         H << "class ";
7280     }
7281     H << fixKwd(p->name());
7282     if(!unscoped && p->maxValue() <= 0xFF)
7283     {
7284         H << " : unsigned char";
7285     }
7286     H << sb;
7287 
7288     EnumeratorList enumerators = p->enumerators();
7289     //
7290     // Check if any of the enumerators were assigned an explicit value.
7291     //
7292     const bool explicitValue = p->explicitValue();
7293     for(EnumeratorList::const_iterator en = enumerators.begin(); en != enumerators.end();)
7294     {
7295         writeDocSummary(H, *en);
7296         H << nl << fixKwd((*en)->name());
7297         //
7298         // If any of the enumerators were assigned an explicit value, we emit
7299         // an explicit value for *all* enumerators.
7300         //
7301         if(explicitValue)
7302         {
7303             H << " = " << int64ToString((*en)->value());
7304         }
7305         if(++en != enumerators.end())
7306         {
7307             H << ',';
7308         }
7309     }
7310     H << eb << ';';
7311 }
7312 
7313 void
visitConst(const ConstPtr & p)7314 Slice::Gen::Cpp11TypesVisitor::visitConst(const ConstPtr& p)
7315 {
7316     const string scope = fixKwd(p->scope());
7317     H << sp;
7318     writeDocSummary(H, p);
7319     H << nl << (isConstexprType(p->type()) ? "constexpr " : "const ")
7320       << typeToString(p->type(), scope, p->typeMetaData(), _useWstring | TypeContextCpp11) << " " << fixKwd(p->name())
7321       << " = ";
7322     writeConstantValue(H, p->type(), p->valueType(), p->value(), _useWstring | TypeContextCpp11, p->typeMetaData(),
7323                        scope);
7324     H << ';';
7325 }
7326 
7327 void
emitUpcall(const ExceptionPtr & base,const string & call,const string & scope,bool isLocal)7328 Slice::Gen::Cpp11TypesVisitor::emitUpcall(const ExceptionPtr& base, const string& call, const string& scope,
7329                                           bool isLocal)
7330 {
7331     C << nl;
7332     if(base)
7333     {
7334         C << getUnqualified(fixKwd(base->scoped()), scope);
7335     }
7336     else
7337     {
7338         getUnqualified(isLocal ? "::Ice::LocalException" : "::Ice::UserException", scope);
7339     }
7340     C << call;
7341 }
7342 
Cpp11ObjectVisitor(::IceUtilInternal::Output & h,::IceUtilInternal::Output & c,const std::string & dllExport)7343 Slice::Gen::Cpp11ObjectVisitor::Cpp11ObjectVisitor(::IceUtilInternal::Output& h,
7344                                                    ::IceUtilInternal::Output& c,
7345                                                    const std::string& dllExport) :
7346     H(h),
7347     C(c),
7348     _dllExport(dllExport),
7349     _dllClassExport(toDllClassExport(dllExport)), _dllMemberExport(toDllMemberExport(dllExport)),
7350     _doneStaticSymbol(false),
7351     _useWstring(false)
7352 {
7353 }
7354 
7355 void
emitDataMember(const DataMemberPtr & p)7356 Slice::Gen::Cpp11ObjectVisitor::emitDataMember(const DataMemberPtr& p)
7357 {
7358     string name = fixKwd(p->name());
7359     int typeContext = _useWstring | TypeContextCpp11;
7360     ContainerPtr container = p->container();
7361     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
7362     string scope = fixKwd(cl->scope());
7363     if(cl->isLocal())
7364     {
7365         typeContext |= TypeContextLocal;
7366     }
7367 
7368     writeDocSummary(H, p);
7369     H << nl << typeToString(p->type(), p->optional(), scope, p->getMetaData(), typeContext) << ' ' << name;
7370 
7371     string defaultValue = p->defaultValue();
7372     if(!defaultValue.empty())
7373     {
7374         BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type());
7375         if(p->optional() && builtin && builtin->kind() == Builtin::KindString)
7376         {
7377             //
7378             // = "<string literal>" doesn't work for optional<std::string>
7379             //
7380             H << '{';
7381             writeConstantValue(H, p->type(), p->defaultValueType(), defaultValue, _useWstring | TypeContextCpp11,
7382                                p->getMetaData(), scope);
7383             H << '}';
7384         }
7385         else
7386         {
7387             H << " = ";
7388             writeConstantValue(H, p->type(), p->defaultValueType(), defaultValue, _useWstring | TypeContextCpp11,
7389                                p->getMetaData(), scope);
7390         }
7391     }
7392     H << ";";
7393 }
7394 
7395 void
emitUpcall(const ClassDefPtr & base,const string & call,const string & scope)7396 Slice::Gen::Cpp11InterfaceVisitor::emitUpcall(const ClassDefPtr& base, const string& call, const string& scope)
7397 {
7398     C << nl;
7399     if(base)
7400     {
7401         C << getUnqualified(fixKwd(base->scoped()), scope);
7402     }
7403     else
7404     {
7405         C << getUnqualified("::Ice::Object", scope);
7406     }
7407     C << call;
7408 }
7409 
7410 void
emitUpcall(const ClassDefPtr & base,const string & call,const string & scope)7411 Slice::Gen::Cpp11ValueVisitor::emitUpcall(const ClassDefPtr& base, const string& call, const string& scope)
7412 {
7413     C << nl;
7414     if(base)
7415     {
7416         C << getUnqualified(fixKwd(base->scoped()), scope);
7417     }
7418     else
7419     {
7420         C << getUnqualified("::Ice::Value", scope);
7421     }
7422     C << call;
7423 }
7424 
Cpp11LocalObjectVisitor(::IceUtilInternal::Output & h,::IceUtilInternal::Output & c,const std::string & dllExport)7425 Slice::Gen::Cpp11LocalObjectVisitor::Cpp11LocalObjectVisitor(::IceUtilInternal::Output& h,
7426                                                              ::IceUtilInternal::Output& c,
7427                                                              const std::string& dllExport) :
7428     Cpp11ObjectVisitor(h, c, dllExport)
7429 {
7430 }
7431 
7432 bool
visitModuleStart(const ModulePtr & p)7433 Slice::Gen::Cpp11LocalObjectVisitor::visitModuleStart(const ModulePtr& p)
7434 {
7435     if(!p->hasLocalClassDefs())
7436     {
7437         return false;
7438     }
7439 
7440     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
7441     string name = fixKwd(p->name());
7442     H << sp << nl << "namespace " << name << nl << '{';
7443     return true;
7444 }
7445 
7446 void
visitModuleEnd(const ModulePtr &)7447 Slice::Gen::Cpp11LocalObjectVisitor::visitModuleEnd(const ModulePtr&)
7448 {
7449     H << sp;
7450     H << nl << '}';
7451     _useWstring = resetUseWstring(_useWstringHist);
7452 }
7453 
7454 bool
visitClassDefStart(const ClassDefPtr & p)7455 Slice::Gen::Cpp11LocalObjectVisitor::visitClassDefStart(const ClassDefPtr& p)
7456 {
7457     if(!p->isLocal())
7458     {
7459         return false;
7460     }
7461 
7462     string name = fixKwd(p->name());
7463     string scope = fixKwd(p->scope());
7464     if(p->isDelegate())
7465     {
7466         int typeCtx = _useWstring | TypeContextLocal | TypeContextCpp11;
7467 
7468         // A delegate only has one operation
7469         OperationPtr op = p->allOperations().front();
7470 
7471         // Generate alias
7472         H << sp;
7473         CommentPtr comment = op->parseComment(false);
7474         if(comment)
7475         {
7476             writeOpDocSummary(H, op, comment, OpDocAllParams, true, StringList(), StringList(), comment->returns());
7477         }
7478         H << nl << "using " << name << " = ";
7479 
7480         TypePtr ret = op->returnType();
7481         string retS = returnTypeToString(ret, op->returnIsOptional(), scope, op->getMetaData(), typeCtx);
7482 
7483         H << "::std::function<" << retS << "(";
7484 
7485         ParamDeclList paramList = op->parameters();
7486         for(ParamDeclList::iterator q = paramList.begin(); q != paramList.end(); ++q)
7487         {
7488             if((*q)->isOutParam())
7489             {
7490                 H << outputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), typeCtx);
7491             }
7492             else
7493             {
7494                 H << inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), typeCtx);
7495             }
7496             H << " " << fixKwd((*q)->name());
7497             H << (IceUtilInternal::distance(q, paramList.end()) == 1  ? "" : ", ");
7498         }
7499         H << ")>;";
7500 
7501         return false;
7502     }
7503 
7504     string scoped = fixKwd(p->scoped());
7505     ClassList bases = p->bases();
7506     ClassDefPtr base;
7507     if(!bases.empty() && !bases.front()->isInterface())
7508     {
7509         base = bases.front();
7510     }
7511     DataMemberList dataMembers = p->dataMembers();
7512     DataMemberList allDataMembers = p->allDataMembers();
7513 
7514     H << sp;
7515     writeDocSummary(H, p);
7516     H << nl << "class " << _dllClassExport << name;
7517     H.useCurrentPosAsIndent();
7518     if(!bases.empty())
7519     {
7520         H << " : ";
7521         ClassList::const_iterator q = bases.begin();
7522         bool virtualInheritance = p->isInterface();
7523         while(q != bases.end())
7524         {
7525             H << "public ";
7526             if(virtualInheritance || (*q)->isInterface())
7527             {
7528                 H << "virtual ";
7529             }
7530 
7531             H << fixKwd((*q)->scoped());
7532             if(++q != bases.end())
7533             {
7534                 H << ',' << nl;
7535             }
7536         }
7537     }
7538 
7539     H.restoreIndent();
7540     H << sb;
7541     H.dec();
7542     H << nl << "public:" << sp;
7543     H.inc();
7544 
7545     //
7546     // Out of line virtual dtor to avoid weak vtable
7547     //
7548     H << nl << _dllMemberExport << "virtual ~" << name  << "();";
7549     C << sp << nl << scoped.substr(2) << "::~" << name << "()";
7550     C << sb;
7551     C << eb;
7552 
7553     if(!p->isInterface())
7554     {
7555         if(p->hasDefaultValues())
7556         {
7557             H << sp << nl << name << "() :";
7558             H.inc();
7559             writeDataMemberInitializers(H, dataMembers, _useWstring | TypeContextCpp11 | TypeContextLocal);
7560             H.dec();
7561             H << sb;
7562             H << eb;
7563         }
7564         else
7565         {
7566             H << sp << nl << name << "() = default;";
7567         }
7568 
7569         H << sp << nl << name << "(const " << name << "&) = default;";
7570         H << nl << name << "(" << name << "&&) = default;";
7571         H << nl << name << "& operator=(const " << name << "&) = default;";
7572         H << nl << name << "& operator=(" << name << "&&) = default;";
7573 
7574         emitOneShotConstructor(p);
7575     }
7576 
7577     if(p->hasMetaData("cpp:comparable"))
7578     {
7579         H << sp;
7580         H << nl << "virtual bool operator==(const " << p->name() << "&) const = 0;";
7581         H << nl << "virtual bool operator<(const " << p->name() << "&) const = 0;";
7582     }
7583     return true;
7584 }
7585 
7586 void
visitClassDefEnd(const ClassDefPtr & p)7587 Slice::Gen::Cpp11LocalObjectVisitor::visitClassDefEnd(const ClassDefPtr& p)
7588 {
7589     string scoped = fixKwd(p->scoped());
7590     string scope = fixKwd(p->scope());
7591     ClassList bases = p->bases();
7592     ClassDefPtr base;
7593     if(!bases.empty() && !bases.front()->isInterface())
7594     {
7595         base = bases.front();
7596     }
7597 
7598     //
7599     // Emit data members. Access visibility may be specified by metadata.
7600     //
7601     bool inProtected = false;
7602     DataMemberList dataMembers = p->dataMembers();
7603     bool prot = p->hasMetaData("protected");
7604     bool needSp = true;
7605     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
7606     {
7607         if(prot || (*q)->hasMetaData("protected"))
7608         {
7609             if(!inProtected)
7610             {
7611                 H.dec();
7612                 H << sp << nl << "protected:" << sp;
7613                 H.inc();
7614                 inProtected = true;
7615                 needSp = false;
7616             }
7617         }
7618         else
7619         {
7620             if(inProtected)
7621             {
7622                 H.dec();
7623                 H << sp << nl << "public:" << sp;
7624                 H.inc();
7625                 inProtected = false;
7626                 needSp = false;
7627             }
7628         }
7629 
7630         if(needSp)
7631         {
7632             H << sp;
7633             needSp = false;
7634         }
7635 
7636         emitDataMember(*q);
7637     }
7638 
7639     H << eb << ';';
7640 }
7641 
7642 bool
visitExceptionStart(const ExceptionPtr &)7643 Slice::Gen::Cpp11LocalObjectVisitor::visitExceptionStart(const ExceptionPtr&)
7644 {
7645     return false;
7646 }
7647 
7648 bool
visitStructStart(const StructPtr &)7649 Slice::Gen::Cpp11LocalObjectVisitor::visitStructStart(const StructPtr&)
7650 {
7651     return false;
7652 }
7653 
7654 void
visitOperation(const OperationPtr & p)7655 Slice::Gen::Cpp11LocalObjectVisitor::visitOperation(const OperationPtr& p)
7656 {
7657     string name = p->name();
7658     string scoped = fixKwd(p->scoped());
7659     string scope = fixKwd(p->scope());
7660 
7661     int typeCtx = _useWstring | TypeContextLocal | TypeContextCpp11;
7662     TypePtr ret = p->returnType();
7663     string retS = returnTypeToString(ret, p->returnIsOptional(), scope, p->getMetaData(), typeCtx);
7664 
7665     string params = "(";
7666 
7667     ContainerPtr container = p->container();
7668     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
7669     string classScope = fixKwd(cl->scope());
7670 
7671     string isConst = ((p->mode() == Operation::Nonmutating) || p->hasMetaData("cpp:const")) ? " const" : "";
7672     string noExcept = p->hasMetaData("cpp:noexcept") ? " noexcept" : "";
7673 
7674     string deprecateSymbol = getDeprecateSymbol(p, cl);
7675 
7676     CommentPtr comment = p->parseComment(false);
7677 
7678     if(cl->hasMetaData("async-oneway") || p->hasMetaData("async-oneway"))
7679     {
7680         vector<string> paramsDeclAMI;
7681         vector<string> outParamsDeclAMI;
7682         vector<string> paramsArgAMI;
7683         ParamDeclList paramList = p->inParameters();
7684         for(ParamDeclList::const_iterator r = paramList.begin(); r != paramList.end(); ++r)
7685         {
7686             string paramName = fixKwd((*r)->name());
7687 
7688             StringList metaData = (*r)->getMetaData();
7689             string typeString = inputTypeToString((*r)->type(), (*r)->optional(), classScope, metaData, typeCtx);
7690             paramsDeclAMI.push_back(typeString + ' ' + paramName);
7691             paramsArgAMI.push_back(paramName);
7692         }
7693 
7694         H << sp;
7695         if(comment)
7696         {
7697             writeOpDocSummary(H, p, comment, OpDocAllParams, true, StringList(), StringList(), comment->returns());
7698         }
7699         H << nl << deprecateSymbol << "virtual " << retS << ' ' << fixKwd(name) << spar << paramsDeclAMI << epar
7700                 << isConst << noExcept;
7701         H << sb;
7702         H << nl << name << "Async" << spar << paramsArgAMI << epar << ".get();";
7703         H << eb;
7704 
7705         H << sp;
7706         if(comment)
7707         {
7708             string exParam = escapeParam(paramList, "exception");
7709             string sentParam = escapeParam(paramList, "sent");
7710             StringList postParams, returns;
7711             postParams.push_back("@param " + exParam + " The exception callback.");
7712             postParams.push_back("@param " + sentParam + " The sent callback.");
7713             returns.push_back("A function that can be called to cancel the invocation locally.");
7714             writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), postParams, returns);
7715         }
7716         H << nl << "virtual ::std::function<void()>";
7717         H << nl << name << "Async(";
7718         H.useCurrentPosAsIndent();
7719         for(vector<string>::const_iterator i = paramsDeclAMI.begin(); i != paramsDeclAMI.end(); ++i)
7720         {
7721             if(i != paramsDeclAMI.begin())
7722             {
7723                 H << nl;
7724             }
7725             H << *i << ",";
7726         }
7727         if(!paramsDeclAMI.empty())
7728         {
7729             H << nl;
7730         }
7731         H << "::std::function<void(::std::exception_ptr)> exception,";
7732         H << nl << "::std::function<void(bool)> sent = nullptr) = 0;";
7733         H.restoreIndent();
7734 
7735         H << sp;
7736         if(comment)
7737         {
7738             StringList returns;
7739             returns.push_back("The future object for the invocation.");
7740             writeOpDocSummary(H, p, comment, OpDocInParams, false, StringList(), StringList(), returns);
7741         }
7742         H << nl << "template<template<typename> class P = ::std::promise>";
7743         H << nl << deprecateSymbol << "auto " << name << "Async" << spar << paramsDeclAMI << epar;
7744         H.inc();
7745         H << nl << "-> decltype(::std::declval<P<void>>().get_future())";
7746         H.dec();
7747         H << sb;
7748         H << nl << "using Promise = P<void>;";
7749         H << nl << "auto promise = ::std::make_shared<Promise>();";
7750 
7751         H << nl << name << "Async(";
7752         H.useCurrentPosAsIndent();
7753         for(vector<string>::const_iterator i = paramsArgAMI.begin(); i != paramsArgAMI.end(); ++i)
7754         {
7755             if(i != paramsArgAMI.begin())
7756             {
7757                 H << " ";
7758             }
7759             H << *i << ",";
7760         }
7761         if(!paramsArgAMI.empty())
7762         {
7763             H << nl;
7764         }
7765         H << "[promise](::std::exception_ptr ex)";
7766         H << sb;
7767         H << nl << "promise->set_exception(::std::move(ex));";
7768         H << eb << ",";
7769         H << nl << "[promise](bool)";
7770         H << sb;
7771         H << nl << "promise->set_value();";
7772         H << eb << ");";
7773         H.restoreIndent();
7774 
7775         H << nl << "return promise->get_future();";
7776         H << eb;
7777     }
7778     else
7779     {
7780         ParamDeclList paramList = p->parameters();
7781         for(ParamDeclList::iterator q = paramList.begin(); q != paramList.end(); ++q)
7782         {
7783             string paramName = fixKwd((*q)->name());
7784             TypePtr type = (*q)->type();
7785             string typeString;
7786             if((*q)->isOutParam())
7787             {
7788                 typeString = outputTypeToString(type, (*q)->optional(), classScope, (*q)->getMetaData(), typeCtx);
7789             }
7790             else
7791             {
7792                 typeString = inputTypeToString(type, (*q)->optional(), classScope, (*q)->getMetaData(), typeCtx);
7793             }
7794 
7795             if(q != paramList.begin())
7796             {
7797                 params += ", ";
7798             }
7799 
7800             params += typeString;
7801             params += ' ';
7802             params += paramName;
7803         }
7804 
7805         params += ')';
7806 
7807         H << sp;
7808         if(comment)
7809         {
7810             writeOpDocSummary(H, p, comment, OpDocAllParams, true, StringList(), StringList(), comment->returns());
7811         }
7812         H << nl << deprecateSymbol << "virtual " << retS << ' ' << fixKwd(name) << params << isConst << noExcept
7813           << " = 0;";
7814     }
7815 }
7816 
Cpp11InterfaceVisitor(::IceUtilInternal::Output & h,::IceUtilInternal::Output & c,const std::string & dllExport)7817 Slice::Gen::Cpp11InterfaceVisitor::Cpp11InterfaceVisitor(::IceUtilInternal::Output& h,
7818                                                          ::IceUtilInternal::Output& c,
7819                                                          const std::string& dllExport) :
7820     Cpp11ObjectVisitor(h, c, dllExport)
7821 {
7822 }
7823 
7824 bool
visitModuleStart(const ModulePtr & p)7825 Slice::Gen::Cpp11InterfaceVisitor::visitModuleStart(const ModulePtr& p)
7826 {
7827     if(!p->hasNonLocalInterfaceDefs())
7828     {
7829         return false;
7830     }
7831 
7832     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
7833     string name = fixKwd(p->name());
7834     H << sp << nl << "namespace " << name << nl << '{';
7835     return true;
7836 }
7837 
7838 void
visitModuleEnd(const ModulePtr &)7839 Slice::Gen::Cpp11InterfaceVisitor::visitModuleEnd(const ModulePtr&)
7840 {
7841     H << sp;
7842     H << nl << '}';
7843 
7844     _useWstring = resetUseWstring(_useWstringHist);
7845 }
7846 
7847 bool
visitClassDefStart(const ClassDefPtr & p)7848 Slice::Gen::Cpp11InterfaceVisitor::visitClassDefStart(const ClassDefPtr& p)
7849 {
7850     if(p->isLocal() || (!p->isInterface() && p->allOperations().empty()))
7851     {
7852         return false;
7853     }
7854 
7855     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
7856 
7857     string suffix = p->isInterface() ? "" : "Disp";
7858 
7859     string name = fixKwd(p->name() + suffix);
7860     string scope = fixKwd(p->scope());
7861     string scoped = fixKwd(p->scope() + p->name() + suffix);
7862     ClassList bases = p->bases();
7863     ClassDefPtr base;
7864     if(!bases.empty() && !bases.front()->isInterface())
7865     {
7866         base = bases.front();
7867     }
7868 
7869     H << sp;
7870     writeDocSummary(H, p);
7871     H << nl << "class " << _dllExport << name << " : ";
7872     H.useCurrentPosAsIndent();
7873     if(bases.empty() || (base && base->allOperations().empty()))
7874     {
7875         H << "public virtual " << getUnqualified("::Ice::Object", scope);
7876     }
7877     else
7878     {
7879         ClassList::const_iterator q = bases.begin();
7880         while(q != bases.end())
7881         {
7882             string baseSuffix = (*q)->isInterface() ? "" : "Disp";
7883             string baseScoped = fixKwd((*q)->scope() + (*q)->name() + baseSuffix);
7884 
7885             H << "public virtual " << getUnqualified(baseScoped, scope);
7886             if(++q != bases.end())
7887             {
7888                 H << ',' << nl;
7889             }
7890         }
7891     }
7892 
7893     H.restoreIndent();
7894     H << sb;
7895     H.dec();
7896     H << nl << "public:" << sp;
7897     H.inc();
7898 
7899     //
7900     // In C++, a nested type cannot have the same name as the enclosing type
7901     //
7902     if(name != "ProxyType")
7903     {
7904         H << nl << "using ProxyType = " << p->name() << "Prx;";
7905     }
7906 
7907     vector<string> params;
7908     vector<string> allTypes;
7909     vector<string> allParamDecls;
7910 
7911     ClassList allBases = p->allBases();
7912     StringList ids;
7913     transform(allBases.begin(), allBases.end(), back_inserter(ids), ::IceUtil::constMemFun(&Contained::scoped));
7914     StringList other;
7915     other.push_back(p->scoped());
7916     other.push_back("::Ice::Object");
7917     other.sort();
7918     ids.merge(other);
7919     ids.unique();
7920     StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), p->scoped());
7921     assert(scopedIter != ids.end());
7922 
7923     H << sp;
7924     H << nl << "/**";
7925     H << nl << " * Determines whether this object supports an interface with the given Slice type ID.";
7926     H << nl << " * @param id The fully-scoped Slice type ID.";
7927     H << nl << " * @param current The Current object for the invocation.";
7928     H << nl << " * @return True if this object supports the interface, false, otherwise.";
7929     H << nl << " */";
7930     H << nl << "virtual bool ice_isA(::std::string id, const " << getUnqualified("::Ice::Current&", scope)
7931       << " current) const override;";
7932         H << sp;
7933     H << nl << "/**";
7934     H << nl << " * Obtains a list of the Slice type IDs representing the interfaces supported by this object.";
7935     H << nl << " * @param current The Current object for the invocation.";
7936     H << nl << " * @return A list of fully-scoped type IDs.";
7937     H << nl << " */";
7938     H << nl
7939       << "virtual ::std::vector<::std::string> ice_ids(const " << getUnqualified("::Ice::Current&", scope)
7940       << " current) const override;";
7941         H << sp;
7942     H << nl << "/**";
7943     H << nl << " * Obtains a Slice type ID representing the most-derived interface supported by this object.";
7944     H << nl << " * @param current The Current object for the invocation.";
7945     H << nl << " * @return A fully-scoped type ID.";
7946     H << nl << " */";
7947     H << nl << "virtual ::std::string ice_id(const " << getUnqualified("::Ice::Current&", scope)
7948       << " current) const override;";
7949         H << sp;
7950     H << nl << "/**";
7951     H << nl << " * Obtains the Slice type ID corresponding to this class.";
7952     H << nl << " * @return A fully-scoped type ID.";
7953     H << nl << " */";
7954     H << nl << "static const ::std::string& ice_staticId();";
7955 
7956     string flatName = "iceC" + p->flattenedScope() + p->name() + "_ids";
7957 
7958     C << sp;
7959     C << nl << "bool" << nl << scoped.substr(2) << "::ice_isA(::std::string s, const "
7960       << getUnqualified("::Ice::Current&", scope) << ") const";
7961     C << sb;
7962     C << nl << "return ::std::binary_search(" << flatName << ", " << flatName << " + " << ids.size() << ", s);";
7963     C << eb;
7964 
7965     C << sp;
7966     C << nl << "::std::vector<::std::string>" << nl << scoped.substr(2) << "::ice_ids(const "
7967       << getUnqualified("::Ice::Current&", scope) << ") const";
7968     C << sb;
7969     C << nl << "return ::std::vector<::std::string>(&" << flatName << "[0], &" << flatName << '[' << ids.size()
7970       << "]);";
7971     C << eb;
7972 
7973     C << sp;
7974     C << nl << "::std::string" << nl << scoped.substr(2) << "::ice_id(const " << getUnqualified("::Ice::Current&", scope)
7975       << ") const";
7976     C << sb;
7977     C << nl << "return ice_staticId();";
7978     C << eb;
7979 
7980     C << sp;
7981     C << nl << "const ::std::string&" << nl << scoped.substr(2) << "::ice_staticId()";
7982     C << sb;
7983     //
7984     // Use local static so that ice_staticId() is usable during static construction.
7985     //
7986     C << nl << "static const ::std::string typeId = \"" << *scopedIter << "\";";
7987     C << nl << "return typeId;";
7988     C << eb;
7989     return true;
7990 }
7991 
7992 void
visitClassDefEnd(const ClassDefPtr & p)7993 Slice::Gen::Cpp11InterfaceVisitor::visitClassDefEnd(const ClassDefPtr& p)
7994 {
7995     string suffix = p->isInterface() ? "" : "Disp";
7996     string scoped = fixKwd(p->scope() + p->name() + suffix);
7997 
7998     string scope = fixKwd(p->scope());
7999     string name = fixKwd(p->name() + suffix);
8000     ClassList bases = p->bases();
8001     ClassDefPtr base;
8002     if(!bases.empty() && !bases.front()->isInterface())
8003     {
8004         base = bases.front();
8005     }
8006 
8007     OperationList allOps = p->allOperations();
8008     if(!allOps.empty())
8009     {
8010         StringList allOpNames;
8011         transform(allOps.begin(), allOps.end(), back_inserter(allOpNames), ::IceUtil::constMemFun(&Contained::name));
8012         allOpNames.push_back("ice_id");
8013         allOpNames.push_back("ice_ids");
8014         allOpNames.push_back("ice_isA");
8015         allOpNames.push_back("ice_ping");
8016         allOpNames.sort();
8017         allOpNames.unique();
8018 
8019         string flatName = "iceC" + p->flattenedScope() + p->name() + "_ops";
8020 
8021         H << sp;
8022         H << nl << "/// \\cond INTERNAL";
8023         H << nl << "virtual bool _iceDispatch(::IceInternal::Incoming&, const "
8024           << getUnqualified("::Ice::Current&", scope) << ") override;";
8025         H << nl << "/// \\endcond";
8026 
8027         C << sp;
8028         C << nl << "/// \\cond INTERNAL";
8029         C << nl << "bool";
8030         C << nl << scoped.substr(2) << "::_iceDispatch(::IceInternal::Incoming& in, const "
8031           << getUnqualified("::Ice::Current&", scope) << " current)";
8032         C << sb;
8033 
8034         C << nl << "::std::pair<const ::std::string*, const ::std::string*> r = "
8035           << "::std::equal_range(" << flatName << ", " << flatName << " + " << allOpNames.size()
8036           << ", current.operation);";
8037         C << nl << "if(r.first == r.second)";
8038         C << sb;
8039         C << nl << "throw " << getUnqualified("::Ice::OperationNotExistException", scope)
8040           << "(__FILE__, __LINE__, current.id, current.facet, current.operation);";
8041         C << eb;
8042         C << sp;
8043         C << nl << "switch(r.first - " << flatName << ')';
8044         C << sb;
8045         int i = 0;
8046         for(StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end(); ++q)
8047         {
8048             C << nl << "case " << i++ << ':';
8049             C << sb;
8050             C << nl << "return _iceD_" << *q << "(in, current);";
8051             C << eb;
8052         }
8053         C << nl << "default:";
8054         C << sb;
8055         C << nl << "assert(false);";
8056         C << nl << "throw " << getUnqualified("::Ice::OperationNotExistException", scope)
8057           << "(__FILE__, __LINE__, current.id, current.facet, current.operation);";
8058         C << eb;
8059         C << eb;
8060         C << eb;
8061         C << nl << "/// \\endcond";
8062     }
8063 
8064     H << eb << ';';
8065 
8066     _useWstring = resetUseWstring(_useWstringHist);
8067 }
8068 
8069 bool
visitExceptionStart(const ExceptionPtr &)8070 Slice::Gen::Cpp11InterfaceVisitor::visitExceptionStart(const ExceptionPtr&)
8071 {
8072     return false;
8073 }
8074 
8075 bool
visitStructStart(const StructPtr &)8076 Slice::Gen::Cpp11InterfaceVisitor::visitStructStart(const StructPtr&)
8077 {
8078     return false;
8079 }
8080 
8081 void
visitOperation(const OperationPtr & p)8082 Slice::Gen::Cpp11InterfaceVisitor::visitOperation(const OperationPtr& p)
8083 {
8084     string name = p->name();
8085 
8086     TypePtr ret = p->returnType();
8087 
8088     vector<string> params;
8089     vector<string> args;
8090 
8091     vector<string> responseParams;
8092     vector<string> responseParamsDecl;
8093     vector<string> responseParamsImplDecl;
8094 
8095     ContainerPtr container = p->container();
8096     ClassDefPtr cl = ClassDefPtr::dynamicCast(container);
8097     string classScope = fixKwd(cl->scope());
8098 
8099     string suffix = cl->isInterface() ? "" : "Disp";
8100     string scope = fixKwd(cl->scope() + cl->name() + suffix + "::");
8101     string scoped = fixKwd(cl->scope() + cl->name() + suffix + "::" + p->name());
8102 
8103     ParamDeclList inParams = p->inParameters();
8104     ParamDeclList outParams = p->outParameters();
8105     ParamDeclList paramList = p->parameters();
8106 
8107     const bool amd = (cl->hasMetaData("amd") || p->hasMetaData("amd"));
8108 
8109     const string returnValueParam = escapeParam(outParams, "returnValue");
8110     const string responsecbParam = escapeParam(inParams, "response");
8111     const string excbParam = escapeParam(inParams, "exception");
8112     const string currentParam = escapeParam(amd ? inParams : paramList, "current");
8113     const string currentTypeDecl = "const " + getUnqualified("::Ice::Current&", classScope);
8114     const string currentDecl = currentTypeDecl + " " + currentParam;
8115 
8116     CommentPtr comment = p->parseComment(false);
8117 
8118     if(ret)
8119     {
8120         string typeS = inputTypeToString(ret, p->returnIsOptional(), classScope, p->getMetaData(),
8121                                          _useWstring | TypeContextCpp11);
8122         responseParams.push_back(typeS + " " + returnValueParam);
8123         responseParamsDecl.push_back(typeS + " ret");
8124         responseParamsImplDecl.push_back(typeS + " ret");
8125     }
8126 
8127     string retS;
8128     if(amd)
8129     {
8130         retS = "void";
8131     }
8132     else if(p->hasMarshaledResult())
8133     {
8134         retS = resultStructName(name, "", true);
8135     }
8136     else
8137     {
8138         retS = returnTypeToString(ret, p->returnIsOptional(), classScope, p->getMetaData(),
8139                                   _useWstring | TypeContextCpp11);
8140     }
8141 
8142     for(ParamDeclList::iterator q = paramList.begin(); q != paramList.end(); ++q)
8143     {
8144         TypePtr type = (*q)->type();
8145         string paramName = fixKwd((*q)->name());
8146         bool isOutParam = (*q)->isOutParam();
8147         string typeString;
8148         int typeCtx = _useWstring | TypeContextCpp11;
8149 
8150         if(!isOutParam)
8151         {
8152             params.push_back(typeToString(type, (*q)->optional(), classScope, (*q)->getMetaData(),
8153                                           typeCtx | TypeContextInParam) + " " + paramName);
8154             args.push_back(condMove(isMovable(type) && !isOutParam, paramPrefix + (*q)->name()));
8155         }
8156         else
8157         {
8158             if(!p->hasMarshaledResult() && !amd)
8159             {
8160                 params.push_back(
8161                     outputTypeToString(type, (*q)->optional(), classScope, (*q)->getMetaData(), typeCtx) + " " +
8162                     paramName);
8163                 args.push_back(condMove(isMovable(type) && !isOutParam, paramPrefix + (*q)->name()));
8164             }
8165 
8166             string responseTypeS = inputTypeToString((*q)->type(), (*q)->optional(), classScope, (*q)->getMetaData(),
8167                                                      typeCtx);
8168             responseParams.push_back(responseTypeS + " " + paramName);
8169             responseParamsDecl.push_back(responseTypeS + " " + paramPrefix + (*q)->name());
8170             responseParamsImplDecl.push_back(responseTypeS + " " + paramPrefix + (*q)->name());
8171         }
8172     }
8173     if(amd)
8174     {
8175         if(p->hasMarshaledResult())
8176         {
8177             string resultName = resultStructName(name, "", true);
8178             params.push_back("::std::function<void(const " + resultName + "&)> " + responsecbParam);
8179             args.push_back("inA->response<" + resultName + ">()");
8180         }
8181         else
8182         {
8183             params.push_back("::std::function<void(" + joinString(responseParams, ", ") + ")> " + responsecbParam);
8184             args.push_back(ret || !outParams.empty() ? "responseCB" : "inA->response()");
8185         }
8186         params.push_back("::std::function<void(::std::exception_ptr)> " + excbParam);
8187         args.push_back("inA->exception()");
8188     }
8189     params.push_back(currentDecl);
8190     args.push_back("current");
8191 
8192     if(cl->isInterface())
8193     {
8194         emitOpNameResult(H, p, _useWstring);
8195     }
8196 
8197     if(p->hasMarshaledResult())
8198     {
8199         string resultName = resultStructName(name, "", true);
8200         H << sp;
8201         H << nl << "/**";
8202         H << nl << " * Marshaled result structure for operation " << (amd ? name + "Async" : fixKwd(name)) << ".";
8203         H << nl << " */";
8204         H << nl << "class " << resultName << " : public " << getUnqualified("::Ice::MarshaledResult", classScope);
8205         H << sb;
8206         H.dec();
8207         H << nl << "public:";
8208         H.inc();
8209         H << nl << "/**";
8210         H << nl << " * Marshals the results immediately.";
8211         if(ret && comment && !comment->returns().empty())
8212         {
8213             H << nl << " * @param " << returnValueParam << " " << getDocSentence(comment->returns());
8214         }
8215         map<string, StringList> paramComments;
8216         if(comment)
8217         {
8218             paramComments = comment->parameters();
8219         }
8220         const string mrcurrent = escapeParam(outParams, "current");
8221         for(ParamDeclList::iterator q = outParams.begin(); q != outParams.end(); ++q)
8222         {
8223             map<string, StringList>::iterator r = paramComments.find((*q)->name());
8224             if(r != paramComments.end())
8225             {
8226                 H << nl << " * @param " << fixKwd(r->first) << " " << getDocSentence(r->second);
8227             }
8228         }
8229         H << nl << " * @param " << mrcurrent << " The Current object for the invocation.";
8230         H << nl << " */";
8231         H << nl << resultName << spar << responseParams << currentTypeDecl + " " + mrcurrent << epar << ";";
8232         H << eb << ';';
8233 
8234         C << sp << nl << scope.substr(2) << resultName << "::" << resultName;
8235         C << spar << responseParamsImplDecl << currentTypeDecl + " current" << epar << ":";
8236         C.inc();
8237         C << nl << "MarshaledResult(current)";
8238         C.dec();
8239         C << sb;
8240         C << nl << "ostr->startEncapsulation(current.encoding, " << opFormatTypeToString(p, true) << ");";
8241         writeMarshalCode(C, outParams, p, true, TypeContextCpp11, "ostr");
8242         if(p->returnsClasses(false))
8243         {
8244             C << nl << "ostr->writePendingValues();";
8245         }
8246         C << nl << "ostr->endEncapsulation();";
8247         C << eb;
8248     }
8249 
8250     string isConst = ((p->mode() == Operation::Nonmutating) || p->hasMetaData("cpp:const")) ? " const" : "";
8251 
8252     string opName = amd ? (name + "Async") : fixKwd(name);
8253     string deprecateSymbol = getDeprecateSymbol(p, cl);
8254 
8255     H << sp;
8256     if(comment)
8257     {
8258         OpDocParamType pt = (amd || p->hasMarshaledResult()) ? OpDocInParams : OpDocAllParams;
8259         StringList postParams, returns;
8260         if(amd)
8261         {
8262             postParams.push_back("@param " + responsecbParam + " The response callback.");
8263             postParams.push_back("@param " + excbParam + " The exception callback.");
8264         }
8265         else if(p->hasMarshaledResult())
8266         {
8267             returns.push_back("The marshaled result structure.");
8268         }
8269         else if(!amd)
8270         {
8271             returns = comment->returns();
8272         }
8273         postParams.push_back("@param " + currentParam + " The Current object for the invocation.");
8274         writeOpDocSummary(H, p, comment, pt, true, StringList(), postParams, returns);
8275     }
8276     H << nl << deprecateSymbol << "virtual " << retS << ' ' << opName << spar << params << epar << isConst << " = 0;";
8277     H << nl << "/// \\cond INTERNAL";
8278     H << nl << "bool _iceD_" << name << "(::IceInternal::Incoming&, const "
8279       << getUnqualified("::Ice::Current&", classScope) << ")" << isConst << ';';
8280     H << nl << "/// \\endcond";
8281 
8282     C << sp;
8283     C << nl << "/// \\cond INTERNAL";
8284     C << nl << "bool";
8285     C << nl << scope.substr(2);
8286     C << "_iceD_" << name << "(::IceInternal::Incoming& inS, const "
8287       << getUnqualified("::Ice::Current&", classScope) << " current)" << isConst;
8288     C << sb;
8289     C << nl << "_iceCheckMode(" << getUnqualified(operationModeToString(p->mode(), true), classScope)
8290       << ", current.mode);";
8291 
8292     if(!inParams.empty())
8293     {
8294         C << nl << "auto istr = inS.startReadParams();";
8295         writeAllocateCode(C, inParams, 0, true, classScope, _useWstring | TypeContextInParam | TypeContextCpp11);
8296         writeUnmarshalCode(C, inParams, 0, true, _useWstring | TypeContextInParam | TypeContextCpp11);
8297         if(p->sendsClasses(false))
8298         {
8299             C << nl << "istr->readPendingValues();";
8300         }
8301         C << nl << "inS.endReadParams();";
8302     }
8303     else
8304     {
8305         C << nl << "inS.readEmptyParams();";
8306     }
8307     if(p->format() != DefaultFormat)
8308     {
8309         C << nl << "inS.setFormat(" << opFormatTypeToString(p, true) << ");";
8310     }
8311 
8312     if(!amd)
8313     {
8314         if(p->hasMarshaledResult())
8315         {
8316             C << nl << "inS.setMarshaledResult(";
8317         }
8318         else
8319         {
8320             writeAllocateCode(C, outParams, 0, true, classScope, _useWstring | TypeContextCpp11);
8321             if(ret)
8322             {
8323                 C << nl << retS << " ret = ";
8324             }
8325             else
8326             {
8327                 C << nl;
8328             }
8329         }
8330 
8331         C << "this->" << opName << spar << args << epar;
8332         if(p->hasMarshaledResult())
8333         {
8334             C << ");";
8335         }
8336         else
8337         {
8338             C << ";";
8339             if(ret || !outParams.empty())
8340             {
8341                 C << nl << "auto ostr = inS.startWriteParams();";
8342                 writeMarshalCode(C, outParams, p, true, TypeContextCpp11);
8343                 if(p->returnsClasses(false))
8344                 {
8345                     C << nl << "ostr->writePendingValues();";
8346                 }
8347                 C << nl << "inS.endWriteParams();";
8348             }
8349             else
8350             {
8351                 C << nl << "inS.writeEmptyParams();";
8352             }
8353         }
8354         C << nl << "return true;";
8355     }
8356     else
8357     {
8358         C << nl << "auto inA = ::IceInternal::IncomingAsync::create(inS);";
8359         if(!p->hasMarshaledResult() && (ret || !outParams.empty()))
8360         {
8361             C << nl << "auto responseCB = [inA]" << spar << responseParamsDecl << epar;
8362             C << sb;
8363             C << nl << "auto ostr = inA->startWriteParams();";
8364             writeMarshalCode(C, outParams, p, true, TypeContextCpp11);
8365             if(p->returnsClasses(false))
8366             {
8367                 C << nl << "ostr->writePendingValues();";
8368             }
8369             C << nl << "inA->endWriteParams();";
8370             C << nl << "inA->completed();";
8371             C << eb << ';';
8372         }
8373         C << nl << "this->" << opName << spar << args << epar << ';';
8374         C << nl << "return false;";
8375     }
8376     C << eb;
8377     C << nl << "/// \\endcond";
8378 }
8379 
Cpp11ValueVisitor(::IceUtilInternal::Output & h,::IceUtilInternal::Output & c,const std::string & dllExport)8380 Slice::Gen::Cpp11ValueVisitor::Cpp11ValueVisitor(::IceUtilInternal::Output& h,
8381                                                  ::IceUtilInternal::Output& c,
8382                                                  const std::string& dllExport) :
8383     Cpp11ObjectVisitor(h, c, dllExport)
8384 {
8385 }
8386 
8387 bool
visitModuleStart(const ModulePtr & p)8388 Slice::Gen::Cpp11ValueVisitor::visitModuleStart(const ModulePtr& p)
8389 {
8390     if(!p->hasValueDefs())
8391     {
8392         return false;
8393     }
8394 
8395     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
8396     string name = fixKwd(p->name());
8397     H << sp << nl << "namespace " << name << nl << '{';
8398     return true;
8399 }
8400 
8401 void
visitModuleEnd(const ModulePtr &)8402 Slice::Gen::Cpp11ValueVisitor::visitModuleEnd(const ModulePtr&)
8403 {
8404     H << sp;
8405     H << nl << '}';
8406 
8407     _useWstring = resetUseWstring(_useWstringHist);
8408 }
8409 
8410 bool
visitClassDefStart(const ClassDefPtr & p)8411 Slice::Gen::Cpp11ValueVisitor::visitClassDefStart(const ClassDefPtr& p)
8412 {
8413     if(p->isLocal() || p->isInterface())
8414     {
8415         return false;
8416     }
8417     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
8418 
8419     string name = fixKwd(p->name());
8420     string scope = fixKwd(p->scope());
8421     string scoped = fixKwd(p->scoped());
8422     ClassList bases = p->bases();
8423     ClassDefPtr base;
8424     if(!bases.empty())
8425     {
8426         base = bases.front();
8427     }
8428     DataMemberList dataMembers = p->dataMembers();
8429     DataMemberList allDataMembers = p->allDataMembers();
8430 
8431     H << sp;
8432     writeDocSummary(H, p);
8433     H << nl << "class " << _dllClassExport << name << " : public " << getUnqualified("::Ice::ValueHelper", scope)
8434       << "<" << name << ", ";
8435 
8436     if(!base || (base && base->isInterface()))
8437     {
8438         H << getUnqualified("::Ice::Value", scope);
8439     }
8440     else
8441     {
8442         H << getUnqualified(fixKwd(base->scoped()), scope);
8443     }
8444     H << ">";
8445     H << sb;
8446     H.dec();
8447     H << nl << "public:" << sp;
8448     H.inc();
8449 
8450     // Out of line dtor to avoid weak vtable
8451     H << nl << _dllMemberExport << "virtual ~" << name << "();";
8452     C << sp;
8453     C << nl << scoped.substr(2) << "::~" << name << "()";
8454     C << sb;
8455     C << eb;
8456 
8457     vector<string> params;
8458 
8459     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
8460     {
8461         params.push_back(fixKwd((*q)->name()));
8462     }
8463 
8464     H << sp << nl << name << "() = default;";
8465 
8466     H << sp << nl << name << "(const " << name << "&) = default;";
8467     H << nl << name << "(" << name << "&&) = default;";
8468     H << nl << name << "& operator=(const " << name << "&) = default;";
8469     H << nl << name << "& operator=(" << name << "&&) = default;";
8470 
8471     emitOneShotConstructor(p);
8472 
8473     H << sp;
8474     H << nl << "/**";
8475     H << nl << " * Obtains a tuple containing all of the value's data members.";
8476     H << nl << " * @return The data members in a tuple.";
8477     H << nl << " */";
8478     writeIceTuple(H, fixKwd(p->scope()), p->allDataMembers(), _useWstring);
8479 
8480     H << sp;
8481     H << nl << "/**";
8482     H << nl << " * Obtains the Slice type ID of this value.";
8483     H << nl << " * @return The fully-scoped type ID.";
8484     H << nl << " */";
8485     H << nl << _dllMemberExport << "static const ::std::string& ice_staticId();";
8486     return true;
8487 }
8488 
8489 void
visitClassDefEnd(const ClassDefPtr & p)8490 Slice::Gen::Cpp11ValueVisitor::visitClassDefEnd(const ClassDefPtr& p)
8491 {
8492     string scoped = fixKwd(p->scoped());
8493     string scope = fixKwd(p->scope());
8494     string name = fixKwd(p->name());
8495     ClassList bases = p->bases();
8496     ClassDefPtr base;
8497     if(!bases.empty() && !bases.front()->isInterface())
8498     {
8499         base = bases.front();
8500     }
8501     bool basePreserved = p->inheritsMetaData("preserve-slice");
8502     bool preserved = p->hasMetaData("preserve-slice");
8503 
8504     if(preserved && !basePreserved)
8505     {
8506         H << sp;
8507         H << nl << "/**";
8508         H << nl << " * Obtains the SlicedData object created when an unknown value type was marshaled";
8509         H << nl << " * in the sliced format and the Ice run time sliced it to a known type.";
8510         H << nl << " * @return The SlicedData object, or nil if the value was not sliced or was not";
8511         H << nl << " * marshaled in the sliced format.";
8512         H << nl << " */";
8513         H << nl << "virtual ::std::shared_ptr<" << getUnqualified("::Ice::SlicedData", scope)
8514           << "> ice_getSlicedData() const override;";
8515 
8516         C << sp;
8517         C << nl << "::std::shared_ptr<::Ice::SlicedData>" << nl << scoped.substr(2) << "::ice_getSlicedData() const";
8518         C << sb;
8519         C << nl << "return _iceSlicedData;";
8520         C << eb;
8521 
8522         H << sp;
8523         H << nl << "/// \\cond STREAM";
8524         H << nl << "virtual void _iceWrite(" << getUnqualified("::Ice::OutputStream*", scope) << ") const override;";
8525         H << nl << "virtual void _iceRead(" << getUnqualified("::Ice::InputStream*", scope) << ") override;";
8526         H << nl << "/// \\endcond";
8527 
8528         C << sp;
8529         C << nl << "/// \\cond STREAM";
8530         C << nl << "void" << nl << scoped.substr(2) << "::_iceWrite(" << getUnqualified("::Ice::OutputStream*", scope)
8531           << " ostr) const";
8532         C << sb;
8533         C << nl << "ostr->startValue(_iceSlicedData);";
8534         C << nl << "_iceWriteImpl(ostr);";
8535         C << nl << "ostr->endValue();";
8536         C << eb;
8537 
8538         C << sp;
8539         C << nl << "void" << nl << scoped.substr(2) << "::_iceRead(" << getUnqualified("::Ice::InputStream*", scope)
8540           << " istr)";
8541         C << sb;
8542         C << nl << "istr->startValue();";
8543         C << nl << "_iceReadImpl(istr);";
8544         C << nl << "_iceSlicedData = istr->endValue(true);";
8545         C << eb;
8546         C << nl << "/// \\endcond";
8547     }
8548 
8549     C << sp;
8550     C << nl << "const ::std::string&" << nl << scoped.substr(2) << "::ice_staticId()";
8551     C << sb;
8552     //
8553     // Use local static so that ice_staticId() is usable during static construction.
8554     //
8555     C << nl << "static const ::std::string typeId = \"" << p->scoped() << "\";";
8556     C << nl << "return typeId;";
8557     C << eb;
8558 
8559     //
8560     // Emit data members. Access visibility may be specified by metadata.
8561     //
8562     bool inProtected = false;
8563     bool generateFriend = false;
8564     DataMemberList dataMembers = p->dataMembers();
8565     bool prot = p->hasMetaData("protected");
8566     bool needSp = true;
8567 
8568     for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
8569     {
8570         if(prot || (*q)->hasMetaData("protected"))
8571         {
8572             if(!inProtected)
8573             {
8574                 H.dec();
8575                 H << sp << nl << "protected:" << sp;
8576                 H.inc();
8577                 inProtected = true;
8578                 needSp = false;
8579             }
8580             generateFriend = true;
8581         }
8582         else
8583         {
8584             if(inProtected)
8585             {
8586                 H.dec();
8587                 H << sp << nl << "public:" << sp;
8588                 H.inc();
8589                 inProtected = false;
8590                 needSp = false;
8591             }
8592         }
8593 
8594         if(needSp)
8595         {
8596             H << sp;
8597             needSp = false;
8598         }
8599 
8600         emitDataMember(*q);
8601     }
8602 
8603     if(preserved && !basePreserved)
8604     {
8605         if(!inProtected)
8606         {
8607             H.dec();
8608             H << sp << nl << "protected:";
8609             H.inc();
8610             inProtected = true;
8611         }
8612         H << sp;
8613         H << nl << "/// \\cond STREAM";
8614         H << nl << "::std::shared_ptr<" << getUnqualified("::Ice::SlicedData", scope) << "> _iceSlicedData;";
8615         H << nl << "/// \\endcond";
8616     }
8617 
8618     if(generateFriend)
8619     {
8620         if(!inProtected)
8621         {
8622             H.dec();
8623             H << sp << nl << "protected:";
8624             H.inc();
8625             inProtected = true;
8626         }
8627 
8628         H << sp;
8629         H << nl << "template<typename T, typename S>";
8630         H << nl << "friend struct Ice::StreamWriter;";
8631         H << nl << "template<typename T, typename S>";
8632         H << nl << "friend struct Ice::StreamReader;";
8633     }
8634 
8635     H << eb << ';';
8636 
8637     if(!_doneStaticSymbol)
8638     {
8639         //
8640         // We need an instance here to trigger initialization if the implementation is in a static library.
8641         // But we do this only once per source file, because a single instance is sufficient to initialize
8642         // all of the globals in a compilation unit.
8643         //
8644         _doneStaticSymbol = true;
8645         H << sp;
8646         H << nl << "/// \\cond INTERNAL";
8647         H << nl << "static " << fixKwd(p->name()) << " _iceS_" << p->name() << "_init;";
8648         H << nl << "/// \\endcond";
8649     }
8650 
8651     _useWstring = resetUseWstring(_useWstringHist);
8652 }
8653 
8654 bool
visitExceptionStart(const ExceptionPtr &)8655 Slice::Gen::Cpp11ValueVisitor::visitExceptionStart(const ExceptionPtr&)
8656 {
8657     return false;
8658 }
8659 
8660 bool
visitStructStart(const StructPtr &)8661 Slice::Gen::Cpp11ValueVisitor::visitStructStart(const StructPtr&)
8662 {
8663     return false;
8664 }
8665 
8666 void
visitOperation(const OperationPtr & p)8667 Slice::Gen::Cpp11ValueVisitor::visitOperation(const OperationPtr& p)
8668 {
8669     emitOpNameResult(H, p, _useWstring);
8670 }
8671 
8672 bool
emitVirtualBaseInitializers(const ClassDefPtr & derived,const ClassDefPtr & base)8673 Slice::Gen::Cpp11ObjectVisitor::emitVirtualBaseInitializers(const ClassDefPtr& derived, const ClassDefPtr& base)
8674 {
8675     const string scope = fixKwd(derived->scope());
8676     DataMemberList allDataMembers = base->allDataMembers();
8677     if(allDataMembers.empty())
8678     {
8679         return false;
8680     }
8681 
8682     string upcall = "(";
8683     for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
8684     {
8685         if(q != allDataMembers.begin())
8686         {
8687             upcall += ", ";
8688         }
8689         if(isMovable((*q)->type()))
8690         {
8691             upcall += "::std::move(" + fixKwd((*q)->name()) + ")";
8692         }
8693         else
8694         {
8695             upcall += "" + fixKwd((*q)->name());
8696         }
8697     }
8698     upcall += ")";
8699 
8700     if(base->isLocal())
8701     {
8702         H << nl << getUnqualified(fixKwd(base->scoped()), scope);
8703     }
8704     else
8705     {
8706         H << nl << "Ice::ValueHelper<" << getUnqualified(fixKwd(derived->scoped()), scope)
8707           << ", " << getUnqualified(fixKwd(base->scoped()), scope) << ">";
8708     }
8709     H << upcall;
8710     return true;
8711 }
8712 
8713 void
emitOneShotConstructor(const ClassDefPtr & p)8714 Slice::Gen::Cpp11ObjectVisitor::emitOneShotConstructor(const ClassDefPtr& p)
8715 {
8716     DataMemberList allDataMembers = p->allDataMembers();
8717     string scope = fixKwd(p->scope());
8718     if(!allDataMembers.empty())
8719     {
8720         vector<string> allParamDecls;
8721         map<string, CommentPtr> allComments;
8722         DataMemberList dataMembers = p->dataMembers();
8723 
8724         int typeContext = _useWstring | TypeContextCpp11;
8725         if(p->isLocal())
8726         {
8727             typeContext |= TypeContextLocal;
8728         }
8729 
8730         for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
8731         {
8732             string typeName =
8733                 inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(), typeContext);
8734             allParamDecls.push_back(typeName + " " + fixKwd((*q)->name()));
8735             CommentPtr comment = (*q)->parseComment(false);
8736             if(comment)
8737             {
8738                 allComments[(*q)->name()] = comment;
8739             }
8740         }
8741 
8742         CommentPtr comment = p->parseComment(false);
8743 
8744         H << sp;
8745         H << nl << "/**";
8746         H << nl << " * One-shot constructor to initialize all data members.";
8747         for(DataMemberList::const_iterator q = allDataMembers.begin(); q != allDataMembers.end(); ++q)
8748         {
8749             map<string, CommentPtr>::iterator r = allComments.find((*q)->name());
8750             if(r != allComments.end())
8751             {
8752                 H << nl << " * @param " << fixKwd(r->first) << " " << getDocSentence(r->second->overview());
8753             }
8754         }
8755         H << nl << " */";
8756         H << nl;
8757         if(allParamDecls.size() == 1)
8758         {
8759             H << "explicit ";
8760         }
8761         H << fixKwd(p->name()) << spar << allParamDecls << epar << " :";
8762         H.inc();
8763 
8764         ClassList bases = p->bases();
8765 
8766         if(!bases.empty() && !bases.front()->isInterface())
8767         {
8768             if(emitVirtualBaseInitializers(p, bases.front()))
8769             {
8770                 if(!dataMembers.empty())
8771                 {
8772                     H << ',';
8773                 }
8774             }
8775         }
8776 
8777         if(!dataMembers.empty())
8778         {
8779             H << nl;
8780         }
8781 
8782         for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q)
8783         {
8784             if(q != dataMembers.begin())
8785             {
8786                 H << ',' << nl;
8787             }
8788             string memberName = fixKwd((*q)->name());
8789             if(isMovable((*q)->type()))
8790             {
8791                 H << memberName << "(::std::move(" << memberName << "))";
8792             }
8793             else
8794             {
8795                 H << memberName << "(" << memberName << ')';
8796             }
8797         }
8798 
8799         H.dec();
8800         H << sb;
8801         H << eb;
8802     }
8803 }
8804 
Cpp11StreamVisitor(Output & h,Output & c,const string & dllExport)8805 Slice::Gen::Cpp11StreamVisitor::Cpp11StreamVisitor(Output& h, Output& c, const string& dllExport) :
8806     H(h),
8807     C(c),
8808     _dllExport(dllExport)
8809 {
8810 }
8811 
8812 bool
visitModuleStart(const ModulePtr & m)8813 Slice::Gen::Cpp11StreamVisitor::visitModuleStart(const ModulePtr& m)
8814 {
8815     if(!m->hasNonLocalContained(Contained::ContainedTypeStruct) &&
8816        !m->hasNonLocalContained(Contained::ContainedTypeEnum) &&
8817        !m->hasNonLocalContained(Contained::ContainedTypeException) &&
8818        !m->hasNonLocalContained(Contained::ContainedTypeClass))
8819     {
8820         return false;
8821     }
8822 
8823     if(UnitPtr::dynamicCast(m->container()))
8824     {
8825         //
8826         // Only emit this for the top-level module.
8827         //
8828         H << sp;
8829         H << nl << "/// \\cond STREAM";
8830         H << nl << "namespace Ice" << nl << '{' << sp;
8831 
8832         if(m->hasNonLocalContained(Contained::ContainedTypeStruct))
8833         {
8834             C << sp;
8835             C << nl << "namespace Ice" << nl << '{';
8836         }
8837     }
8838     return true;
8839 }
8840 
8841 void
visitModuleEnd(const ModulePtr & m)8842 Slice::Gen::Cpp11StreamVisitor::visitModuleEnd(const ModulePtr& m)
8843 {
8844     if(UnitPtr::dynamicCast(m->container()))
8845     {
8846         //
8847         // Only emit this for the top-level module.
8848         //
8849         H << nl << '}';
8850         H << nl << "/// \\endcond";
8851         if(m->hasNonLocalContained(Contained::ContainedTypeStruct))
8852         {
8853             C << nl << '}';
8854         }
8855     }
8856 }
8857 
8858 bool
visitStructStart(const StructPtr & p)8859 Slice::Gen::Cpp11StreamVisitor::visitStructStart(const StructPtr& p)
8860 {
8861     if(p->isLocal())
8862     {
8863         return false;
8864     }
8865 
8866     string scoped = fixKwd(p->scoped());
8867 
8868     H << nl << "template<>";
8869     H << nl << "struct StreamableTraits<" << scoped << ">";
8870     H << sb;
8871     H << nl << "static const StreamHelperCategory helper = StreamHelperCategoryStruct;";
8872     H << nl << "static const int minWireSize = " << p->minWireSize() << ";";
8873     H << nl << "static const bool fixedLength = " << (p->isVariableLength() ? "false" : "true") << ";";
8874     H << eb << ";" << nl;
8875 
8876     writeStreamHelpers(H, p, p->dataMembers(), false, false, true);
8877 
8878     return false;
8879 }
8880 
8881 bool
visitClassDefStart(const ClassDefPtr & c)8882 Slice::Gen::Cpp11StreamVisitor::visitClassDefStart(const ClassDefPtr& c)
8883 {
8884     if(!c->isLocal() && !c->isInterface())
8885     {
8886         writeStreamHelpers(H,c, c->dataMembers(), c->hasBaseDataMembers(), true, true);
8887     }
8888     return false;
8889 }
8890 
8891 void
visitExceptionEnd(const ExceptionPtr & p)8892 Slice::Gen::Cpp11StreamVisitor::visitExceptionEnd(const ExceptionPtr& p)
8893 {
8894     if(!p->isLocal())
8895     {
8896         writeStreamHelpers(H,p, p->dataMembers(), p->hasBaseDataMembers(), true, true);
8897     }
8898 }
8899 
8900 void
visitEnum(const EnumPtr & p)8901 Slice::Gen::Cpp11StreamVisitor::visitEnum(const EnumPtr& p)
8902 {
8903     if(!p->isLocal())
8904     {
8905         string scoped = fixKwd(p->scoped());
8906         H << nl << "template<>";
8907         H << nl << "struct StreamableTraits< " << scoped << ">";
8908         H << sb;
8909         H << nl << "static const StreamHelperCategory helper = StreamHelperCategoryEnum;";
8910         H << nl << "static const int minValue = " << p->minValue() << ";";
8911         H << nl << "static const int maxValue = " << p->maxValue() << ";";
8912         H << nl << "static const int minWireSize = " << p->minWireSize() << ";";
8913         H << nl << "static const bool fixedLength = false;";
8914         H << eb << ";" << nl;
8915     }
8916 }
8917 
Cpp11CompatibilityVisitor(Output & h,Output &,const string & dllExport)8918 Slice::Gen::Cpp11CompatibilityVisitor::Cpp11CompatibilityVisitor(Output& h, Output&, const string& dllExport) :
8919     H(h),
8920     _dllExport(dllExport)
8921 {
8922 }
8923 
8924 bool
visitModuleStart(const ModulePtr & p)8925 Slice::Gen::Cpp11CompatibilityVisitor::visitModuleStart(const ModulePtr& p)
8926 {
8927     if(!p->hasClassDecls())
8928     {
8929         return false;
8930     }
8931 
8932     string name = fixKwd(p->name());
8933 
8934     H << sp;
8935     H << nl << "/// \\cond INTERNAL";
8936     H << nl << "namespace " << name << nl << '{';
8937     return true;
8938 }
8939 
8940 void
visitModuleEnd(const ModulePtr &)8941 Slice::Gen::Cpp11CompatibilityVisitor::visitModuleEnd(const ModulePtr&)
8942 {
8943     H << sp;
8944     H << nl << '}';
8945     H << nl << "/// \\endcond";
8946 }
8947 
8948 void
visitClassDecl(const ClassDeclPtr & p)8949 Slice::Gen::Cpp11CompatibilityVisitor::visitClassDecl(const ClassDeclPtr& p)
8950 {
8951     if(p->definition() && p->definition()->isDelegate())
8952     {
8953         return;
8954     }
8955 
8956     string name = fixKwd(p->name());
8957     string scoped = fixKwd(p->scoped());
8958 
8959     H << sp << nl << "using " << p->name() << "Ptr = ::std::shared_ptr<" << name << ">;";
8960 
8961     if(!p->isLocal())
8962     {
8963         ClassDefPtr def = p->definition();
8964         if(p->isInterface() || (def && !def->allOperations().empty()))
8965         {
8966             H << nl << "using " << p->name() << "PrxPtr = ::std::shared_ptr<" << p->name() << "Prx>;";
8967         }
8968     }
8969 }
8970 
Cpp11ImplVisitor(Output & h,Output & c,const string & dllExport)8971 Slice::Gen::Cpp11ImplVisitor::Cpp11ImplVisitor(Output& h, Output& c, const string& dllExport) :
8972     H(h), C(c), _dllExport(dllExport), _useWstring(false)
8973 {
8974 }
8975 
8976 string
defaultValue(const TypePtr & type,const string & scope,const StringList & metaData) const8977 Slice::Gen::Cpp11ImplVisitor::defaultValue(const TypePtr& type, const string& scope, const StringList& metaData) const
8978 {
8979     BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
8980     if(builtin)
8981     {
8982         switch(builtin->kind())
8983         {
8984             case Builtin::KindBool:
8985             {
8986                 return "false";
8987             }
8988             case Builtin::KindByte:
8989             case Builtin::KindShort:
8990             case Builtin::KindInt:
8991             case Builtin::KindLong:
8992             {
8993                 return "0";
8994             }
8995             case Builtin::KindFloat:
8996             case Builtin::KindDouble:
8997             {
8998                 return "0.0";
8999             }
9000             case Builtin::KindString:
9001             {
9002                 return "::std::string()";
9003             }
9004             case Builtin::KindValue:
9005             case Builtin::KindObject:
9006             case Builtin::KindObjectProxy:
9007             case Builtin::KindLocalObject:
9008             {
9009                 return "nullptr";
9010             }
9011         }
9012     }
9013     else
9014     {
9015         ProxyPtr prx = ProxyPtr::dynamicCast(type);
9016 
9017         if(ProxyPtr::dynamicCast(type) || ClassDeclPtr::dynamicCast(type))
9018         {
9019             return "nullptr";
9020         }
9021 
9022         StructPtr st = StructPtr::dynamicCast(type);
9023         if(st)
9024         {
9025             return getUnqualified(fixKwd(st->scoped()), scope) + "()";
9026         }
9027 
9028         EnumPtr en = EnumPtr::dynamicCast(type);
9029         if(en)
9030         {
9031             EnumeratorList enumerators = en->enumerators();
9032             return getUnqualified(fixKwd(en->scoped() + "::" + enumerators.front()->name()), scope);
9033         }
9034 
9035         SequencePtr seq = SequencePtr::dynamicCast(type);
9036         if(seq)
9037         {
9038             return typeToString(seq, scope, metaData, _useWstring | TypeContextCpp11) + "()";
9039         }
9040 
9041         DictionaryPtr dict = DictionaryPtr::dynamicCast(type);
9042         if(dict)
9043         {
9044             return getUnqualified(fixKwd(dict->scoped()), scope) + "()";
9045         }
9046     }
9047 
9048     assert(false);
9049     return "???";
9050 }
9051 
9052 bool
visitModuleStart(const ModulePtr & p)9053 Slice::Gen::Cpp11ImplVisitor::visitModuleStart(const ModulePtr& p)
9054 {
9055     if(!p->hasClassDefs())
9056     {
9057         return false;
9058     }
9059 
9060     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
9061 
9062     string name = fixKwd(p->name());
9063 
9064     H << sp << nl << "namespace " << name << nl << '{';
9065 
9066     return true;
9067 }
9068 
9069 void
visitModuleEnd(const ModulePtr &)9070 Slice::Gen::Cpp11ImplVisitor::visitModuleEnd(const ModulePtr&)
9071 {
9072     H << sp;
9073     H << nl << '}';
9074 
9075     _useWstring = resetUseWstring(_useWstringHist);
9076 }
9077 
9078 bool
visitClassDefStart(const ClassDefPtr & p)9079 Slice::Gen::Cpp11ImplVisitor::visitClassDefStart(const ClassDefPtr& p)
9080 {
9081     if(!p->isAbstract())
9082     {
9083         return false;
9084     }
9085 
9086     _useWstring = setUseWstring(p, _useWstringHist, _useWstring);
9087 
9088     string name = p->name();
9089     string scoped = fixKwd(p->scoped());
9090     string scope = fixKwd(p->scope());
9091     string cls = scope.substr(2) + name + "I";
9092     ClassList bases = p->bases();
9093 
9094     H << sp;
9095     H << nl << "class " << name << "I : ";
9096     H.useCurrentPosAsIndent();
9097     H << "public virtual ";
9098 
9099     if(p->isInterface() || p->isLocal())
9100     {
9101         H << fixKwd(name);
9102     }
9103     else
9104     {
9105         H << fixKwd(name + "Disp");
9106     }
9107     H.restoreIndent();
9108 
9109     H << sb;
9110     H.dec();
9111     H << nl << "public:";
9112     H.inc();
9113 
9114     OperationList ops = p->allOperations();
9115 
9116     for(OperationList::const_iterator r = ops.begin(); r != ops.end(); ++r)
9117     {
9118         OperationPtr op = (*r);
9119         string opName = op->name();
9120 
9121         TypePtr ret = op->returnType();
9122         string retS = op->hasMarshaledResult() ?
9123             scoped + "::" + resultStructName(opName, "", true) :
9124             returnTypeToString(ret, op->returnIsOptional(), "", op->getMetaData(), _useWstring | TypeContextCpp11);
9125 
9126         ParamDeclList params = op->parameters();
9127         ParamDeclList outParams;
9128         ParamDeclList inParams;
9129         for(ParamDeclList::const_iterator q = params.begin(); q != params.end(); ++q)
9130         {
9131             if((*q)->isOutParam())
9132             {
9133                 outParams.push_back(*q);
9134             }
9135             else
9136             {
9137                 inParams.push_back(*q);
9138             }
9139         }
9140 
9141         if(!p->isLocal() && (p->hasMetaData("amd") || op->hasMetaData("amd")))
9142         {
9143             string responseParams;
9144 
9145             H << sp << nl << "virtual void " << opName << "Async(";
9146             H.useCurrentPosAsIndent();
9147             for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q)
9148             {
9149                 H << typeToString((*q)->type(), (*q)->optional(), scope,
9150                                   (*q)->getMetaData(), _useWstring | TypeContextInParam | TypeContextCpp11)
9151                   << "," << nl;
9152             }
9153 
9154             if(op->hasMarshaledResult())
9155             {
9156                 responseParams = "const " + scoped + "::" + resultStructName(opName, "", true) + "&";
9157             }
9158             else
9159             {
9160                 if(ret)
9161                 {
9162                     responseParams = inputTypeToString(ret, op->returnIsOptional(), scope, op->getMetaData(),
9163                                                        _useWstring | TypeContextCpp11);
9164                     if(!outParams.empty())
9165                     {
9166                         responseParams += ", ";
9167                     }
9168                 }
9169 
9170                 for(ParamDeclList::iterator q = outParams.begin(); q != outParams.end(); ++q)
9171                 {
9172                     if(q != outParams.begin())
9173                     {
9174                         responseParams += ", ";
9175                     }
9176                     responseParams += inputTypeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(),
9177                                                         _useWstring | TypeContextCpp11);
9178                 }
9179             }
9180 
9181             string isConst = ((op->mode() == Operation::Nonmutating) || op->hasMetaData("cpp:const")) ? " const" : "";
9182 
9183             H << "std::function<void(" << responseParams << ")>,";
9184             H << nl << "std::function<void(std::exception_ptr)>,";
9185             H << nl << "const Ice::Current&)" << isConst << " override;";
9186             H.restoreIndent();
9187 
9188             C << sp << nl << "void" << nl << scope << name << "I::" << opName << "Async(";
9189             C.useCurrentPosAsIndent();
9190             for(ParamDeclList::const_iterator q = inParams.begin(); q != inParams.end(); ++q)
9191             {
9192                 C << typeToString((*q)->type(), (*q)->optional(), scope, (*q)->getMetaData(),
9193                                   _useWstring | TypeContextInParam | TypeContextCpp11);
9194                 C << ' ' << fixKwd((*q)->name()) << "," << nl;
9195             }
9196 
9197             C << "std::function<void(" << responseParams << ")> " << opName << "_response,";
9198             C << nl << "std::function<void(std::exception_ptr)>,";
9199             C << nl << "const Ice::Current& current)" << isConst;
9200             C.restoreIndent();
9201             C << sb;
9202 
9203              C << nl << opName << "_response";
9204             if(op->hasMarshaledResult())
9205             {
9206                 C << "(" << scoped + "::" + resultStructName(opName, "", true);
9207             }
9208             C << spar;
9209             if(ret)
9210             {
9211                 C << defaultValue(ret, scope, op->getMetaData());
9212             }
9213             for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q)
9214             {
9215                 C << defaultValue((*q)->type(), scope, op->getMetaData());
9216             }
9217 
9218             if(op->hasMarshaledResult())
9219             {
9220                 C << "current" << epar << ");";
9221             }
9222             else
9223             {
9224                 C << epar << ';';
9225             }
9226 
9227             C << eb;
9228         }
9229         else
9230         {
9231             H << sp << nl << "virtual " << getUnqualified(retS, scope) << ' ' << fixKwd(opName) << '(';
9232             H.useCurrentPosAsIndent();
9233             ParamDeclList paramList = op->hasMarshaledResult() ? inParams : op->parameters();
9234             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
9235             {
9236                 if(q != paramList.begin())
9237                 {
9238                     H << ',' << nl;
9239                 }
9240                 StringList metaData = (*q)->getMetaData();
9241                 string typeString;
9242                 if((*q)->isOutParam())
9243                 {
9244                     typeString = outputTypeToString((*q)->type(), (*q)->optional(), scope, metaData,
9245                                                     _useWstring | TypeContextCpp11);
9246                 }
9247                 else
9248                 {
9249                     typeString = typeToString((*q)->type(), (*q)->optional(), scope, metaData,
9250                                               _useWstring | TypeContextInParam | TypeContextCpp11);
9251                 }
9252                 H << typeString;
9253             }
9254             if(!p->isLocal())
9255             {
9256                 if(!paramList.empty())
9257                 {
9258                     H << ',' << nl;
9259                 }
9260                 H << "const Ice::Current&";
9261             }
9262             H.restoreIndent();
9263 
9264             string isConst = ((op->mode() == Operation::Nonmutating) || op->hasMetaData("cpp:const")) ? " const" : "";
9265 
9266             H << ")" << isConst << " override;";
9267 
9268             C << sp << nl << retS << nl;
9269             C << scope.substr(2) << name << "I::" << fixKwd(opName) << '(';
9270             C.useCurrentPosAsIndent();
9271             for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q)
9272             {
9273                 if(q != paramList.begin())
9274                 {
9275                     C << ',' << nl;
9276                 }
9277                 StringList metaData = (*q)->getMetaData();
9278                 string typeString;
9279                 if((*q)->isOutParam())
9280                 {
9281                     C << outputTypeToString((*q)->type(), (*q)->optional(), scope, metaData, _useWstring | TypeContextCpp11)
9282                       << " "
9283                       << fixKwd((*q)->name());
9284                 }
9285                 else
9286                 {
9287                     C << typeToString((*q)->type(), (*q)->optional(), scope, metaData,
9288                                       _useWstring | TypeContextInParam | TypeContextCpp11)
9289                       << " /*" << fixKwd((*q)->name()) << "*/";
9290                 }
9291             }
9292             if(!p->isLocal())
9293             {
9294                 if(!paramList.empty())
9295                 {
9296                     C << ',' << nl;
9297                 }
9298                 C << "const Ice::Current& current";
9299             }
9300             C.restoreIndent();
9301             C << ')';
9302             C << isConst;
9303             C << sb;
9304 
9305             if(op->hasMarshaledResult())
9306             {
9307                 if(ret || !outParams.empty())
9308                 {
9309                     C << nl << "return " << scoped << "::" << resultStructName(opName, "", true) << "(";
9310                     if(ret)
9311                     {
9312                         C << defaultValue(ret, scope, op->getMetaData());
9313                         if(!outParams.empty())
9314                         {
9315                             C << ", ";
9316                         }
9317                     }
9318 
9319                     for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end();)
9320                     {
9321                         C << defaultValue((*q)->type(), scope, op->getMetaData());
9322                         if(++q != outParams.end())
9323                         {
9324                             C << ", ";
9325                         }
9326                     }
9327                     C << ", current);";
9328                 }
9329             }
9330             else
9331             {
9332                 for(ParamDeclList::const_iterator q = outParams.begin(); q != outParams.end(); ++q)
9333                 {
9334                     C << nl << fixKwd((*q)->name()) << " = " << defaultValue((*q)->type(), scope, op->getMetaData()) << ";";
9335                 }
9336 
9337                 if(ret)
9338                 {
9339                     C << nl << "return " << defaultValue(ret, scope, op->getMetaData()) << ";";
9340                 }
9341             }
9342             C << eb;
9343         }
9344     }
9345 
9346     H << eb << ';';
9347 
9348     _useWstring = resetUseWstring(_useWstringHist);
9349 
9350     return true;
9351 }
9352