mummy  1.0.3
MummyCsharpGenerator.cxx
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // $Id: MummyCsharpGenerator.cxx 517 2010-11-11 15:00:41Z david.cole $
4 //
5 // $Author: david.cole $
6 // $Date: 2010-11-11 10:00:41 -0500 (Thu, 11 Nov 2010) $
7 // $Revision: 517 $
8 //
9 // Copyright (C) 2006-2009 Kitware, Inc.
10 //
11 //----------------------------------------------------------------------------
12 
13 #include "MummyCsharpGenerator.h"
15 #include "MummyLog.h"
16 #include "MummySettings.h"
17 
18 #include "cableArrayType.h"
19 #include "cableClass.h"
20 #include "cableClassType.h"
21 #include "cableConstructor.h"
22 #include "cableEnumeration.h"
23 #include "cableEnumerationType.h"
24 #include "cableField.h"
25 #include "cableFunctionType.h"
26 #include "cableFundamentalType.h"
27 #include "cableMethod.h"
28 #include "cablePointerType.h"
29 #include "cableReferenceType.h"
30 #include "cableType.h"
31 #include "cableTypedef.h"
32 
33 #include "cxxFundamentalType.h"
34 
35 #include "gxsys/RegularExpression.hxx"
36 #include "gxsys/SystemTools.hxx"
37 #include "gxsys/ios/sstream"
38 #include "gxsys/stl/algorithm"
39 #include "gxsys/stl/map"
40 #include "gxsys/stl/set"
41 #include "gxsys/stl/string"
42 #include "gxsys/stl/vector"
43 
44 #include <string.h> // strstr
45 #include <stdio.h> // sprintf
46 
47 
48 //----------------------------------------------------------------------------
50 {
51  this->CurrentMethodId = 0;
52  this->ClassLineNumber = 0;
53  //this->MethodIdMap; // empty, as constructed
54  //this->TargetInterface; // empty, as constructed
55  //this->HintsMap; // empty, as constructed
56 }
57 
58 
59 //----------------------------------------------------------------------------
61 {
62 }
63 
64 
65 //----------------------------------------------------------------------------
67 {
68  gxsys_stl::string elDllVariableName(this->GetSettings()->GetGroup());
69  elDllVariableName += "EL_dll";
70 
71  this->EmitCSharpWrapperClass(*GetStream(), elDllVariableName.c_str(),
72  GetTargetClass());
73 
74  if (this->GetSettings()->GetVerbose())
75  {
76  gxsys_stl::map<const gxsys_stl::string, gxsys_stl::string>::iterator it;
77  for (it = this->HintsMap.begin(); it != this->HintsMap.end(); ++it)
78  {
79  LogInfo(mi_VerboseInfo, << it->first << ": '" << it->second << "'");
80  }
81  }
82 
83  return true;
84 }
85 
86 
87 //----------------------------------------------------------------------------
88 void MummyCsharpGenerator::SetTargetClass(const cable::Class *c)
89 {
91 
92  // Ensure HeaderFileReader is always called first with the target class.
93  // (Presently, there is only one cached HeaderFileReader and it only reads
94  // the file when it is first called... Subsequent calls ignore the input
95  // data and simply return the cached HeaderFileReader. Multiple readers
96  // may eventually be necessary to support BTX/ETX exclusion fully...)
97  //
98  this->GetHeaderFileReader(c);
99 
100  // Only populate the lookup entries with stuff from the *parent* class
101  // (and its parents...) That way, we can use the existence of a signature
102  // in the table as evidence that a virtual is being overridden (for C#
103  // keyword override purposes) or that a static is being redefined at a
104  // more derived level (hence hiding the parent's definition and requiring
105  // use of the C# keyword "new" to avoid the warning about hiding...)
106  //
109 
110  // Cache a map of the externalHints file:
111  //
112  this->CacheExternalHints(this->GetSettings()->GetExternalHints(c));
113 }
114 
115 
116 //----------------------------------------------------------------------------
117 void MummyCsharpGenerator::CacheExternalHints(const gxsys_stl::string& hintsfile)
118 {
119  gxsys_stl::vector<gxsys_stl::string> hints;
120  gxsys_stl::string line;
121 
122  gxsys::RegularExpression re;
123  re.compile("([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)");
124 
126  reader.SetFileName(hintsfile.c_str());
127 
128  this->HintsMap.clear();
129 
130  unsigned int n = reader.GetNumberOfLines();
131  unsigned int i = 0;
132  for (i= 1; i<=n; ++i)
133  {
134  line = reader.GetLine(i);
135 
136  if (!line.empty())
137  {
138  if (re.find(line))
139  {
140  gxsys_stl::string className = re.match(1);
141  gxsys_stl::string methodName = re.match(2);
142  gxsys_stl::string type = re.match(3);
143  gxsys_stl::string count = re.match(4);
144  gxsys_stl::string key(className + "::" + methodName);
145 
146  if (this->HintsMap.find(key) == this->HintsMap.end())
147  {
148  this->HintsMap[key] = line;
149  }
150  else
151  {
153  "More than one line in the hints file for " << className
154  << "::" << methodName);
155  }
156  }
157  }
158  }
159 }
160 
161 
162 //----------------------------------------------------------------------------
163 void MummyCsharpGenerator::AddTargetInterface(const gxsys_stl::string& iface)
164 {
165  if (this->TargetInterface != "")
166  {
168  "AddTargetInterface being called more than once. " <<
169  "Implementation currently only supports 1 interface. " <<
170  "Clobbering existing target interface: " <<
171  this->TargetInterface);
172  }
173 
174  this->TargetInterface = iface;
175 }
176 
177 
178 //----------------------------------------------------------------------------
179 bool MummyCsharpGenerator::HasTargetInterface(const char *iface) const
180 {
181  if (iface)
182  {
183  return this->TargetInterface == iface;
184  }
185 
186  return false;
187 }
188 
189 
190 //----------------------------------------------------------------------------
192 {
193  static gxsys_stl::set<gxsys_stl::string> keywords;
194 
195  if (0 == keywords.size())
196  {
197  keywords.insert("abstract");
198  keywords.insert("as");
199  keywords.insert("base");
200  keywords.insert("bool");
201  keywords.insert("break");
202  keywords.insert("byte");
203  keywords.insert("case");
204  keywords.insert("catch");
205  keywords.insert("char");
206  keywords.insert("checked");
207  keywords.insert("class");
208  keywords.insert("const");
209  keywords.insert("continue");
210  keywords.insert("decimal");
211  keywords.insert("default");
212  keywords.insert("delegate");
213  keywords.insert("do");
214  keywords.insert("double");
215  keywords.insert("else");
216  keywords.insert("enum");
217  keywords.insert("event");
218  keywords.insert("explicit");
219  keywords.insert("extern");
220  keywords.insert("false");
221  keywords.insert("finally");
222  keywords.insert("fixed");
223  keywords.insert("float");
224  keywords.insert("for");
225  keywords.insert("foreach");
226  keywords.insert("goto");
227  keywords.insert("if");
228  keywords.insert("implicit");
229  keywords.insert("in");
230  keywords.insert("int");
231  keywords.insert("interface");
232  keywords.insert("internal");
233  keywords.insert("is");
234  keywords.insert("lock");
235  keywords.insert("long");
236  keywords.insert("namespace");
237  keywords.insert("new");
238  keywords.insert("null");
239  keywords.insert("object");
240  keywords.insert("operator");
241  keywords.insert("out");
242  keywords.insert("override");
243  keywords.insert("params");
244  keywords.insert("private");
245  keywords.insert("protected");
246  keywords.insert("public");
247  keywords.insert("readonly");
248  keywords.insert("ref");
249  keywords.insert("return");
250  keywords.insert("sbyte");
251  keywords.insert("sealed");
252  keywords.insert("short");
253  keywords.insert("sizeof");
254  keywords.insert("stackalloc");
255  keywords.insert("static");
256  keywords.insert("string");
257  keywords.insert("struct");
258  keywords.insert("switch");
259  keywords.insert("this");
260  keywords.insert("throw");
261  keywords.insert("true");
262  keywords.insert("try");
263  keywords.insert("typeof");
264  keywords.insert("uint");
265  keywords.insert("ulong");
266  keywords.insert("unchecked");
267  keywords.insert("unsafe");
268  keywords.insert("ushort");
269  keywords.insert("using");
270  keywords.insert("virtual");
271  keywords.insert("void");
272  keywords.insert("volatile");
273  keywords.insert("while");
274  }
275 
276  gxsys_stl::set<gxsys_stl::string>::iterator it = keywords.find(gxsys_stl::string(p));
277  if (it != keywords.end())
278  {
279  return true;
280  }
281 
282  return false;
283 }
284 
285 
286 //----------------------------------------------------------------------------
287 bool MummyCsharpGenerator::IsReservedMethodName(const gxsys_stl::string &name)
288 {
289  return (
290  name == "Equals" ||
291  name == "Finalize" ||
292  name == "GetHashCode" ||
293  name == "GetType" ||
294  name == "MemberwiseClone" ||
295  name == "Object" ||
296  name == "ToString");
297 }
298 
299 
300 //----------------------------------------------------------------------------
301 gxsys_stl::string MummyCsharpGenerator::GetFundamentalTypeString(const cable::Type *t)
302 {
303  gxsys_stl::string s;
304 
305  if (cable::Type::FundamentalTypeId == t->GetTypeId())
306  {
307  switch (cxx::FundamentalType::SafeDownCast(t->GetCxxType().GetType())->GetId())
308  {
309  case cxx::FundamentalType::UnsignedChar:
310  s = "byte";
311  break;
312 
313  case cxx::FundamentalType::UnsignedShortInt:
314  s = "ushort";
315  break;
316 
317  case cxx::FundamentalType::UnsignedInt:
318  case cxx::FundamentalType::UnsignedLongInt:
319  s = "uint";
320  break;
321 
322  case cxx::FundamentalType::SignedChar:
323  case cxx::FundamentalType::Char:
324  s = "sbyte";
325  break;
326 
327  case cxx::FundamentalType::ShortInt:
328  s = "short";
329  break;
330 
331  case cxx::FundamentalType::Int:
332  case cxx::FundamentalType::LongInt:
333  s = "int";
334  break;
335 
336  case cxx::FundamentalType::Bool:
337  s = "bool";
338  break;
339 
340  case cxx::FundamentalType::Float:
341  s = "float";
342  break;
343 
344  case cxx::FundamentalType::Double:
345  s = "double";
346  break;
347 
348  case cxx::FundamentalType::Void:
349  s = "void";
350  break;
351 
352  case cxx::FundamentalType::UnsignedLongLongInt:
353  s = "ulong";
354  break;
355 
356  case cxx::FundamentalType::LongLongInt:
357  s = "long";
358  break;
359 
360  //case cxx::FundamentalType::WChar_t:
361  //case cxx::FundamentalType::LongDouble:
362  //case cxx::FundamentalType::ComplexFloat:
363  //case cxx::FundamentalType::ComplexDouble:
364  //case cxx::FundamentalType::ComplexLongDouble:
365  //case cxx::FundamentalType::NumberOfTypes:
366 
367  default:
368  break;
369  }
370  }
371 
372  if (s == "")
373  {
375  << "Unhandled variable type. GetFundamentalTypeString returning the empty string...");
376  }
377 
378  return s;
379 }
380 
381 
382 //----------------------------------------------------------------------------
383 gxsys_stl::string MummyCsharpGenerator::GetWrappedMethodName(const cable::Method *m)
384 {
385  gxsys_stl::string name(m->GetName());
386 
387  if (IsReservedMethodName(name))
388  {
389  name = name + "Wrapper";
390 
391  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_ReservedMethodName,
392  << "Reserved method name '" << m->GetName() << "' used. Rename it to eliminate this warning...");
393  }
394 
395  return name;
396 }
397 
398 
399 //----------------------------------------------------------------------------
400 gxsys_stl::string GetWrappedEnumName(const cable::Enumeration *e)
401 {
402  gxsys_stl::string ename(e->GetName());
403 
404  // Don't name unnamed enums with invalid C#/C++ identifiers like "$"...
405  //
406  if (ename == "" ||
407  strstr(ename.c_str(), "$"))
408  {
409  if (e->Begin() != e->End())
410  {
411  ename = *(e->Begin());
412  ename += "_WrapperEnum";
413  }
414  else
415  {
416  ename = "WARNING_unnamed_enum";
417  }
418 
419  LogFileLineWarningMsg(e->GetFile(), e->GetLine(), mw_UnnamedEnum,
420  "Unnamed enum found. Name it to eliminate this warning...");
421  }
422 
423  return ename;
424 }
425 
426 
427 //----------------------------------------------------------------------------
429  const gxsys_stl::string& hint,
430  gxsys_stl::string& type,
431  gxsys_stl::string& count
432 )
433 {
434  gxsys::RegularExpression re;
435  re.compile("([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)[\t ]+([^\t ]+)");
436 
437  if (re.find(hint))
438  {
439  //className = re.match(1);
440  //methodName = re.match(2);
441  type = re.match(3);
442  count = re.match(4);
443  return true;
444  }
445 
446  return false;
447 }
448 
449 
450 //----------------------------------------------------------------------------
452  cable::Type *t,
453  const gxsys_stl::string& type
454  )
455 {
456  gxsys_stl::string utype = gxsys::SystemTools::UpperCase(type);
457 
458  // Init with the "not a real enum value" value:
459  //
460  cxx::FundamentalType::Id ftid = cxx::FundamentalType::NumberOfTypes;
461 
462  // Values of 'type' currently present in the VTK hints file are:
463  //
464  if (utype == "301") { ftid = cxx::FundamentalType::Float; }
465  else if (utype == "304") { ftid = cxx::FundamentalType::Int; }
466  else if (utype == "307") { ftid = cxx::FundamentalType::Double; }
467  else if (utype == "30A") { ftid = cxx::FundamentalType::Int; } // vtkIdType (could be 32 or 64 bit...)
468  else if (utype == "2307") { ftid = cxx::FundamentalType::Double; } // 0x2307 == double* + something?
469 
470  if (cxx::FundamentalType::NumberOfTypes == ftid)
471  {
472  LogWarning(mw_UnknownHintDataType, "Unknown externalHints data type string '" << type << "'");
473  }
474  else if (IsFundamentalPointer(t, ftid))
475  {
476  return true;
477  }
478 
479  return false;
480 }
481 
482 
483 //----------------------------------------------------------------------------
485  const gxsys_stl::string& line,
486  gxsys_stl::string& count
487 )
488 {
489  // Grudgingly allow this VTK-ism to creep into the mummy codebase to avoid
490  // introducing a list of regular expressions in the MummySettings.xml file
491  // just for VTK-wrapping-hint-based array size specification...
492  //
493  // In VTK, in addition to the explicit external hints file VTK/Wrapping/hints,
494  // the following macros from VTK/Common/vtkSetGet.h are also recognized as
495  // implicitly having hint sizes associated with them:
496  //
497  gxsys::RegularExpression re;
498 
499  re.compile("^[\t ]*vtkGetVector([0-9]+)Macro\\(.*,.*\\)");
500  if (re.find(line))
501  {
502  count = re.match(1);
503  return true;
504  }
505 
506  re.compile("^[\t ]*vtkGetVectorMacro\\(.*,.*,.*([0-9]+).*\\)");
507  if (re.find(line))
508  {
509  count = re.match(1);
510  return true;
511  }
512 
513  re.compile("^[\t ]*vtkViewportCoordinateMacro\\(.*\\)");
514  if (re.find(line))
515  {
516  count = "2";
517  return true;
518  }
519 
520  re.compile("^[\t ]*vtkWorldCoordinateMacro\\(.*\\)");
521  if (re.find(line))
522  {
523  count = "3";
524  return true;
525  }
526 
527  return false;
528 }
529 
530 
531 //----------------------------------------------------------------------------
532 // Callers of GetMethodArgumentArraySize pass this value as "i" to query
533 // about the return value of the method. Otherwise, "i" is presumed to be an
534 // index (0 to cArgs-1) of one of the method's arguments.
535 #define RETURN_VALUE (0x84848484)
536 
537 
538 //----------------------------------------------------------------------------
539 gxsys_stl::string MummyCsharpGenerator::GetMethodArgumentArraySize(const cable::Class *c,
540  const cable::Method *m, const cable::FunctionType *ft, unsigned int i)
541 {
542  gxsys_stl::string argArraySize;
543  cable::Type *retType = 0;
544 
545  // First check for an attribute directly in the source code:
546  //
547  gxsys_stl::string atts;
548 
549  if (RETURN_VALUE == i)
550  {
551  atts = m->GetAttributes();
552  }
553  else
554  {
555  atts = ft->GetArgumentAttributes(i);
556  }
557 
558  if (atts != "")
559  {
560  argArraySize = ExtractArraySize(atts);
561  }
562 
563  // If no direct hint, check the externalHints file, if any:
564  //
565  if ((argArraySize == "") && (this->HintsMap.size() > 0))
566  {
567  // The VTK/Wrapping/hints file only tells us about the size of the pointer
568  // returned by the method. Only return a non-empty array size from a
569  // VTK/Wrapping/hints-style file if this is for a return value of a method:
570  //
571  if (RETURN_VALUE == i)
572  {
573  retType = ft->GetReturns();
574  if (!IsVoid(retType))
575  {
576  gxsys_stl::string methodName(m->GetName());
577  gxsys_stl::map<const gxsys_stl::string, gxsys_stl::string>::iterator it;
578 
579  const cable::Class *cIt = c;
580  while (cIt != NULL && (argArraySize == ""))
581  {
582  gxsys_stl::string fullClassName(GetFullyQualifiedNameForCPlusPlus(cIt));
583  gxsys_stl::string key(fullClassName + "::" + methodName);
584  gxsys_stl::string hintline;
585 
586  it = this->HintsMap.find(key);
587  if (it != this->HintsMap.end())
588  {
589  hintline = it->second;
590 
591  gxsys_stl::string type;
592  gxsys_stl::string count;
593  if (ExtractTypeAndCountFromHintLine(hintline, type, count) &&
594  ReturnTypeMatchesHintType(retType, type))
595  {
596  argArraySize = count;
597  LogVerboseInfo("using external array size hint: " << argArraySize << " " << key);
598  }
599  }
600 
601  // If not found yet, keep looking up at parent class hints to see
602  // if it is inherited. Method name and return type should still match
603  // even if the hint is at the parent class level.
604  //
605  if (argArraySize == "")
606  {
607  cIt = GetParentClass(cIt);
608  }
609  }
610  }
611  }
612  }
613 
614  // If still no hint, see if the line declaring the method in the header
615  // file uses a macro that gives us a hint about the size of the array...
616  //
617  if (argArraySize == "")
618  {
619  if (RETURN_VALUE == i)
620  {
621  retType = ft->GetReturns();
622  if (!IsVoid(retType) && !IsObjectPointer(retType))
623  {
624  gxsys_stl::string line(this->GetHeaderFileReader(c)->GetLine(m->GetLine()));
625  gxsys_stl::string count;
626 
627  if (ExtractCountFromMethodDeclarationLine(line, count))
628  {
629  argArraySize = count;
630 
631  if (this->GetSettings()->GetVerbose())
632  {
633  LogFileLineInfoMsg(c->GetFile(), m->GetLine(), mi_VerboseInfo,
634  "inferred array size hint '" << count <<
635  "' from method declaration '" << line << "'");
636  }
637  }
638  }
639  }
640  }
641 
642  return argArraySize;
643 }
644 
645 
646 //----------------------------------------------------------------------------
647 //
648 // GetMethodSignature is very similar to EmitCSharpMethodDeclaration.
649 // Changes in either may need to be made in both places...
650 //
651 gxsys_stl::string MummyCsharpGenerator::GetMethodSignature(const cable::Class *c, const cable::Method *m)
652 {
653  gxsys_ios::ostringstream os;
654 
655  cable::FunctionType *ft = m->GetFunctionType();
656  unsigned int cArgs = ft->GetNumberOfArguments();
657  unsigned int i = 0;
658  cable::Type *argType = 0;
659 
660  // Method name:
661  Emit(os, GetWrappedMethodName(m).c_str());
662 
663  // Open args:
664  Emit(os, "(");
665 
666  // The C# arg types:
667  for (i= 0; i<cArgs; ++i)
668  {
669  argType = ft->GetArgument(i);
670 
671  // Is arg an array?
672  //
673  gxsys_stl::string argArraySize(GetMethodArgumentArraySize(c, m, ft, i));
674 
675  // arg type:
676  Emit(os, GetCSharpTypeString(argType, false, argArraySize != "").c_str());
677 
678  // array notation:
679  if (argArraySize != "")
680  {
681  Emit(os, "[]");
682  }
683 
684  if (i<cArgs-1)
685  {
686  Emit(os, ", ");
687  }
688  }
689 
690  // Close args:
691  Emit(os, ")");
692 
693  return os.str();
694 }
695 
696 
697 //----------------------------------------------------------------------------
698 const char *MummyCsharpGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i)
699 {
700  const char *p = ftype->GetArgumentName(i);
701 
702  if (p && *p && !IsKeyword(p))
703  {
704  return p;
705  }
706 
707  // Hacky, but for now:
708  static char buf[32];
709  sprintf(buf, "arg%u", i);
710  return buf;
711 }
712 
713 
714 //----------------------------------------------------------------------------
716 {
717  if (cable::Type::FundamentalTypeId == t->GetTypeId())
718  {
719  switch (cxx::FundamentalType::SafeDownCast(t->GetCxxType().GetType())->GetId())
720  {
721  case cxx::FundamentalType::UnsignedChar:
722  case cxx::FundamentalType::UnsignedShortInt:
723  case cxx::FundamentalType::UnsignedInt:
724  case cxx::FundamentalType::UnsignedLongInt:
725  case cxx::FundamentalType::SignedChar:
726  case cxx::FundamentalType::Char:
727  case cxx::FundamentalType::ShortInt:
728  case cxx::FundamentalType::Int:
729  case cxx::FundamentalType::LongInt:
730  case cxx::FundamentalType::Bool:
731  case cxx::FundamentalType::Float:
732  case cxx::FundamentalType::Double:
733  case cxx::FundamentalType::Void:
734  case cxx::FundamentalType::UnsignedLongLongInt:
735  case cxx::FundamentalType::LongLongInt:
736  return true;
737  break;
738 
739  case cxx::FundamentalType::WChar_t:
740  case cxx::FundamentalType::LongDouble:
741  case cxx::FundamentalType::ComplexFloat:
742  case cxx::FundamentalType::ComplexDouble:
743  case cxx::FundamentalType::ComplexLongDouble:
744  case cxx::FundamentalType::NumberOfTypes:
745  default:
746  break;
747  }
748  }
749 
750  return false;
751 }
752 
753 
754 //----------------------------------------------------------------------------
755 bool MummyCsharpGenerator::TypeIsWrappable(const cable::Type* t)
756 {
757  bool wrappable = false;
758 
759  switch (t->GetTypeId())
760  {
761  case cable::Type::EnumerationTypeId:
762  wrappable = true;
763  break;
764 
765  case cable::Type::FundamentalTypeId:
766  wrappable = FundamentalTypeIsWrappable(t);
767  break;
768 
769  case cable::Type::ArrayTypeId:
770  wrappable = false;//TypeIsWrappable(cable::ArrayType::SafeDownCast(t)->GetTarget());
771  break;
772 
773  case cable::Type::ClassTypeId:
774  wrappable = ClassIsWrappable(cable::ClassType::SafeDownCast(t)->GetClass());
775  break;
776 
777  case cable::Type::PointerTypeId:
778  {
779  cable::Type *nested_type = cable::PointerType::SafeDownCast(t)->GetTarget();
780  cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId();
781 
782  // Only pointers to enums, fundamentals and objects are wrappable
783  // and then only if the nested type is also wrappable...
784  //
785  // A function pointer is "nearly" wrappable (as a delegate definition)
786  // if its return type and all of its argument types are wrappable.
787  // And it has a typedef that names it within this class (because
788  // that typedef is the thing that generates the delegate def in
789  // the C# class...)
790  //
791  // (This is what prevents pointers to pointers from being wrapped
792  // in the general case...)
793  //
794  if (cable::Type::EnumerationTypeId == nested_type_id ||
795  cable::Type::FundamentalTypeId == nested_type_id ||
796  cable::Type::ClassTypeId == nested_type_id)
797  {
798  wrappable = TypeIsWrappable(nested_type);
799  }
800  else if (cable::Type::FunctionTypeId == nested_type_id)
801  {
802  gxsys_stl::string s;
803 
804  // Only really wrappable if nested_type is wrappable and an
805  // equivalent typedef name exists:
806  //
807  wrappable = TypeIsWrappable(nested_type) &&
809  cable::FunctionType::SafeDownCast(nested_type), s);
810  }
811  else
812  {
813  wrappable = false; // as initialized...
814  }
815  }
816  break;
817 
818  case cable::Type::ReferenceTypeId:
819  {
820  cable::Type *nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget();
821  cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId();
822 
823  wrappable = false; // as initialized...
824 
825  if (cable::Type::EnumerationTypeId == nested_type_id ||
826  cable::Type::FundamentalTypeId == nested_type_id ||
827  cable::Type::ClassTypeId == nested_type_id)
828  {
829  wrappable = TypeIsWrappable(nested_type);
830  }
831  else if (cable::Type::PointerTypeId == nested_type_id)
832  {
833  // References to pointers are allowed, but only if the pointer points
834  // to a wrappable class...
835  //
836  cable::Type *doubly_nested_type = cable::PointerType::SafeDownCast(nested_type)->GetTarget();
837  cable::Type::TypeIdType doubly_nested_type_id = doubly_nested_type->GetTypeId();
838 
839  if (cable::Type::ClassTypeId == doubly_nested_type_id)
840  {
841  wrappable = TypeIsWrappable(doubly_nested_type);
842  }
843  }
844  }
845  break;
846 
847  case cable::Type::OffsetTypeId:
848  case cable::Type::MethodTypeId:
849  wrappable = false;
850  break;
851 
852  case cable::Type::FunctionTypeId:
853  wrappable = FunctionTypeIsWrappable(cable::FunctionType::SafeDownCast(t));
854  break;
855 
856  default:
857  wrappable = false;
858  break;
859  }
860 
861  return wrappable;
862 }
863 
864 
865 //----------------------------------------------------------------------------
866 bool IsCxxMainStyleParamPair(const cable::FunctionType* ft, unsigned int i)
867 {
868  // Special case C++ "main" style functions, as indicated by *this* *exact*
869  // *signature* including arg names:
870  // (..., int argc, char* argv[], ...)
871  //
872  if (i < ft->GetNumberOfArguments()-1 &&
873  gxsys_stl::string("argc") == ft->GetArgumentName(i) &&
874  cable::Type::FundamentalTypeId == ft->GetArgument(i)->GetTypeId() &&
875  cxx::FundamentalType::Int == cxx::FundamentalType::SafeDownCast(ft->GetArgument(i)->GetCxxType().GetType())->GetId() &&
876  gxsys_stl::string("argv") == ft->GetArgumentName(i+1) &&
877  IsCharPointerPointer(ft->GetArgument(i+1))
878  )
879  {
880  return true;
881  }
882 
883  return false;
884 }
885 
886 
887 //----------------------------------------------------------------------------
888 bool MummyCsharpGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft)
889 {
890  bool wrappable = true;
891 
892  cable::Type *argType = 0;
893  cable::Type *retType = 0;
894  unsigned int i = 0;
895  unsigned int cArgs = ft->GetNumberOfArguments();
896 
897  retType = ft->GetReturns();
898  wrappable = TypeIsWrappable(retType);
899 
900  for (i= 0; wrappable && i<cArgs; ++i)
901  {
902  argType = ft->GetArgument(i);
903  wrappable = TypeIsWrappable(argType);
904 
905  // If not wrappable because argType is "char**" but it is a cxx main style
906  // param pair, then go ahead and say it is wrappable...
907  //
908  if (!wrappable && IsCxxMainStyleParamPair(ft, i-1))
909  {
910  wrappable = true;
911  }
912  }
913 
914  return wrappable;
915 }
916 
917 
918 //----------------------------------------------------------------------------
919 bool MummyCsharpGenerator::MethodWrappableAsEvent(const cable::Method* m, const cable::Context::Access& access)
920 {
921  bool wrappableAsEvent = false;
922  gxsys_stl::string atts;
923 
924  if (m)
925  {
926  if (cable::Context::Public == access)
927  {
928  if (cable::Function::FunctionId == m->GetFunctionId() ||
929  cable::Function::MethodId == m->GetFunctionId())
930  {
931  wrappableAsEvent = HasAttribute(m, "gccxml(iwhEvent)");
932  }
933  }
934  }
935 
936  return wrappableAsEvent;
937 }
938 
939 //----------------------------------------------------------------------------
940 bool MummyCsharpGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access)
941 {
942  bool wrappable = false;
943  bool hasDeprecatedAttribute = false;
944  bool hasExcludeAttribute = false;
945  bool isExcludedViaBtxEtx = false;
946 
947  if (m)
948  {
949  if (cable::Context::Public == access)
950  {
951  if (cable::Function::FunctionId == m->GetFunctionId() ||
952  cable::Function::MethodId == m->GetFunctionId())
953  {
954  if (FunctionTypeIsWrappable(m->GetFunctionType()))
955  {
956  wrappable = true;
957  }
958  }
959  }
960  }
961 
962  if (m && wrappable)
963  {
964  hasDeprecatedAttribute = HasAttribute(m, "deprecated");
965  hasExcludeAttribute = HasAttribute(m, "gccxml(iwhExclude)");
966 
967  if (hasDeprecatedAttribute || hasExcludeAttribute)
968  {
969  wrappable = false;
970  }
971  }
972 
973  if (m && wrappable)
974  {
975  cable::Class* c = cable::Class::SafeDownCast(m->GetContext());
976 
977  // BTX ETX style exclusion can only be applied to methods of the current target
978  // class... We need to add multiple HeaderFileReader support to enable BTX ETX style
979  // exclusion fully (including parent class method exclusion for purposes of constructing
980  // the initial "what virtual methods do I inherit?" table...)
981  //
982  if (c && c == this->GetTargetClass() &&
983  this->GetHeaderFileReader(c)->IsLineExcluded(m->GetLine()))
984  {
985  isExcludedViaBtxEtx = true;
986  wrappable = false;
987  }
988  }
989 
990  if (this->GetSettings()->GetVerbose())
991  {
992  if (m)
993  {
994  if (cable::Context::Public == access)
995  {
996  if (cable::Function::FunctionId == m->GetFunctionId() ||
997  cable::Function::MethodId == m->GetFunctionId())
998  {
999  if (wrappable)
1000  {
1001  LogInfo(mi_VerboseInfo, << m->GetNameOfClass() << " '" << m->GetName()
1002  << "' is wrappable..." << gxsys_ios::endl);
1003  }
1004  else
1005  {
1006  if (hasDeprecatedAttribute)
1007  {
1008  LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName()
1009  << "' could not be wrapped because it is marked with the 'deprecated' attribute..." << gxsys_ios::endl);
1010  }
1011  else if (hasExcludeAttribute)
1012  {
1013  LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName()
1014  << "' could not be wrapped because it is marked with the 'gccxml(iwhExclude)' attribute..." << gxsys_ios::endl);
1015  }
1016  else if (isExcludedViaBtxEtx)
1017  {
1018  LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName()
1019  << "' could not be wrapped because it is in between begin/end exclude markers (BTX/ETX)..." << gxsys_ios::endl);
1020  }
1021  else
1022  {
1023  LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName()
1024  << "' could not be wrapped because of its return type or one of its arguments' types..." << gxsys_ios::endl);
1025  }
1026  }
1027  }
1028  else
1029  {
1030  LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName()
1031  << "' could not be wrapped because it's not a function or method..." << gxsys_ios::endl);
1032  }
1033  }
1034  else
1035  {
1036  LogWarning(mw_CouldNotWrap, << m->GetNameOfClass() << " '" << m->GetName()
1037  << "' is not considered for wrapping because of its non-public access level..." << gxsys_ios::endl);
1038  }
1039  }
1040  else
1041  {
1042  LogWarning(mw_CouldNotWrap, << "NULL m!!" << gxsys_ios::endl);
1043  }
1044  }
1045 
1046  return wrappable;
1047 }
1048 
1049 
1050 //----------------------------------------------------------------------------
1051 bool MummyCsharpGenerator::ClassIsWrappable(const cable::Class* c)
1052 {
1054 }
1055 
1056 
1057 //----------------------------------------------------------------------------
1058 const cable::Class* MummyCsharpGenerator::GetWrappableParentClass(const cable::Class *c)
1059 {
1060  const cable::Class* wrappableParent = GetParentClass(c);
1061 
1062  while (wrappableParent && !this->ClassIsWrappable(wrappableParent))
1063  {
1064  wrappableParent = GetParentClass(wrappableParent);
1065  }
1066 
1067  return wrappableParent;
1068 }
1069 
1070 
1071 //----------------------------------------------------------------------------
1072 //
1073 // WARNING: GetIsRefArg, GetPInvokeTypeString and GetCSharpTypeString need to
1074 // stay in sync. Changes in one likely imply that changes in the other are
1075 // also required...
1076 //
1077 // This function needs to stay in sync with the case in GetCSharpTypeString
1078 // where "ref " is prepended to the C# type string... If "ref " is prepended
1079 // then this function should return true.
1080 //
1081 bool MummyCsharpGenerator::GetIsRefArg(const cable::Type *t)
1082 {
1083  cable::Type *nested_type = 0;
1084 
1085  if (cable::Type::ReferenceTypeId == t->GetTypeId())
1086  {
1087  nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget();
1088  cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId();
1089 
1090  if (cable::Type::EnumerationTypeId == nested_type_id ||
1091  cable::Type::FundamentalTypeId == nested_type_id)
1092  {
1093  return true;
1094  }
1095  }
1096 
1097  return false;
1098 }
1099 
1100 
1101 //----------------------------------------------------------------------------
1102 gxsys_stl::string /* MummyCsharpGenerator:: */ GetEnumerationTypeString(const cable::Type *t)
1103 {
1104  gxsys_stl::string s;
1105  cable::Enumeration* e = cable::EnumerationType::SafeDownCast(t)->GetEnumeration();
1106 
1108 
1109  // Don't name unnamed enums with invalid C#/C++ identifiers like "$"...
1110  //
1111  if (strstr(s.c_str(), "$"))
1112  {
1113  s = "uint /* WARNING_unnamed_enum */";
1114  }
1115 
1116  return s;
1117 }
1118 
1119 
1120 //----------------------------------------------------------------------------
1121 //
1122 // WARNING: GetIsRefArg, GetPInvokeTypeString and GetCSharpTypeString need to
1123 // stay in sync. Changes in one likely imply that changes in the other are
1124 // also required...
1125 //
1126 gxsys_stl::string MummyCsharpGenerator::GetPInvokeTypeString(const cable::Type *t, bool forReturn, bool isArray, bool forDelegate)
1127 {
1128  gxsys_stl::string s;
1129  cable::Type *nested_type = 0;
1130 
1131  switch (t->GetTypeId())
1132  {
1133  case cable::Type::EnumerationTypeId:
1134  s = GetEnumerationTypeString(t);
1135  break;
1136 
1137  case cable::Type::FundamentalTypeId:
1138  s = GetFundamentalTypeString(t);
1139 
1140  // C# byte maps automatically to C++ bool via PInvoke
1141  //
1142  if (s == "bool")
1143  {
1144  s = "byte";
1145  }
1146  break;
1147 
1148  case cable::Type::ArrayTypeId:
1149  s = "ERROR_ArrayTypeId_not_yet_implemented";
1150  LogError(me_InternalError, << s.c_str());
1151  break;
1152 
1153  case cable::Type::ClassTypeId:
1154  //s = cable::ClassType::SafeDownCast(t)->GetClass()->GetName();
1155  s = GetWrappedClassNameFullyQualified(cable::ClassType::SafeDownCast(t)->GetClass());
1156  break;
1157 
1158  case cable::Type::PointerTypeId:
1159  nested_type = cable::PointerType::SafeDownCast(t)->GetTarget();
1160 
1161  if (IsObject(nested_type))
1162  {
1163  if (forReturn || forDelegate)
1164  {
1165  s = "IntPtr";
1166  }
1167  else
1168  {
1169  cable::Class *c = cable::ClassType::SafeDownCast(nested_type)->GetClass();
1170  if (IsUtilityClass(c))
1171  {
1172  //s = c->GetName();
1174  }
1175  else
1176  {
1177  s = "HandleRef";
1178  }
1179  }
1180  }
1181  else if (IsChar(nested_type))
1182  {
1183  if (forReturn)
1184  {
1185  s = "IntPtr";
1186  }
1187  else
1188  {
1189  s = "string";
1190  }
1191  }
1192  else if (IsVoid(nested_type))
1193  {
1194  s = "IntPtr";
1195  }
1196  else if (cable::Type::FundamentalTypeId == nested_type->GetTypeId())
1197  {
1198  if (isArray && !forReturn)
1199  {
1200  s = GetPInvokeTypeString(nested_type, forReturn, isArray, forDelegate);
1201  }
1202  else
1203  {
1204  s = "IntPtr";
1205  }
1206  }
1207  else if (cable::Type::PointerTypeId == nested_type->GetTypeId())
1208  {
1209  if (IsCharPointer(nested_type))
1210  {
1211  s = "[In, Out] string[]";
1212  }
1213  else
1214  {
1215  s = "IntPtr /* pointer-to-pointer */";
1216  }
1217  }
1218  else if (cable::Type::FunctionTypeId == nested_type->GetTypeId())
1219  {
1221  cable::FunctionType::SafeDownCast(nested_type), s))
1222  {
1223  s = "ERROR_No_equivalent_typedef_name_for_function_pointer";
1224  LogError(me_InternalError, << s.c_str());
1225  }
1226  }
1227  else
1228  {
1229  s = "ERROR_PointerTypeId_not_yet_implemented_for_nested_type";
1230  LogError(me_InternalError, << s.c_str());
1231  }
1232  break;
1233 
1234  case cable::Type::ReferenceTypeId:
1235  {
1236  cable::Type *nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget();
1237  cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId();
1238 
1239  s = "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type";
1240 
1241  if (cable::Type::EnumerationTypeId == nested_type_id ||
1242  cable::Type::FundamentalTypeId == nested_type_id ||
1243  cable::Type::ClassTypeId == nested_type_id)
1244  {
1245  s = GetPInvokeTypeString(nested_type, forReturn, isArray, forDelegate);
1246 
1247  if (!isArray && (cable::Type::EnumerationTypeId == nested_type_id ||
1248  cable::Type::FundamentalTypeId == nested_type_id))
1249  {
1250  if (forReturn)
1251  {
1252  s = "IntPtr";
1253  }
1254  else
1255  {
1256  s = gxsys_stl::string("ref ") + s;
1257  }
1258  }
1259  }
1260  else if (cable::Type::PointerTypeId == nested_type_id)
1261  {
1262  // References to pointers are allowed, but only if the pointer points
1263  // to a wrappable class...
1264  //
1265  cable::Type *doubly_nested_type = cable::PointerType::SafeDownCast(nested_type)->GetTarget();
1266  cable::Type::TypeIdType doubly_nested_type_id = doubly_nested_type->GetTypeId();
1267 
1268  if (cable::Type::ClassTypeId == doubly_nested_type_id)
1269  {
1270  s = GetPInvokeTypeString(nested_type, forReturn, isArray, forDelegate);
1271  }
1272  }
1273 
1274  if (s == "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type")
1275  {
1276  LogError(me_InternalError, << s.c_str());
1277  }
1278  }
1279  break;
1280 
1281  case cable::Type::OffsetTypeId:
1282  case cable::Type::MethodTypeId:
1283  case cable::Type::FunctionTypeId:
1284  default:
1285  s = "ERROR_No_CSharp_type_for_cable_Type_TypeId";
1286  LogError(me_InternalError, << s.c_str());
1287  break;
1288  }
1289 
1290  return s;
1291 }
1292 
1293 
1294 //----------------------------------------------------------------------------
1295 //
1296 // WARNING: GetIsRefArg, GetPInvokeTypeString and GetCSharpTypeString need to
1297 // stay in sync. Changes in one likely imply that changes in the other are
1298 // also required...
1299 //
1300 gxsys_stl::string MummyCsharpGenerator::GetCSharpTypeString(const cable::Type *t, bool forReturn, bool isArray)
1301 {
1302  gxsys_stl::string s;
1303  cable::Type *nested_type = 0;
1304 
1305  switch (t->GetTypeId())
1306  {
1307  case cable::Type::EnumerationTypeId:
1308  s = GetEnumerationTypeString(t);
1309  break;
1310 
1311  case cable::Type::FundamentalTypeId:
1312  s = GetFundamentalTypeString(t);
1313  break;
1314 
1315  case cable::Type::ArrayTypeId:
1316  s = "ERROR_ArrayTypeId_not_yet_implemented";
1317  LogError(me_InternalError, << s.c_str());
1318  break;
1319 
1320  case cable::Type::ClassTypeId:
1321  //s = cable::ClassType::SafeDownCast(t)->GetClass()->GetName();
1322  s = GetWrappedClassNameFullyQualified(cable::ClassType::SafeDownCast(t)->GetClass());
1323  break;
1324 
1325  case cable::Type::PointerTypeId:
1326  nested_type = cable::PointerType::SafeDownCast(t)->GetTarget();
1327 
1328  if (IsObject(nested_type))
1329  {
1330  s = GetCSharpTypeString(nested_type, forReturn, isArray);
1331  }
1332  else if (IsChar(nested_type))
1333  {
1334  s = "string";
1335  }
1336  else if (IsVoid(nested_type))
1337  {
1338  s = "IntPtr";
1339  }
1340  else if (cable::Type::FundamentalTypeId == nested_type->GetTypeId())
1341  {
1342  if (isArray)
1343  {
1344  s = GetCSharpTypeString(nested_type, forReturn, isArray);
1345  }
1346  else
1347  {
1348  s = "IntPtr";
1349  }
1350  }
1351  else if (cable::Type::PointerTypeId == nested_type->GetTypeId())
1352  {
1353  s = GetCSharpTypeString(nested_type, forReturn, isArray);
1354 
1355  if (IsCharPointer(nested_type))
1356  {
1357  s += "[]";
1358  }
1359  else
1360  {
1361  s += " /* pointer-to-pointer */ ";
1362  }
1363  }
1364  else if (cable::Type::FunctionTypeId == nested_type->GetTypeId())
1365  {
1366  s = GetCSharpTypeString(nested_type, forReturn, isArray);
1367  }
1368  else
1369  {
1370  s = "ERROR_PointerTypeId_not_yet_implemented_for_nested_type";
1371  LogError(me_InternalError, << s.c_str());
1372  }
1373  break;
1374 
1375  case cable::Type::ReferenceTypeId:
1376  {
1377  cable::Type *nested_type = cable::ReferenceType::SafeDownCast(t)->GetTarget();
1378  cable::Type::TypeIdType nested_type_id = nested_type->GetTypeId();
1379 
1380  s = "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type";
1381 
1382  if (cable::Type::EnumerationTypeId == nested_type_id ||
1383  cable::Type::FundamentalTypeId == nested_type_id ||
1384  cable::Type::ClassTypeId == nested_type_id)
1385  {
1386  s = GetCSharpTypeString(nested_type, forReturn, isArray);
1387 
1388  if (!isArray && (cable::Type::EnumerationTypeId == nested_type_id ||
1389  cable::Type::FundamentalTypeId == nested_type_id))
1390  {
1391  if (forReturn)
1392  {
1393  s = "IntPtr";
1394  }
1395  else if (s == "bool")
1396  {
1397  // Special case: transform "ref bool" args to "ref byte" args so
1398  // that we can call the PInvoke method, which changes all "bool"
1399  // to "byte" -- we don't do it in the non-ref case because it works
1400  // automatically and "bool" is a nicer C# signature. But in the ref
1401  // case, we need:
1402  //
1403  s = gxsys_stl::string("ref byte");
1404  }
1405  else
1406  {
1407  s = gxsys_stl::string("ref ") + s;
1408  }
1409  }
1410  }
1411  else if (cable::Type::PointerTypeId == nested_type_id)
1412  {
1413  // References to pointers are allowed, but only if the pointer points
1414  // to a wrappable class...
1415  //
1416  cable::Type *doubly_nested_type = cable::PointerType::SafeDownCast(nested_type)->GetTarget();
1417  cable::Type::TypeIdType doubly_nested_type_id = doubly_nested_type->GetTypeId();
1418 
1419  if (cable::Type::ClassTypeId == doubly_nested_type_id)
1420  {
1421  s = GetCSharpTypeString(doubly_nested_type, forReturn, isArray);
1422  }
1423  }
1424 
1425  if (s == "ERROR_ReferenceTypeId_not_yet_implemented_for_nested_type")
1426  {
1427  LogError(me_InternalError, << s.c_str());
1428  }
1429  }
1430  break;
1431 
1432  case cable::Type::FunctionTypeId:
1434  cable::FunctionType::SafeDownCast(t), s))
1435  {
1436  s = "ERROR_No_equivalent_typedef_name_for_function_pointer";
1437  LogError(me_InternalError, << s.c_str());
1438  }
1439  break;
1440 
1441  case cable::Type::OffsetTypeId:
1442  case cable::Type::MethodTypeId:
1443  default:
1444  s = "ERROR_No_CSharp_type_for_cable_Type_TypeId";
1445  LogError(me_InternalError, << s.c_str());
1446  break;
1447  }
1448 
1449  return s;
1450 }
1451 
1452 
1453 //----------------------------------------------------------------------------
1455 {
1456 public:
1457  const cable::Class* Class;
1458  const cable::Method* Method;
1459 
1460  MethodInstance(const cable::Class* c, const cable::Method* m) :
1461  Class(c), Method(m)
1462  {
1463  }
1464 };
1465 
1466 
1467 //----------------------------------------------------------------------------
1468 gxsys_stl::map<gxsys_stl::string, MethodInstance> OtherMethods;
1469 gxsys_stl::map<gxsys_stl::string, MethodInstance> StaticMethods;
1470 gxsys_stl::map<gxsys_stl::string, MethodInstance> VirtualMethods;
1471 gxsys_stl::map<gxsys_stl::string, MethodInstance> WrappedMethods;
1472 gxsys_stl::map<gxsys_stl::string, MethodInstance> WrappedEnums; // in this case all MethodInstance.Method members are null
1473 
1474 
1475 //----------------------------------------------------------------------------
1477 {
1478  OtherMethods.clear();
1479  StaticMethods.clear();
1480  VirtualMethods.clear();
1481  WrappedMethods.clear();
1482  WrappedEnums.clear();
1483 
1484  // Pretend that "System.Object" is in our inheritance chain and that its
1485  // virtual method signatures exist in our lookup map:
1486  //
1487 // VirtualMethods.insert(gxsys_stl::make_pair("Equals(object)", MethodInstance(0, 0)));
1488 // VirtualMethods.insert(gxsys_stl::make_pair("Finalize()", MethodInstance(0, 0)));
1489 // VirtualMethods.insert(gxsys_stl::make_pair("GetHashCode()", MethodInstance(0, 0)));
1490 // VirtualMethods.insert(gxsys_stl::make_pair("GetType()", MethodInstance(0, 0)));
1491 // VirtualMethods.insert(gxsys_stl::make_pair("MemberwiseClone()", MethodInstance(0, 0)));
1492 // VirtualMethods.insert(gxsys_stl::make_pair("Object()", MethodInstance(0, 0)));
1493 // VirtualMethods.insert(gxsys_stl::make_pair("ToString()", MethodInstance(0, 0)));
1494 }
1495 
1496 
1497 //----------------------------------------------------------------------------
1498 void MummyCsharpGenerator::AddLookupEntries(const cable::Class* c)
1499 {
1500  if (c)
1501  {
1502  const cable::Class *parent = GetWrappableParentClass(c);
1503 
1504  if (parent)
1505  {
1506  AddLookupEntries(parent);
1507  }
1508 
1509  for(cable::Context::Iterator it = c->Begin(); it != c->End(); ++it)
1510  {
1511  cable::Method *m = cable::Method::SafeDownCast(*it);
1512 
1513  if (m && MethodIsWrappable(m, it.GetAccess()))
1514  {
1515  if (m->GetVirtual())
1516  {
1517  VirtualMethods.insert(gxsys_stl::make_pair(GetMethodSignature(c, m), MethodInstance(c, m)));
1518  }
1519  else if (m->GetStatic())
1520  {
1521  StaticMethods.insert(gxsys_stl::make_pair(GetMethodSignature(c, m), MethodInstance(c, m)));
1522  }
1523  else
1524  {
1525  OtherMethods.insert(gxsys_stl::make_pair(GetMethodSignature(c, m), MethodInstance(c, m)));
1526  }
1527  }
1528 
1529  if (!m)
1530  {
1531  cable::Enumeration *e = cable::Enumeration::SafeDownCast(*it);
1532 
1533  if (e && (cable::Context::Public == it.GetAccess()))
1534  {
1535  WrappedEnums.insert(gxsys_stl::make_pair(GetWrappedEnumName(e), MethodInstance(c, 0)));
1536  }
1537  }
1538  }
1539  }
1540 }
1541 
1542 
1543 //----------------------------------------------------------------------------
1545 {
1546  gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it;
1547 
1548  LogInfo(mi_Info, << "<DumpLookupEntries>");
1549  LogInfo(mi_Info, << "inherited static methods:");
1550  for (it= StaticMethods.begin(); it!=StaticMethods.end(); ++it)
1551  {
1552  LogInfo(mi_Info, << " " << it->first);
1553  }
1554 
1555  LogInfo(mi_Info, << "inherited virtual methods:");
1556  for (it= VirtualMethods.begin(); it!=VirtualMethods.end(); ++it)
1557  {
1558  LogInfo(mi_Info, << " " << it->first);
1559  }
1560 
1561  LogInfo(mi_Info, << "inherited other methods:");
1562  for (it= OtherMethods.begin(); it!=OtherMethods.end(); ++it)
1563  {
1564  LogInfo(mi_Info, << " " << it->first);
1565  }
1566 
1567  LogInfo(mi_Info, << "wrapped methods:");
1568  for (it= WrappedMethods.begin(); it!=WrappedMethods.end(); ++it)
1569  {
1570  LogInfo(mi_Info, << " " << it->first);
1571  }
1572 
1573  LogInfo(mi_Info, << "wrapped enums:");
1574  for (it= WrappedEnums.begin(); it!=WrappedEnums.end(); ++it)
1575  {
1576  LogInfo(mi_Info, << " " << it->first);
1577  }
1578 
1579  LogInfo(mi_Info, << "</DumpLookupEntries>");
1580 }
1581 
1582 
1583 //----------------------------------------------------------------------------
1584 bool MummyCsharpGenerator::OtherMethodRedefined(const gxsys_stl::string &signature)
1585 {
1586  gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it =
1587  OtherMethods.find(signature);
1588  return it != OtherMethods.end();
1589 }
1590 
1591 
1592 //----------------------------------------------------------------------------
1593 bool MummyCsharpGenerator::StaticMethodRedefined(const gxsys_stl::string &signature)
1594 {
1595  gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it =
1596  StaticMethods.find(signature);
1597  return it != StaticMethods.end();
1598 }
1599 
1600 
1601 //----------------------------------------------------------------------------
1602 bool MummyCsharpGenerator::VirtualMethodOverridden(const gxsys_stl::string &signature)
1603 {
1604  gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it =
1605  VirtualMethods.find(signature);
1606  return it != VirtualMethods.end();
1607 }
1608 
1609 
1610 //----------------------------------------------------------------------------
1611 bool MummyCsharpGenerator::WrappedMethodExists(const gxsys_stl::string &signature)
1612 {
1613  gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it =
1614  WrappedMethods.find(signature);
1615  return it != WrappedMethods.end();
1616 }
1617 
1618 
1619 //----------------------------------------------------------------------------
1620 bool MummyCsharpGenerator::WrappedEnumExists(const gxsys_stl::string &name)
1621 {
1622  gxsys_stl::map<gxsys_stl::string, MethodInstance>::iterator it =
1623  WrappedEnums.find(name);
1624  return it != WrappedEnums.end();
1625 }
1626 
1627 
1628 //----------------------------------------------------------------------------
1629 bool MummyCsharpGenerator::IsFactoryMethod(const cable::Class *c, const cable::Method *m)
1630 {
1631  if (m->GetStatic() &&
1632  0 == m->GetFunctionType()->GetNumberOfArguments() &&
1633  gxsys_stl::string(m->GetName()) == this->GetSettings()->GetFactoryMethod(c))
1634  {
1635  return true;
1636  }
1637 
1638  return false;
1639 }
1640 
1641 
1642 //----------------------------------------------------------------------------
1643 bool MummyCsharpGenerator::IsDisposalMethod(const cable::Class *c, const cable::Method *m)
1644 {
1645  if (m->GetVirtual() &&
1646  0 == m->GetFunctionType()->GetNumberOfArguments() &&
1647  gxsys_stl::string(m->GetName()) == this->GetSettings()->GetDisposalMethod(c))
1648  {
1649  return true;
1650  }
1651 
1652  return false;
1653 }
1654 
1655 
1656 //----------------------------------------------------------------------------
1657 bool MummyCsharpGenerator::MethodReturnValueIsCounted(const cable::Class *c, const cable::Method *m)
1658 {
1659  if (this->IsFactoryMethod(c, m))
1660  {
1661  return true;
1662  }
1663 
1664  if (HasAttribute(m, "gccxml(iwhCounted)"))
1665  {
1666  return true;
1667  }
1668 
1669  gxsys_stl::string countedMethodsRegex(this->GetSettings()->GetCountedMethodsRegex(c));
1670  if (!countedMethodsRegex.empty())
1671  {
1672  gxsys::RegularExpression re;
1673  re.compile(countedMethodsRegex.c_str());
1674  if (re.find(m->GetName()))
1675  {
1677  << "MethodReturnValueIsCounted match:" << gxsys_ios::endl
1678  << " countedMethodsRegex: " << countedMethodsRegex << gxsys_ios::endl
1679  << " method: " << c->GetName() << "::" << m->GetName()
1680  );
1681  return true;
1682  }
1683  }
1684 
1685  return false;
1686 }
1687 
1688 
1689 //----------------------------------------------------------------------------
1690 gxsys_stl::string MummyCsharpGenerator::GetExportLayerFunctionName(const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname)
1691 {
1692  gxsys_stl::string s(GetFullyQualifiedName(c, "_"));
1693  s += "_";
1694  s += mname;
1695 
1696  if (this->IsFactoryMethod(c, m) || this->IsDisposalMethod(c, m) || mname == "new" || mname == "delete")
1697  {
1698  // No suffix...
1699  }
1700  else
1701  {
1702  // Append a unique-fying suffix...
1703  char idStr[32];
1704  unsigned int methodId = 0;
1705 
1706  gxsys_stl::map<const cable::Method*, unsigned int>::iterator it = this->MethodIdMap.find(m);
1707  if (it != this->MethodIdMap.end())
1708  {
1709  methodId = it->second;
1710  }
1711  else
1712  {
1713  // Any methods passed in to here should have been inserted into the
1714  // MethodIdMap during a previous call to GatherWrappedMethods...
1715  // What happened...!?!?
1716  //
1717  LogError(me_InternalError, << "Could not find method in MethodIdMap.");
1718  }
1719 
1720  sprintf(idStr, "%02u", methodId);
1721  s += "_";
1722  s += idStr;
1723  }
1724 
1725  return s;
1726 }
1727 
1728 
1729 //----------------------------------------------------------------------------
1730 //
1731 // GetMethodSignature is very similar to EmitCSharpMethodDeclaration.
1732 // Changes in either may need to be made in both places...
1733 //
1734 void MummyCsharpGenerator::EmitCSharpMethodDeclaration(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, bool asProperty, bool useArg0AsReturn, const gxsys_stl::string& accessLevel)
1735 {
1736  gxsys_stl::string signature(GetMethodSignature(c, m));
1737 
1738  gxsys_stl::string arraySize;
1739  gxsys_stl::string s;
1740  cable::FunctionType *ft = m->GetFunctionType();
1741  unsigned int cArgs = ft->GetNumberOfArguments();
1742  unsigned int i = 0;
1743  cable::Type *argType = 0;
1744  cable::Type *retType = ft->GetReturns();
1745 
1746  i = RETURN_VALUE;
1747 
1748  // If emitting a declaration based on a "property set" method,
1749  // the type of the first argument to the set method is the type
1750  // of the C# property... typically retType will be "void" when
1751  // this is the case...
1752  //
1753  if (asProperty && useArg0AsReturn)
1754  {
1755  if (!IsVoid(retType))
1756  {
1757  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropSetReturnsNonVoid,
1758  "Method transformed to a property 'set' returns non-void. The return value will be ignored in generated code.");
1759  }
1760 
1761  if (cArgs!=1)
1762  {
1763  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropSetUnexpectedArgCount,
1764  "Unexpected number of arguments for method transformed to a property 'set' - cArgs: " << cArgs);
1765  }
1766 
1767  // :-)
1768  //
1769  // Pretend return type and attributes come from arg0 for the
1770  // rest of this method call:
1771  //
1772  if (cArgs!=0)
1773  {
1774  i = 0;
1775  retType = ft->GetArgument(0);
1776  }
1777  }
1778 
1779  // Do attributes indicate an array?
1780  //
1781  arraySize = GetMethodArgumentArraySize(c, m, ft, i);
1782 
1783 
1784  // Public, protected, private, internal, hmmmm...?
1785  //
1786  Emit(os, accessLevel.c_str());
1787  Emit(os, " ");
1788 
1789 
1790  if (m->GetStatic())
1791  {
1792  // C# static == C++ static:
1793  //
1794  if (StaticMethodRedefined(signature))
1795  {
1796  Emit(os, "new ");
1797  }
1798 
1799  Emit(os, "static ");
1800  }
1801 
1802  if (!asProperty)
1803  {
1804  if (m->GetVirtual())
1805  {
1806  // C# : "virtual" or "override" ?
1807  //
1808  if (VirtualMethodOverridden(signature))
1809  {
1810  Emit(os, "override ");
1811  }
1812  else
1813  {
1814  // If I am virtual, but my parent is not then:
1815  //
1816  if (OtherMethodRedefined(signature))
1817  {
1818  Emit(os, "new ");
1819  }
1820 
1821  Emit(os, "virtual ");
1822  }
1823  }
1824  else
1825  {
1826  if (OtherMethodRedefined(signature))
1827  {
1828  Emit(os, "new ");
1829  }
1830  }
1831  }
1832 
1833  // Return type. (Has special transformations for supporting collections
1834  // and enumerators. Method name + class supports target interface ==
1835  // special generated code...)
1836  //
1837  gxsys_stl::string mname = m->GetName();
1838 
1839  if ((mname == "GetEnumerator") &&
1840  this->HasTargetInterface("IEnumerable"))
1841  {
1842  Emit(os, "System.Collections.IEnumerator");
1843  }
1844  else if ((mname == "GetCurrent") &&
1845  this->HasTargetInterface("IEnumerator"))
1846  {
1847  Emit(os, "object");
1848  }
1849  else
1850  {
1851  Emit(os, GetCSharpTypeString(retType, true, arraySize != "").c_str());
1852  if (arraySize != "")
1853  {
1854  Emit(os, "[]");
1855  }
1856  }
1857 
1858  Emit(os, " ");
1859 
1860  // Use the wrapped method name or the property name:
1861  //
1862  s = GetWrappedMethodName(m);
1863  if (asProperty)
1864  {
1865  s = ExtractDerivedName(s.c_str(), m, this->GetSettings()->GetVerbose());
1866  }
1867 
1868  Emit(os, s.c_str());
1869 
1870  if (!asProperty)
1871  {
1872  // Open args:
1873  Emit(os, "(");
1874 
1875  // The C# args:
1876  for (i= 0; i<cArgs; ++i)
1877  {
1878  // If it's a CxxMain param pair, only declare the 2nd (string[] argv) part
1879  // of the pair... So, do nothing here and skip the 1st (int argc) part...
1880  //
1881  if (IsCxxMainStyleParamPair(ft, i))
1882  {
1883  }
1884  else
1885  {
1886  argType = ft->GetArgument(i);
1887 
1888  // Is arg an array?
1889  //
1890  arraySize = GetMethodArgumentArraySize(c, m, ft, i);
1891 
1892  // arg type:
1893  Emit(os, GetCSharpTypeString(argType, false, arraySize != "").c_str());
1894 
1895  // array notation:
1896  if (arraySize != "")
1897  {
1898  Emit(os, "[]");
1899  }
1900 
1901  // arg name:
1902  Emit(os, " ");
1903  Emit(os, GetArgName(ft, i));
1904 
1905  if (i<cArgs-1)
1906  {
1907  Emit(os, ", ");
1908  }
1909  }
1910  }
1911 
1912  // Close args:
1913  Emit(os, ")");
1914  }
1915 }
1916 
1917 
1918 //----------------------------------------------------------------------------
1919 void MummyCsharpGenerator::EmitCSharpDllImportDeclaration(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, const char *f, bool emitExceptionParams)
1920 {
1921  gxsys_stl::string arraySize;
1922  cable::FunctionType *ft = m->GetFunctionType();
1923  unsigned int cArgs = ft->GetNumberOfArguments();
1924  unsigned int cArgsEmitted = 0;
1925  unsigned int i = 0;
1926  cable::Type *argType = 0;
1927  cable::Type *retType = ft->GetReturns();
1928 
1929  Emit(os, "[DllImport(");
1930  Emit(os, dllname);
1931  Emit(os, ", EntryPoint = \"");
1932  Emit(os, f);
1933  Emit(os, "\")]");
1934  Emit(os, "\n");
1935 
1936  // Does method return an array?
1937  //
1938  arraySize = GetMethodArgumentArraySize(c, m, ft, RETURN_VALUE);
1939 
1940  EmitIndent(os);
1941  Emit(os, "internal static extern ");
1942 
1943  if (mname == "new")
1944  {
1945  Emit(os, "IntPtr ");
1946  Emit(os, f);
1947  Emit(os, "(ref uint mteStatus, ref uint mteIndex, ref uint rawRefCount");
1948  cArgsEmitted += 3;
1949 
1950  if (emitExceptionParams)
1951  {
1952  Emit(os, ", ref uint mteExceptionIndex, ref IntPtr clonedException");
1953  cArgsEmitted += 2;
1954  }
1955 
1956  Emit(os, ");");
1957  }
1958  else if (mname == "delete")
1959  {
1960  Emit(os, "void ");
1961  Emit(os, f);
1962  Emit(os, "(HandleRef pThis");
1963  cArgsEmitted += 1;
1964 
1965  if (emitExceptionParams)
1966  {
1967  Emit(os, ", ref uint mteExceptionIndex, ref IntPtr clonedException");
1968  cArgsEmitted += 2;
1969  }
1970 
1971  Emit(os, ");");
1972  }
1973  else
1974  {
1975  Emit(os, GetPInvokeTypeString(retType, true, arraySize != "", false).c_str());
1976  Emit(os, " ");
1977  Emit(os, f);
1978  Emit(os, "(");
1979 
1980  if (!m->GetStatic())
1981  {
1982  Emit(os, "HandleRef pThis");
1983  cArgsEmitted += 1;
1984 
1985  if (cArgs!=0)
1986  {
1987  Emit(os, ", ");
1988  }
1989  }
1990 
1991  for (i= 0; i<cArgs; ++i)
1992  {
1993  argType = ft->GetArgument(i);
1994 
1995  // Is arg an array?
1996  //
1997  arraySize = GetMethodArgumentArraySize(c, m, ft, i);
1998 
1999  // array MarshalAs directive:
2000  if (arraySize != "")
2001  {
2002  Emit(os, "[MarshalAs(UnmanagedType.LPArray, SizeConst = ");
2003  Emit(os, arraySize.c_str());
2004  Emit(os, ")] ");
2005  }
2006 
2007  // arg type:
2008  Emit(os, GetPInvokeTypeString(argType, false, arraySize != "", false).c_str());
2009 
2010  // array notation:
2011  if (arraySize != "")
2012  {
2013  Emit(os, "[]");
2014  }
2015 
2016  // arg name:
2017  Emit(os, " ");
2018  Emit(os, GetArgName(ft, i));
2019 
2020  cArgsEmitted += 1;
2021 
2022  if (i<cArgs-1)
2023  {
2024  Emit(os, ", ");
2025  }
2026  }
2027 
2028  // Add "generated args" to method signatures that return object pointers:
2029  //
2030  if (!HasMapToType(retType) && IsObjectPointer(retType))
2031  {
2032  if (cArgsEmitted)
2033  {
2034  Emit(os, ", ");
2035  }
2036 
2037  Emit(os, "ref uint mteStatus, ref uint mteIndex, ref uint rawRefCount");
2038  cArgsEmitted += 3;
2039  }
2040 
2041  // And to those that handle wrapped exceptions:
2042  //
2043  if (emitExceptionParams)
2044  {
2045  if (cArgsEmitted)
2046  {
2047  Emit(os, ", ");
2048  }
2049 
2050  Emit(os, "ref uint mteExceptionIndex, ref IntPtr clonedException");
2051  cArgsEmitted += 2;
2052  }
2053 
2054  // Close args:
2055  //
2056  Emit(os, ");");
2057  }
2058 }
2059 
2060 
2061 //----------------------------------------------------------------------------
2062 gxsys_stl::string GetQualifiedEventName(const cable::Method *m)
2063 {
2064  const cable::Class *c = cable::ClassType::SafeDownCast(
2065  cable::PointerType::SafeDownCast(
2066  m->GetFunctionType()->GetReturns()
2067  )->GetTarget())->GetClass();
2068 
2069  gxsys_stl::string eventName;
2070 
2071  if (c && c->GetContext())
2072  {
2073  eventName = c->GetContext()->GetName();
2074  eventName += GetWrappedClassName(c);
2075  }
2076  else
2077  {
2078  eventName = "ERROR_invalid_input_to_GetQualifiedEventName";
2079  LogError(me_InvalidArg, << eventName.c_str());
2080  }
2081 
2082  return eventName;
2083 }
2084 
2085 
2086 //----------------------------------------------------------------------------
2087 gxsys_stl::string GetEventName(const cable::Method *m)
2088 {
2089  gxsys_stl::string eventName = GetWrappedClassName(
2090  cable::ClassType::SafeDownCast(cable::PointerType::SafeDownCast(
2091  m->GetFunctionType()->GetReturns()
2092  )->GetTarget())->GetClass()
2093  );
2094 
2095  return eventName;
2096 }
2097 
2098 
2099 //----------------------------------------------------------------------------
2100 void MummyCsharpGenerator::EmitCSharpEvent(gxsys_ios::ostream& os, const char *, const cable::Class* c, const cable::Method* m, const gxsys_stl::string& eventName)
2101 {
2102  // Caller provides eventName because caller is the one with the knowledge
2103  // about whether there are multiple events with the same unqualified name
2104  // due to classes with the same name existing in multiple namespaces.
2105  // So, if there are not, eventName will be from "GetEventName", but if
2106  // there are, eventName will be from "GetQualifiedEventName"...
2107  //
2108  gxsys_stl::string e(eventName);
2109  gxsys_stl::string eFull;
2110  gxsys_stl::string mname(m->GetName());
2111 
2112  // An "event method" is expected to return a pointer to the event class
2113  // that it is supposed to wrap... If that's not true, the code generated
2114  // by this following block is likely not to compile! So make sure it's
2115  // true in your sources to be wrapped.
2116  //
2117  cable::FunctionType *ft = m->GetFunctionType();
2118  cable::Type *retType = ft->GetReturns();
2119 
2120  if (retType->GetTypeId() != cable::Type::PointerTypeId)
2121  {
2122  LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_EventMethodIncorrectReturnType,
2123  "iwhEvent method '" << mname << "' does not return a pointer to an event object");
2124  return;
2125  }
2126 
2127  if (cable::PointerType::SafeDownCast(retType)->GetTarget()->GetTypeId() !=
2128  cable::Type::ClassTypeId)
2129  {
2130  LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_EventMethodIncorrectReturnType,
2131  "iwhEvent method '" << mname << "' does not return a pointer to an event object");
2132  return;
2133  }
2134 
2135  eFull = GetWrappedClassNameFullyQualified(cable::ClassType::SafeDownCast(
2136  cable::PointerType::SafeDownCast(retType)->GetTarget())->GetClass());
2137 
2138  // Assumptions:
2139  //
2140  // (These could all be codified and made into non-assumptions, but for now
2141  // they all *are* assumptions...)
2142  //
2143  // There's a type called "Handler" in the Event class (typedef to a function pointer in unmanaged C++)
2144  // The typedef signature is "void blah(object sender, object args)"
2145  // There's a corresponding EventArgs class named the same but with "EventArgs" at the end
2146  // There's an AddHandler method in the Event class
2147  // There's a RemoveHandler method in the Event class
2148  // The handler is id'able by a C# "uint"
2149 
2150  // Make this next section collapsible inside a "region":
2151  //
2152  EmitIndent(os);
2153  Emit(os, "#region ");
2154  Emit(os, e.c_str());
2155  Emit(os, " event implementation details\n");
2156  Emit(os, "\n");
2157 
2158  // A data member (*Impl) to hold the managed listeners:
2159  //
2160  EmitIndent(os);
2161  Emit(os, "private ");
2162  Emit(os, e.c_str());
2163  Emit(os, "EventHandler ");
2164  Emit(os, e.c_str());
2165  Emit(os, "Impl;\n");
2166 
2167  // A data member (*Instance) to cache the managed wrapper of the unmanaged
2168  // event object:
2169  //
2170  EmitIndent(os);
2171  Emit(os, "private ");
2172  Emit(os, eFull.c_str());
2173  Emit(os, " ");
2174  Emit(os, e.c_str());
2175  Emit(os, "Instance;\n");
2176 
2177  // A data member (*RelayHandler) and an id (*RelayHandlerId) for the handler
2178  // when we are actively connected...
2179  //
2180  EmitIndent(os);
2181  Emit(os, "private ");
2182  Emit(os, eFull.c_str());
2183  Emit(os, ".Handler ");
2184  Emit(os, e.c_str());
2185  Emit(os, "RelayHandler;\n");
2186  EmitIndent(os);
2187  Emit(os, "private uint ");
2188  Emit(os, e.c_str());
2189  Emit(os, "RelayHandlerId;\n");
2190  Emit(os, "\n");
2191 
2192  // A listener to receive events from the unmanaged code and relay them on to
2193  // managed listeners. Conforms to event's "unmanaged" delegate signature.
2194  // (The delegate named "Handler" in the event class itself.) One improvement
2195  // we could make here would be to generate RelayHandler's signature based
2196  // on the actual signature of "Handler."
2197  //
2198  EmitIndent(os);
2199  Emit(os, "private void ");
2200  Emit(os, e.c_str());
2201  Emit(os, "RelayHandlerMethod(IntPtr rawSender, IntPtr rawArgs)\n");
2202  EmitIndent(os);
2203  Emit(os, "{\n");
2204  EmitIndent(os, 2);
2205  Emit(os, "if (this.");
2206  Emit(os, e.c_str());
2207  Emit(os, "Impl != null)\n");
2208  EmitIndent(os, 2);
2209  Emit(os, "{\n");
2210  EmitIndent(os, 3);
2211  Emit(os, eFull.c_str());
2212  Emit(os, "EventArgs rv = null;\n");
2213  EmitIndent(os, 3);
2214  Emit(os, "if (IntPtr.Zero != rawArgs)\n");
2215  EmitIndent(os, 3);
2216  Emit(os, "{\n");
2217 
2218 
2219 
2220 
2221  const cable::Class* cRetType = cable::ClassType::SafeDownCast(
2222  cable::PointerType::SafeDownCast(retType)->GetTarget()
2223  )->GetClass();
2224 
2225  gxsys_stl::string registerMethod = this->GetSettings()->GetRegisterMethod(cRetType);
2226  gxsys_stl::string unRegisterMethod = this->GetSettings()->GetUnRegisterMethod(cRetType);
2227 
2228 
2229 
2230 
2231  // Technique #1 : using "new" (and ignoring potential issues with
2232  // the mummy Runtime table...
2233  //
2234  EmitIndent(os, 4);
2235  Emit(os, "rv = new ");
2236  Emit(os, eFull.c_str());
2237  Emit(os, "EventArgs(rawArgs, ");
2238 
2239  if (!registerMethod.empty())
2240  {
2241  Emit(os, "true");
2242  }
2243  else
2244  {
2245  Emit(os, "false");
2246  }
2247 
2248  Emit(os, ", false);\n");
2249 
2250  if (!registerMethod.empty())
2251  {
2252  EmitIndent(os, 4);
2253  Emit(os, "rv.");
2254  Emit(os, registerMethod.c_str());
2255  Emit(os, ";\n");
2256  }
2257 
2258 
2259 
2260 
2261  // Technique #2 : using "CreateWrappedObject" (and forcing a call
2262  // back across the boundary to "Register" the EventArgs if the wrapper
2263  // was just created...)
2264  //
2265  // This imposes an additional assumption/constraint on Event and EventArgs
2266  // classes. They must share Register/UnRegister methods for this to work
2267  // properly...
2268  //
2269  // Either that, or we need to get a "cable::Class*" to the EventArgs class
2270  // somehow (which we may or may not be able to do depending on how the
2271  // gccxml step and the input header files were crafted...)
2272  //
2273  //unsigned int indent = 3;
2274  //EmitIndent(os, indent+1);
2275  //Emit(os, "bool mteCreated;\n");
2276  //EmitIndent(os, indent+1);
2277  //Emit(os, "rv = (");
2278  //Emit(os, eFull.c_str());
2279  //Emit(os, "EventArgs)\n");
2280  //EmitIndent(os, indent+2);
2281  //Emit(os, "Kitware.mummy.Runtime.Methods.CreateWrappedObject(\n");
2282  //EmitIndent(os, indent+3);
2283  //Emit(os, "\"class ");
2284  //Emit(os, eFull.c_str());
2285  //Emit(os, "EventArgs\", rawArgs, ");
2286 
2287  //if (!unRegisterMethod.empty())
2288  // {
2289  // Emit(os, "true");
2290  // }
2291  //else
2292  // {
2293  // Emit(os, "false");
2294  // }
2295 
2296  //Emit(os, ", out mteCreated");
2297  //Emit(os, ");\n");
2298 
2299  //if (!registerMethod.empty())
2300  // {
2301  // //if (this->MethodReturnValueIsCounted(c, m))
2302  // // {
2303  // // EmitIndent(os, indent+1);
2304  // // Emit(os, "Returned object is counted already, (factory method or iwhCounted hint),\n");
2305  // // EmitIndent(os, indent+1);
2306  // // Emit(os, "// no 'rv.");
2307  // // Emit(os, registerMethod.c_str());
2308  // // Emit(os, "' call is necessary...\n");
2309  // // }
2310  // //else
2311  // // {
2312  // EmitIndent(os, indent+1);
2313  // Emit(os, "if (mteCreated)\n");
2314  // EmitIndent(os, indent+1);
2315  // Emit(os, "{\n");
2316  // EmitIndent(os, indent+2);
2317  // Emit(os, "rv.");
2318  // Emit(os, registerMethod.c_str());
2319  // Emit(os, ";\n");
2320  // EmitIndent(os, indent+1);
2321  // Emit(os, "}\n");
2322  // // }
2323  // }
2324 
2325 
2326 
2327 
2328  EmitIndent(os, 3);
2329  Emit(os, "}\n");
2330  EmitIndent(os, 3);
2331  Emit(os, "this.");
2332  Emit(os, e.c_str());
2333  Emit(os, "Impl(this, rv);\n");
2334  EmitIndent(os, 2);
2335  Emit(os, "}\n");
2336  EmitIndent(os);
2337  Emit(os, "}\n");
2338  Emit(os, "\n");
2339 
2340  // Methods to add and remove the RelayHandler:
2341  //
2342  EmitIndent(os);
2343  Emit(os, "private void Add");
2344  Emit(os, e.c_str());
2345  Emit(os, "RelayHandler()\n");
2346  EmitIndent(os);
2347  Emit(os, "{\n");
2348  EmitIndent(os, 2);
2349  Emit(os, "if (0 == this.");
2350  Emit(os, e.c_str());
2351  Emit(os, "RelayHandlerId)\n");
2352  EmitIndent(os, 2);
2353  Emit(os, "{\n");
2354 
2355  EmitIndent(os, 3);
2356  Emit(os, "this.");
2357  Emit(os, e.c_str());
2358  Emit(os, "RelayHandler =\n");
2359  EmitIndent(os, 4);
2360  Emit(os, "new ");
2361  Emit(os, eFull.c_str());
2362  Emit(os, ".Handler(\n");
2363  EmitIndent(os, 5);
2364  Emit(os, "this.");
2365  Emit(os, e.c_str());
2366  Emit(os, "RelayHandlerMethod);\n");
2367  Emit(os, "\n");
2368 
2369  EmitIndent(os, 3);
2370  Emit(os, "this.");
2371  Emit(os, e.c_str());
2372  Emit(os, "Instance =\n");
2373  EmitIndent(os, 4);
2374  Emit(os, "this.");
2375  Emit(os, mname.c_str());
2376  Emit(os, "();\n");
2377  Emit(os, "\n");
2378 
2379  EmitIndent(os, 3);
2380  Emit(os, "this.");
2381  Emit(os, e.c_str());
2382  Emit(os, "RelayHandlerId =\n");
2383  EmitIndent(os, 4);
2384  Emit(os, "this.");
2385  Emit(os, e.c_str());
2386  Emit(os, "Instance.AddHandler(\n");
2387  EmitIndent(os, 5);
2388  Emit(os, "this.");
2389  Emit(os, e.c_str());
2390  Emit(os, "RelayHandler);\n");
2391 
2392  EmitIndent(os, 2);
2393  Emit(os, "}\n");
2394  EmitIndent(os);
2395  Emit(os, "}\n");
2396  Emit(os, "\n");
2397 
2398  EmitIndent(os);
2399  Emit(os, "private void Remove");
2400  Emit(os, e.c_str());
2401  Emit(os, "RelayHandler()\n");
2402  EmitIndent(os);
2403  Emit(os, "{\n");
2404  EmitIndent(os, 2);
2405  Emit(os, "if (0 != this.");
2406  Emit(os, e.c_str());
2407  Emit(os, "RelayHandlerId)\n");
2408  EmitIndent(os, 2);
2409  Emit(os, "{\n");
2410 
2411  EmitIndent(os, 3);
2412  Emit(os, "if (System.IntPtr.Zero != this.");
2413  Emit(os, e.c_str());
2414  Emit(os, "Instance.GetCppThis().Handle)\n");
2415  EmitIndent(os, 3);
2416  Emit(os, "{\n");
2417  EmitIndent(os, 4);
2418  Emit(os, "this.");
2419  Emit(os, e.c_str());
2420  Emit(os, "Instance.RemoveHandler(\n");
2421  EmitIndent(os, 5);
2422  Emit(os, "this.");
2423  Emit(os, e.c_str());
2424  Emit(os, "RelayHandlerId);\n");
2425  EmitIndent(os, 3);
2426  Emit(os, "}\n");
2427  Emit(os, "\n");
2428 
2429  EmitIndent(os, 3);
2430  Emit(os, "this.");
2431  Emit(os, e.c_str());
2432  Emit(os, "Instance = null;\n");
2433 
2434  EmitIndent(os, 3);
2435  Emit(os, "this.");
2436  Emit(os, e.c_str());
2437  Emit(os, "RelayHandler = null;\n");
2438 
2439  EmitIndent(os, 3);
2440  Emit(os, "this.");
2441  Emit(os, e.c_str());
2442  Emit(os, "RelayHandlerId = 0;\n");
2443 
2444  EmitIndent(os, 2);
2445  Emit(os, "}\n");
2446  EmitIndent(os);
2447  Emit(os, "}\n");
2448  Emit(os, "\n");
2449 
2450  // End the private details "region":
2451  //
2452  EmitIndent(os);
2453  Emit(os, "#endregion\n");
2454  Emit(os, "\n");
2455  Emit(os, "\n");
2456 
2457  // A delegate definition that managed C# handlers must conform to in order
2458  // to listen to this event:
2459  //
2460  EmitIndent(os);
2461  Emit(os, "/// <summary>\n");
2462  EmitIndent(os);
2463  Emit(os, "/// Delegate signature for the ");
2464  Emit(os, e.c_str());
2465  Emit(os, " event.\n");
2466  EmitIndent(os);
2467  Emit(os, "/// </summary>\n");
2468  EmitIndent(os);
2469  Emit(os, "public delegate void ");
2470  Emit(os, e.c_str());
2471  Emit(os, "EventHandler(");
2472  Emit(os, c->GetName());
2473  Emit(os, " sender, ");
2474  Emit(os, eFull.c_str());
2475  Emit(os, "EventArgs args);\n");
2476  Emit(os, "\n");
2477  Emit(os, "\n");
2478 
2479  // Documentation:
2480  gxsys_stl::vector<gxsys_stl::string> docblock;
2481  this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber);
2482  EmitDocumentationBlock(os, docblock, 1);
2483 
2484  // The actual event with add and remove handlers.
2485  //
2486  EmitIndent(os);
2487  Emit(os, "public event ");
2488  Emit(os, e.c_str());
2489  Emit(os, "EventHandler ");
2490  Emit(os, e.c_str());
2491  Emit(os, "\n");
2492 
2493  EmitIndent(os);
2494  Emit(os, "{\n");
2495 
2496  EmitIndent(os, 2);
2497  Emit(os, "add\n");
2498  EmitIndent(os, 2);
2499  Emit(os, "{\n");
2500  EmitIndent(os, 3);
2501  Emit(os, "if (this.");
2502  Emit(os, e.c_str());
2503  Emit(os, "Impl == null)\n");
2504  EmitIndent(os, 3);
2505  Emit(os, "{\n");
2506  EmitIndent(os, 4);
2507  Emit(os, "Add");
2508  Emit(os, e.c_str());
2509  Emit(os, "RelayHandler();\n");
2510  EmitIndent(os, 3);
2511  Emit(os, "}\n");
2512  Emit(os, "\n");
2513  EmitIndent(os, 3);
2514  Emit(os, "this.");
2515  Emit(os, e.c_str());
2516  Emit(os, "Impl += value;\n");
2517  EmitIndent(os, 2);
2518  Emit(os, "}\n");
2519  Emit(os, "\n");
2520 
2521  EmitIndent(os, 2);
2522  Emit(os, "remove\n");
2523  EmitIndent(os, 2);
2524  Emit(os, "{\n");
2525  EmitIndent(os, 3);
2526  Emit(os, "this.");
2527  Emit(os, e.c_str());
2528  Emit(os, "Impl -= value;\n");
2529  Emit(os, "\n");
2530  EmitIndent(os, 3);
2531  Emit(os, "if (this.");
2532  Emit(os, e.c_str());
2533  Emit(os, "Impl == null)\n");
2534  EmitIndent(os, 3);
2535  Emit(os, "{\n");
2536  EmitIndent(os, 4);
2537  Emit(os, "Remove");
2538  Emit(os, e.c_str());
2539  Emit(os, "RelayHandler();\n");
2540  EmitIndent(os, 3);
2541  Emit(os, "}\n");
2542  EmitIndent(os, 2);
2543  Emit(os, "}\n");
2544 
2545  EmitIndent(os);
2546  Emit(os, "}\n");
2547 }
2548 
2549 
2550 //----------------------------------------------------------------------------
2551 void MummyCsharpGenerator::EmitCSharpProperty(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *propGetMethod, const cable::Method *propSetMethod, bool emitExceptionParams)
2552 {
2553  gxsys_stl::string fGet;
2554  gxsys_stl::string fSet;
2555  unsigned int indent = 3;
2556  const cable::Method *declMethod = propGetMethod;
2557 
2558  // Declare the DllImport functions.
2559  //
2560  if (propGetMethod)
2561  {
2562  fGet = GetExportLayerFunctionName(c, propGetMethod, propGetMethod->GetName());
2563  EmitIndent(os);
2564  EmitCSharpDllImportDeclaration(os, dllname, c, propGetMethod, propGetMethod->GetName(), fGet.c_str(), emitExceptionParams);
2565  Emit(os, "\n");
2566  Emit(os, "\n");
2567  }
2568 
2569  if (propSetMethod)
2570  {
2571  fSet = GetExportLayerFunctionName(c, propSetMethod, propSetMethod->GetName());
2572  EmitIndent(os);
2573  EmitCSharpDllImportDeclaration(os, dllname, c, propSetMethod, propSetMethod->GetName(), fSet.c_str(), emitExceptionParams);
2574  Emit(os, "\n");
2575  Emit(os, "\n");
2576 
2577  if (!declMethod)
2578  {
2579  declMethod = propSetMethod;
2580  }
2581  }
2582 
2583  if (!declMethod)
2584  {
2585  // What? no propGetMethod or propSetMethod? Caller has made a mistake somewhere...
2586  //
2587  LogError(me_InternalError, << "No declMethod in MummyCsharpGenerator::EmitCSharpProperty.");
2588  return;
2589  }
2590 
2591  // Documentation:
2592  gxsys_stl::vector<gxsys_stl::string> docblock;
2593  this->GetHeaderFileReader(c)->GetCommentBlockBefore(declMethod->GetLine(), docblock, this->ClassLineNumber);
2594  EmitDocumentationBlock(os, docblock, 1);
2595 
2596  // Declaration:
2597  EmitIndent(os);
2598  EmitCSharpMethodDeclaration(os, c, declMethod, true, declMethod == propSetMethod, "public");
2599  Emit(os, "\n");
2600 
2601  // Open body:
2602  EmitIndent(os);
2603  Emit(os, "{");
2604  Emit(os, "\n");
2605 
2606  // The "get" body:
2607  if (propGetMethod)
2608  {
2609  EmitIndent(os, 2);
2610  Emit(os, "get\n");
2611  EmitIndent(os, 2);
2612  Emit(os, "{\n");
2613  EmitIndent(os, 3);
2614  Emit(os, "// iwhPropGet\n");
2615  EmitCSharpMethodBody(os, 3, c, propGetMethod, fGet, 0, emitExceptionParams);
2616  indent = 3;
2617  EmitIndent(os, 2);
2618  Emit(os, "}\n");
2619  }
2620 
2621  // The "set" body:
2622  if (propSetMethod)
2623  {
2624  if (propGetMethod)
2625  {
2626  Emit(os, "\n");
2627  }
2628 
2629  EmitIndent(os, 2);
2630  Emit(os, "set\n");
2631  EmitIndent(os, 2);
2632  Emit(os, "{\n");
2633  EmitIndent(os, 3);
2634  Emit(os, "// iwhPropSet\n");
2635  EmitCSharpMethodBody(os, 3, c, propSetMethod, fSet, "value", emitExceptionParams);
2636  indent = 3;
2637  EmitIndent(os, 2);
2638  Emit(os, "}\n");
2639  }
2640 
2641  // Close body:
2642  EmitIndent(os);
2643  Emit(os, "}");
2644  Emit(os, "\n");
2645 }
2646 
2647 
2648 //----------------------------------------------------------------------------
2649 void EmitThrowClonedException(gxsys_ios::ostream &os, unsigned int indent)
2650 {
2651  EmitIndent(os, indent);
2652  Emit(os, "if (IntPtr.Zero != clonedException)\n");
2653  EmitIndent(os, indent);
2654  Emit(os, "{\n");
2655 
2656  EmitIndent(os, indent+1);
2657  Emit(os, "bool mteCreatedException;\n");
2658  EmitIndent(os, indent+1);
2659  Emit(os, "System.Exception wrappedException = (System.Exception)\n");
2660  EmitIndent(os, indent+2);
2661  Emit(os, "Kitware.mummy.Runtime.Methods.CreateWrappedObject(\n");
2662  EmitIndent(os, indent+3);
2663  Emit(os, "0, mteExceptionIndex, 0, clonedException, true, out mteCreatedException);\n");
2664  EmitIndent(os, indent+1);
2665  Emit(os, "throw wrappedException;\n");
2666 
2667  //EmitIndent(os, indent+1);
2668  //Emit(os, "System.Exception exc = new System.Exception(\"received clonedException from unmanaged layer...\");\n");
2669  //EmitIndent(os, indent+1);
2670  //Emit(os, "throw exc;\n");
2671 
2672  EmitIndent(os, indent);
2673  Emit(os, "}\n");
2674 }
2675 
2676 
2677 //----------------------------------------------------------------------------
2678 void MummyCsharpGenerator::EmitCSharpMethodBody(gxsys_ios::ostream &os, unsigned int indent, const cable::Class *c, const cable::Method *m, gxsys_stl::string& f, const char *impliedArg0, bool emitExceptionParams)
2679 {
2680  // need qualified name?
2681  gxsys_stl::string cname(c->GetName());
2682 
2683  gxsys_stl::string retArraySize;
2684  gxsys_stl::string argArraySize;
2685  cable::FunctionType *ft = m->GetFunctionType();
2686  unsigned int cArgs = ft->GetNumberOfArguments();
2687  unsigned int cArgsEmitted = 0;
2688  unsigned int i = 0;
2689  cable::Type *argType = 0;
2690  cable::Type *retType = ft->GetReturns();
2691  bool voidReturn = false;
2692  gxsys_stl::string rvType;
2693  gxsys_stl::string rvpType;
2694  bool argIsRef = false;
2695  gxsys_stl::string argTypeString;
2696  gxsys_stl::string emittedArg;
2697  bool callGetCppThis = false;
2698 
2699  // Does method return anything?
2700  //
2701  if (IsVoid(retType))
2702  {
2703  voidReturn = true;
2704  }
2705 
2706  // Does method return an array?
2707  //
2708  retArraySize = GetMethodArgumentArraySize(c, m, ft, RETURN_VALUE);
2709 
2710  rvpType = GetPInvokeTypeString(retType, true, retArraySize != "", false);
2711  rvType = GetCSharpTypeString(retType, true, retArraySize != "");
2712 
2713 
2714  // Body:
2715  //
2716 
2717 
2718  // Set up to handle wrapped exceptions if this class may throw them:
2719  //
2720  if (emitExceptionParams)
2721  {
2722  EmitIndent(os, indent);
2723  Emit(os, "uint mteExceptionIndex = 0;\n");
2724  EmitIndent(os, indent);
2725  Emit(os, "IntPtr clonedException = IntPtr.Zero;\n");
2726  Emit(os, "\n");
2727  }
2728 
2729  // Delegate the call through the PInvoke/DllImport layer:
2730  //
2731  EmitIndent(os, indent);
2732 
2733  if (!voidReturn)
2734  {
2735  if (retArraySize != "")
2736  {
2737  Emit(os, rvpType.c_str());
2738  Emit(os, " rvp = "); // rvp == return value pointer
2739  }
2740  else if (IsObjectPointer(retType))
2741  {
2742  Emit(os, rvType.c_str());
2743  Emit(os, " rv = null;\n");
2744 
2745  Emit(os, "\n");
2746 
2747  EmitIndent(os, indent);
2748  Emit(os, "uint mteStatus = 0;\n");
2749  EmitIndent(os, indent);
2750  Emit(os, "uint mteIndex = UInt32.MaxValue;\n");
2751  EmitIndent(os, indent);
2752  Emit(os, "uint rawRefCount = 0;\n");
2753 
2754  EmitIndent(os, indent);
2755  Emit(os, rvpType.c_str());
2756  Emit(os, " rvp = "); // rvp == return value pointer
2757  }
2758  else
2759  {
2760  Emit(os, rvType.c_str());
2761  Emit(os, " rv = "); // rv == return value
2762  }
2763  }
2764 
2765  // Open any special marshalling blocks required:
2766  //
2767  if (IsCharPointer(retType))
2768  {
2769  Emit(os, "Marshal.PtrToStringAnsi(");
2770  }
2771 
2772  // Call the DllImport function:
2773  //
2774  Emit(os, f.c_str());
2775  Emit(os, "(");
2776 
2777  // Arguments, 'this' first, then loop over C++ method formal params:
2778  //
2779  if (!m->GetStatic())
2780  {
2781  Emit(os, "this.GetCppThis()");
2782  cArgsEmitted += 1;
2783 
2784  if (cArgs!=0)
2785  {
2786  Emit(os, ", ");
2787  }
2788  }
2789 
2790  for (i= 0; i<cArgs; ++i)
2791  {
2792  // If it's a CxxMain param pair, use the length of the 2nd (string[] argv)
2793  // part as the value of the 1st (int argc) part...
2794  //
2795  if (IsCxxMainStyleParamPair(ft, i))
2796  {
2797  Emit(os, GetArgName(ft, i+1));
2798  Emit(os, ".Length");
2799  }
2800  else
2801  {
2802  argType = ft->GetArgument(i);
2803 
2804  // Is arg an array?
2805  //
2806  argArraySize = GetMethodArgumentArraySize(c, m, ft, i);
2807 
2808  argIsRef = false;
2809  if (argArraySize == "" && GetIsRefArg(argType))
2810  {
2811  argIsRef = true;
2812  Emit(os, "ref ");
2813  }
2814 
2815  argTypeString = GetCSharpTypeString(argType, true, argArraySize != "");
2816  if (!argIsRef && (argTypeString == "bool"))
2817  {
2818  Emit(os, "(byte)(");
2819  }
2820 
2821  if (impliedArg0 && 0==i)
2822  {
2823  emittedArg = impliedArg0;
2824  }
2825  else
2826  {
2827  emittedArg = GetArgName(ft, i);
2828  }
2829 
2830  Emit(os, emittedArg.c_str());
2831 
2832  if (argIsRef)
2833  {
2835  << "reference arg: "
2836  << cname << "." << m->GetName()
2837  << " " << argType->GetCxxType().GetName() << " " << emittedArg
2838  << " (arg " << i << ")"
2839  );
2840  }
2841 
2842  callGetCppThis = false;
2843 
2844  if (IsObjectPointer(argType))
2845  {
2846  const cable::Class* argClass = cable::ClassType::SafeDownCast(
2847  cable::PointerType::SafeDownCast(argType)->GetTarget())->GetClass();
2848  if (!IsUtilityClass(argClass))
2849  {
2850  callGetCppThis = true;
2851  }
2852  }
2853  else if (IsObjectPointerReference(argType))
2854  {
2855  const cable::PointerType* ptrClass = cable::PointerType::SafeDownCast(
2856  cable::ReferenceType::SafeDownCast(argType)->GetTarget());
2857  const cable::Class* argClass = cable::ClassType::SafeDownCast(
2858  ptrClass->GetTarget())->GetClass();
2859  if (!IsUtilityClass(argClass))
2860  {
2861  callGetCppThis = true;
2862  }
2863  }
2864 
2865  if (callGetCppThis)
2866  {
2867  Emit(os, " == null ? new HandleRef() : ");
2868  Emit(os, emittedArg.c_str());
2869  Emit(os, ".GetCppThis()");
2870  }
2871 
2872  if (!argIsRef && (argTypeString == "bool"))
2873  {
2874  Emit(os, " ? 1 : 0)");
2875  }
2876  }
2877 
2878  cArgsEmitted += 1;
2879 
2880  if (i<cArgs-1)
2881  {
2882  Emit(os, ", ");
2883  }
2884  }
2885 
2886  if (IsObjectPointer(retType))
2887  {
2888  if (cArgsEmitted)
2889  {
2890  Emit(os, ", ");
2891  }
2892 
2893  Emit(os, "ref mteStatus, ref mteIndex, ref rawRefCount");
2894  cArgsEmitted += 3;
2895  }
2896 
2897  if (emitExceptionParams)
2898  {
2899  if (cArgsEmitted)
2900  {
2901  Emit(os, ", ");
2902  }
2903 
2904  Emit(os, "ref mteExceptionIndex, ref clonedException");
2905  cArgsEmitted += 2;
2906  }
2907 
2908  Emit(os, ")");
2909 
2910  // Close special marshalling for object casting or char * to string mapping
2911  // or handle bool/byte specially for PInvoke:
2912  //
2913  if (IsObjectPointer(retType))
2914  {
2915  const cable::Class* cRetType = cable::ClassType::SafeDownCast(
2916  cable::PointerType::SafeDownCast(retType)->GetTarget()
2917  )->GetClass();
2918 
2919  gxsys_stl::string registerMethod = this->GetSettings()->GetRegisterMethod(cRetType);
2920  gxsys_stl::string unRegisterMethod = this->GetSettings()->GetUnRegisterMethod(cRetType);
2921 
2922  Emit(os, ";\n");
2923 
2924  EmitIndent(os, indent);
2925  Emit(os, "if (IntPtr.Zero != rvp)\n");
2926  EmitIndent(os, indent);
2927  Emit(os, "{\n");
2928 
2929  EmitIndent(os, indent+1);
2930  Emit(os, "bool mteCreated;\n");
2931  EmitIndent(os, indent+1);
2932  Emit(os, "rv = (");
2933  Emit(os, rvType.c_str());
2934  Emit(os, ")\n");
2935  EmitIndent(os, indent+2);
2936  Emit(os, "Kitware.mummy.Runtime.Methods.CreateWrappedObject(\n");
2937  EmitIndent(os, indent+3);
2938  Emit(os, "mteStatus, mteIndex, rawRefCount, rvp, ");
2939 
2940  if (!unRegisterMethod.empty())
2941  {
2942  Emit(os, "true");
2943  }
2944  else
2945  {
2946  Emit(os, "false");
2947  }
2948 
2949  Emit(os, ", out mteCreated");
2950  Emit(os, ");\n");
2951 
2952  if (!registerMethod.empty())
2953  {
2954  if (this->MethodReturnValueIsCounted(c, m))
2955  {
2956  EmitIndent(os, indent+1);
2957  Emit(os, "// Returned object is counted already, (factory method or iwhCounted hint),\n");
2958  EmitIndent(os, indent+1);
2959  Emit(os, "// no 'rv.");
2960  Emit(os, registerMethod.c_str());
2961  Emit(os, "' call is necessary...\n");
2962  }
2963  else
2964  {
2965  EmitIndent(os, indent+1);
2966  Emit(os, "if (mteCreated)\n");
2967  EmitIndent(os, indent+1);
2968  Emit(os, "{\n");
2969  EmitIndent(os, indent+2);
2970  Emit(os, "rv.");
2971  Emit(os, registerMethod.c_str());
2972  Emit(os, ";\n");
2973  EmitIndent(os, indent+1);
2974  Emit(os, "}\n");
2975  }
2976  }
2977 
2978  EmitIndent(os, indent);
2979  Emit(os, "}\n");
2980 
2981  Emit(os, "\n");
2982  }
2983  else if (IsCharPointer(retType))
2984  {
2985  Emit(os, ");\n");
2986  }
2987  else if (rvType == "bool")
2988  {
2989  Emit(os, " == 0 ? false : true;\n");
2990  }
2991  else
2992  {
2993  Emit(os, ";\n");
2994  }
2995 
2996 
2997  if (emitExceptionParams)
2998  {
2999  Emit(os, "\n");
3000  EmitThrowClonedException(os, indent);
3001  Emit(os, "\n");
3002  }
3003 
3004 
3005  // Specially marshal array return values:
3006  if (retArraySize != "")
3007  {
3008  EmitIndent(os, indent);
3009  Emit(os, rvType.c_str());
3010  Emit(os, "[] rv = null;");
3011  Emit(os, "\n");
3012 
3013  EmitIndent(os, indent);
3014  Emit(os, "if (IntPtr.Zero != rvp)");
3015  Emit(os, "\n");
3016  EmitIndent(os, indent);
3017  Emit(os, "{");
3018  Emit(os, "\n");
3019  EmitIndent(os, indent+1);
3020  Emit(os, "rv = new ");
3021  Emit(os, rvType.c_str());
3022  Emit(os, "[");
3023  Emit(os, retArraySize.c_str());
3024  Emit(os, "];");
3025  Emit(os, "\n");
3026 
3027  // Special case "uint" since Marshal.Copy does not have
3028  // a "uint" overload...
3029  //
3030  if (rvType == "uint")
3031  {
3032  EmitIndent(os, indent+1);
3033  Emit(os, "int[] rv2 = new int[");
3034  Emit(os, retArraySize.c_str());
3035  Emit(os, "];");
3036  Emit(os, "\n");
3037 
3038  EmitIndent(os, indent+1);
3039  Emit(os, "Marshal.Copy(rvp, rv2, 0, rv.Length);");
3040  Emit(os, "\n");
3041 
3042  EmitIndent(os, indent+1);
3043  Emit(os, "for (int rv2i = 0; rv2i < ");
3044  Emit(os, retArraySize.c_str());
3045  Emit(os, "; ++rv2i)");
3046  Emit(os, "\n");
3047 
3048  EmitIndent(os, indent+1);
3049  Emit(os, "{");
3050  Emit(os, "\n");
3051 
3052  EmitIndent(os, indent+2);
3053  Emit(os, "rv[rv2i] = (uint)rv2[rv2i];");
3054  Emit(os, "\n");
3055 
3056  EmitIndent(os, indent+1);
3057  Emit(os, "}");
3058  Emit(os, "\n");
3059  }
3060  else
3061  {
3062  EmitIndent(os, indent+1);
3063  Emit(os, "Marshal.Copy(rvp, rv, 0, rv.Length);");
3064  Emit(os, "\n");
3065  }
3066 
3067  EmitIndent(os, indent);
3068  Emit(os, "}");
3069  Emit(os, "\n");
3070  }
3071 
3072  // Return statement:
3073  if (!voidReturn)
3074  {
3075  EmitIndent(os, indent);
3076  Emit(os, "return rv;");
3077  Emit(os, "\n");
3078  }
3079 }
3080 
3081 
3082 //----------------------------------------------------------------------------
3083 void MummyCsharpGenerator::EmitCSharpMethod(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, const gxsys_stl::string& accessLevel, bool emitExceptionParams)
3084 {
3085  gxsys_stl::string f(GetExportLayerFunctionName(c, m, mname));
3086 
3087  // First declare the DllImport function. This gets called within the method body.
3088  //
3089  EmitIndent(os);
3090  EmitCSharpDllImportDeclaration(os, dllname, c, m, mname, f.c_str(), emitExceptionParams);
3091  Emit(os, "\n");
3092  Emit(os, "\n");
3093 
3094  // Documentation:
3095  gxsys_stl::vector<gxsys_stl::string> docblock;
3096  this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber);
3097  EmitDocumentationBlock(os, docblock, 1);
3098 
3099  // Declaration:
3100  EmitIndent(os);
3101  EmitCSharpMethodDeclaration(os, c, m, false, false, accessLevel);
3102  Emit(os, "\n");
3103 
3104  // Open body:
3105  EmitIndent(os);
3106  Emit(os, "{");
3107  Emit(os, "\n");
3108 
3109  // Body:
3110  EmitCSharpMethodBody(os, 2, c, m, f, 0, emitExceptionParams);
3111 
3112  // Close body:
3113  EmitIndent(os);
3114  Emit(os, "}");
3115  Emit(os, "\n");
3116 }
3117 
3118 
3119 //----------------------------------------------------------------------------
3120 void MummyCsharpGenerator::EmitCSharpEnums(gxsys_ios::ostream &os, const cable::Class *c)
3121 {
3122  gxsys_stl::vector<gxsys_stl::string> docblock;
3123 
3124  for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it)
3125  {
3126  cable::Enumeration *e = cable::Enumeration::SafeDownCast(*it);
3127 
3128  if (e && (cable::Context::Public == it.GetAccess()))
3129  {
3130  gxsys_stl::string ename(GetWrappedEnumName(e));
3131 
3132  LogVerboseInfo(<< "public enum - wrapped name: " << ename);
3133 
3134  Emit(os, "\n");
3135  Emit(os, "\n");
3136 
3137  docblock.clear();
3138  this->GetHeaderFileReader(c)->GetCommentBlockBefore(e->GetLine(), docblock, this->ClassLineNumber);
3139  EmitDocumentationBlock(os, docblock, 1);
3140 
3141  EmitIndent(os);
3142  Emit(os, "public ");
3143  if (WrappedEnumExists(ename))
3144  {
3145  Emit(os, "new ");
3146  }
3147  Emit(os, "enum ");
3148  Emit(os, ename.c_str());
3149  Emit(os, "\n");
3150 
3151  EmitIndent(os);
3152  Emit(os, "{\n");
3153 
3154  for (cable::Enumeration::Iterator eit = e->Begin(); eit != e->End(); ++eit)
3155  {
3156  EmitIndent(os, 2);
3157  Emit(os, "/// <summary>enum member</summary>\n");
3158 
3159  EmitIndent(os, 2);
3160  Emit(os, *eit);
3161  Emit(os, " = ");
3162  EmitInt(os, eit.GetValue());
3163  Emit(os, ",");
3164  Emit(os, "\n");
3165 
3166  Emit(os, "\n");
3167  }
3168 
3169  EmitIndent(os);
3170  Emit(os, "}\n");
3171  }
3172  }
3173 }
3174 
3175 
3176 //----------------------------------------------------------------------------
3177 void MummyCsharpGenerator::EmitCSharpConstructor(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams)
3178 {
3179  // need qualified name?
3180  gxsys_stl::string cname(c->GetName());
3181  gxsys_stl::string f;
3182 
3183  if (this->GetSettings()->GetUseShadow(c))
3184  {
3185  // Special case shadow class factory method since m might be NULL
3186  // (like it *is* with vtkCommand...)
3187  //
3188  f = cname + "Shadow_CreateShadow";
3189 
3190  EmitIndent(os);
3191  Emit(os, "[DllImport(");
3192  Emit(os, dllname);
3193  Emit(os, ", EntryPoint = \"");
3194  Emit(os, f.c_str());
3195  Emit(os, "\")]");
3196  Emit(os, "\n");
3197 
3198  EmitIndent(os);
3199  Emit(os, "static extern IntPtr ");
3200  Emit(os, f.c_str());
3201  Emit(os, "(IntPtr primary);\n");
3202 
3203  Emit(os, "\n");
3204 
3205  // Documentation:
3206  gxsys_stl::vector<gxsys_stl::string> docblock;
3208  (m ? m->GetLine() : c->GetLine()), docblock, this->ClassLineNumber);
3209  EmitDocumentationBlock(os, docblock, 1);
3210 
3211  EmitIndent(os);
3212  Emit(os, "public ");
3213  Emit(os, cname.c_str());
3214  Emit(os, "() : this(IntPtr.Zero, false, false)\n");
3215 
3216  EmitIndent(os);
3217  Emit(os, "{\n");
3218 
3219  EmitIndent(os, 2);
3220  Emit(os, "IntPtr primary = Marshal.GetIDispatchForObject(this);\n");
3221 
3222  EmitIndent(os, 2);
3223  Emit(os, "this.SetCppThis(");
3224  Emit(os, f.c_str());
3225  Emit(os, "(primary), true, false);\n");
3226 
3227  EmitIndent(os, 2);
3228  Emit(os, "Marshal.Release(primary);\n");
3229 
3230  EmitIndent(os);
3231  Emit(os, "}\n");
3232  }
3233  else
3234  {
3235  f = GetExportLayerFunctionName(c, m, mname);
3236 
3237  // Explanation of the "emitDefaultFactoryMethod" MummySettings.xml attribute.
3238  // ==========================================================================
3239  //
3240  // Either: emit the factory method itself, including the DllImport declaration,
3241  // and then emit the default C# constructor, too, which gives two ways to get an
3242  // instance of an object of class c...
3243  // (emitDefaultFactoryMethod="true" in MummySettings.xml)
3244  //
3245  // Or: emit just the DllImport declaration and the default C# constructor and
3246  // *skip* emitting the factory method itself, which only gives one way to get an
3247  // instance of class c.
3248  // (emitDefaultFactoryMethod="false" in or absent from MummySettings.xml)
3249  //
3250  // We code for both ways because we have some clients who want abstract C# classes
3251  // to be really abstract and *uncreatable* (even via a separate factory method) at
3252  // this class level. Only concrete subclasses can even be instantiated.
3253  //
3254  // On the other hand, we also have clients (think VTK and its ubiquitous New method)
3255  // that want the factory method behavior specifically so that abstract class instances
3256  // *can* be created, even though behind the scenes a concrete subclass of the factory
3257  // method's choice is the thing actually being instantiated.
3258  //
3259  if (this->GetSettings()->GetEmitDefaultFactoryMethod(c))
3260  {
3261  EmitCSharpMethod(os, dllname, c, m, mname, "public", emitExceptionParams);
3262  }
3263  else
3264  {
3265  EmitIndent(os);
3266  EmitCSharpDllImportDeclaration(os, dllname, c, m, mname, f.c_str(), emitExceptionParams);
3267  }
3268 
3269  Emit(os, "\n");
3270  Emit(os, "\n");
3271 
3272  // Documentation:
3273  gxsys_stl::vector<gxsys_stl::string> docblock;
3274  this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber);
3275  EmitDocumentationBlock(os, docblock, 1);
3276 
3277  EmitIndent(os);
3278  Emit(os, "public ");
3279  Emit(os, cname.c_str());
3280  Emit(os, "()\n");
3281  EmitIndent(os, 2);
3282  Emit(os, ": base(IntPtr.Zero, false, false)\n");
3283 
3284  EmitIndent(os);
3285  Emit(os, "{\n");
3286 
3287  EmitIndent(os, 2);
3288  Emit(os, "// mummy generated default C# constructor\n");
3289  EmitIndent(os, 2);
3290  Emit(os, "uint mteStatus = 0;\n");
3291  EmitIndent(os, 2);
3292  Emit(os, "uint mteIndex = UInt32.MaxValue;\n");
3293  EmitIndent(os, 2);
3294  Emit(os, "uint rawRefCount = 0;\n");
3295  Emit(os, "\n");
3296 
3297  if (emitExceptionParams)
3298  {
3299  EmitIndent(os, 2);
3300  Emit(os, "uint mteExceptionIndex = UInt32.MaxValue;\n");
3301  EmitIndent(os, 2);
3302  Emit(os, "IntPtr clonedException = IntPtr.Zero;\n");
3303  Emit(os, "\n");
3304  }
3305 
3306  EmitIndent(os, 2);
3307  Emit(os, "IntPtr rawCppThis = ");
3308  Emit(os, f.c_str());
3309  Emit(os, "(ref mteStatus, ref mteIndex, ref rawRefCount");
3310 
3311  if (emitExceptionParams)
3312  {
3313  Emit(os, ", ref mteExceptionIndex, ref clonedException");
3314  }
3315 
3316  Emit(os, ");\n");
3317 
3318  if (emitExceptionParams)
3319  {
3320  Emit(os, "\n");
3321  EmitThrowClonedException(os, 2);
3322  Emit(os, "\n");
3323  }
3324 
3325  EmitIndent(os, 2);
3326  Emit(os, "this.SetCppThis(rawCppThis, true, (0==mteStatus || rawRefCount<2 ? false : true));\n");
3327 
3328  EmitIndent(os);
3329  Emit(os, "}\n");
3330  }
3331 }
3332 
3333 
3334 //----------------------------------------------------------------------------
3335 void MummyCsharpGenerator::EmitCSharpRegister(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams)
3336 {
3337  EmitCSharpMethod(os, dllname, c, m, mname, "public", emitExceptionParams);
3338 }
3339 
3340 
3341 //----------------------------------------------------------------------------
3342 void MummyCsharpGenerator::EmitCSharpDispose(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, const unsigned int eventCount, bool emitExceptionParams)
3343 {
3344  cable::FunctionType *ft = 0;
3345  cable::Type *argType = 0;
3346  unsigned int cArgs = 0;
3347  unsigned int i = 0;
3348  gxsys_stl::string f;
3349 
3350  if (m)
3351  {
3352  ft = m->GetFunctionType();
3353  cArgs = ft->GetNumberOfArguments();
3354 
3355  // need qualified name?
3356  f = GetExportLayerFunctionName(c, m, mname);
3357 
3358  EmitIndent(os);
3359  EmitCSharpDllImportDeclaration(os, dllname, c, m, mname, f.c_str(), emitExceptionParams);
3360  Emit(os, "\n");
3361  Emit(os, "\n");
3362 
3363  // Documentation:
3364  gxsys_stl::vector<gxsys_stl::string> docblock;
3365  this->GetHeaderFileReader(c)->GetCommentBlockBefore(m->GetLine(), docblock, this->ClassLineNumber);
3366  EmitDocumentationBlock(os, docblock, 1);
3367  }
3368  else
3369  {
3370  EmitIndent(os);
3371  Emit(os, "/// <summary>\n");
3372  EmitIndent(os);
3373  Emit(os, "/// Automatically generated protected Dispose method - called from\n");
3374  EmitIndent(os);
3375  Emit(os, "/// public Dispose or the C# destructor. DO NOT call directly.\n");
3376  EmitIndent(os);
3377  Emit(os, "/// </summary>\n");
3378  }
3379 
3380 
3381  EmitIndent(os);
3382  Emit(os, "protected override void Dispose(bool disposing)\n");
3383  EmitIndent(os);
3384  Emit(os, "{\n");
3385 
3386 
3387  // If we are going to emit any code other than "base.Dispose(disposing);"
3388  // then make sure it is wrapped in a try/finally block so that we still call
3389  // base.Dispose if one of these other bits of code we're calling throws
3390  // an exception...
3391  //
3392  bool openedTryFinally = false;
3393  unsigned int indent = 2;
3394  if ((0 != eventCount) || m)
3395  {
3396  openedTryFinally = true;
3397  indent = 3;
3398 
3399  EmitIndent(os, indent-1);
3400  Emit(os, "try\n");
3401  EmitIndent(os, indent-1);
3402  Emit(os, "{\n");
3403  }
3404 
3405 
3406  if (0 != eventCount)
3407  {
3408  EmitIndent(os, indent);
3409  Emit(os, "this.RemoveAllRelayHandlers();\n");
3410  }
3411 
3412  if (m)
3413  {
3414  EmitIndent(os, indent);
3415  Emit(os, "if (this.GetCallDisposalMethod())\n");
3416  EmitIndent(os, indent);
3417  Emit(os, "{\n");
3418 
3419  if (emitExceptionParams)
3420  {
3421  EmitIndent(os, indent+1);
3422  Emit(os, "uint mteExceptionIndex = 0;\n");
3423  EmitIndent(os, indent+1);
3424  Emit(os, "IntPtr clonedException = IntPtr.Zero;\n");
3425  Emit(os, "\n");
3426  }
3427 
3428  EmitIndent(os, indent+1);
3429  Emit(os, f.c_str());
3430  Emit(os, "(this.GetCppThis()");
3431 
3432  for (i = 0; i<cArgs; ++i)
3433  {
3434  argType = ft->GetArgument(i);
3435 
3436  if (IsObjectPointer(argType))
3437  {
3438  Emit(os, ", new HandleRef()");
3439  }
3440  else if (IsVoidPointer(argType))
3441  {
3442  Emit(os, ", System.IntPtr.Zero");
3443  }
3444  else
3445  {
3446  Emit(os, ", 0");
3447  }
3448  }
3449 
3450  if (emitExceptionParams)
3451  {
3452  Emit(os, ", ref mteExceptionIndex, ref clonedException");
3453  }
3454 
3455  Emit(os, ");\n");
3456  EmitIndent(os, indent+1);
3457  Emit(os, "this.ClearCppThis();\n");
3458 
3459  if (emitExceptionParams)
3460  {
3461  Emit(os, "\n");
3462  EmitThrowClonedException(os, indent+1);
3463  }
3464 
3465  EmitIndent(os, indent);
3466  Emit(os, "}\n");
3467  Emit(os, "\n");
3468  }
3469 
3470  if (openedTryFinally)
3471  {
3472  EmitIndent(os, indent-1);
3473  Emit(os, "}\n");
3474  EmitIndent(os, indent-1);
3475  Emit(os, "finally\n");
3476  EmitIndent(os, indent-1);
3477  Emit(os, "{\n");
3478  }
3479 
3480  EmitIndent(os, indent);
3481  Emit(os, "base.Dispose(disposing);\n");
3482 
3483  if (openedTryFinally)
3484  {
3485  EmitIndent(os, indent-1);
3486  Emit(os, "}\n");
3487  }
3488 
3489  EmitIndent(os);
3490  Emit(os, "}\n");
3491 }
3492 
3493 
3494 //----------------------------------------------------------------------------
3496 {
3497  bool operator()(const cable::Field* f1, const cable::Field* f2)
3498  {
3499  return f1->GetOffset() < f2->GetOffset();
3500  }
3501 };
3502 
3503 
3504 //----------------------------------------------------------------------------
3505 void MummyCsharpGenerator::EmitCSharpWrapperClassAsStruct(gxsys_ios::ostream &os, const cable::Class *c)
3506 {
3507  gxsys_stl::vector<cable::Field*> fields;
3508  gxsys_stl::vector<cable::Field*>::iterator fit;
3509  gxsys_stl::string derivedName;
3510  gxsys_stl::string fieldType;
3511  gxsys_stl::vector<gxsys_stl::string> docblock;
3512  bool isPartial = this->GetSettings()->GetPartialClass(c);
3513  bool fieldAccess = !HasAttribute(c, "gccxml(iwhNoFieldAccess)");
3514 
3515  // First iterate and collect all the fields in a local vector:
3516  //
3517  for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it)
3518  {
3519  cable::Field* f = cable::Field::SafeDownCast(*it);
3520  if (f)
3521  {
3522  fields.push_back(f);
3523  }
3524  }
3525 
3526  // Sort the vector so that we can emit the fields in the same order
3527  // in which they appear in the original C++ struct/class:
3528  //
3529  gxsys_stl::sort(fields.begin(), fields.end(), SortByFieldOffset());
3530 
3531  // Emit class opening:
3532  //
3533  Emit(os, "public ");
3534  if (isPartial)
3535  {
3536  Emit(os, "partial ");
3537  }
3538  Emit(os, "struct ");
3539  Emit(os, GetWrappedClassName(c).c_str());
3540  Emit(os, "\n");
3541  Emit(os, "{\n");
3542 
3543  // Enums:
3544  //
3545  EmitCSharpEnums(os, c);
3546 
3547  // Now iterate and emit a private data member for each field:
3548  //
3549  for (fit = fields.begin(); fit != fields.end(); ++fit)
3550  {
3551  cable::Field* f = *fit;
3552  if (f)
3553  {
3554  derivedName = ExtractDerivedName(f->GetName(), f, this->GetSettings()->GetVerbose());
3555  fieldType = GetCSharpTypeString(f->GetType(), false, false);
3556 
3557  // "bool" is special - help it marshal properly to a C++ bool struct
3558  // data member...
3559  //
3560  // Using C# bool here causes an InteropServices.MarshalDirectiveException
3561  // with a message that says the type cannot be marshalled via PInvoke.
3562  // So we use C# byte instead and make it look like a bool through the
3563  // public accessors emitted in the next step.
3564  //
3565  if (fieldType == "bool")
3566  {
3567  fieldType = "byte";
3568  }
3569 
3570  EmitIndent(os);
3571  Emit(os, "private ");
3572  Emit(os, fieldType.c_str());
3573  Emit(os, " m_");
3574  Emit(os, derivedName.c_str());
3575  Emit(os, ";");
3576  Emit(os, "\n");
3577  }
3578  }
3579 
3580  // Iterate and emit public accessors for each private data member:
3581  //
3582  for (fit = fields.begin(); fieldAccess && fit != fields.end(); ++fit)
3583  {
3584  cable::Field* f = *fit;
3585  if (f)
3586  {
3587  derivedName = ExtractDerivedName(f->GetName(), f, false);
3588  fieldType = GetCSharpTypeString(f->GetType(), false, false);
3589 
3590  Emit(os, "\n");
3591 
3592  this->GetHeaderFileReader(c)->GetCommentBlockBefore(f->GetLine(), docblock, this->ClassLineNumber);
3593  EmitDocumentationBlock(os, docblock, 1);
3594  docblock.clear();
3595 
3596  EmitIndent(os);
3597  Emit(os, "public ");
3598  Emit(os, fieldType.c_str());
3599  Emit(os, " ");
3600  Emit(os, derivedName.c_str());
3601  Emit(os, "\n");
3602 
3603  EmitIndent(os);
3604  Emit(os, "{");
3605  Emit(os, "\n");
3606 
3607  EmitIndent(os, 2);
3608  Emit(os, "get\n");
3609 
3610  EmitIndent(os, 2);
3611  Emit(os, "{\n");
3612 
3613  EmitIndent(os, 3);
3614  Emit(os, "return this.m_");
3615  Emit(os, derivedName.c_str());
3616  if (fieldType == "bool")
3617  {
3618  // "bool" is special -- see above comments...
3619  //
3620  Emit(os, " == 0 ? false : true");
3621  }
3622  Emit(os, ";\n");
3623 
3624  EmitIndent(os, 2);
3625  Emit(os, "}\n");
3626 
3627  Emit(os, "\n");
3628 
3629  EmitIndent(os, 2);
3630  Emit(os, "set\n");
3631 
3632  EmitIndent(os, 2);
3633  Emit(os, "{\n");
3634 
3635  EmitIndent(os, 3);
3636  Emit(os, "this.m_");
3637  Emit(os, derivedName.c_str());
3638  Emit(os, " = ");
3639  if (fieldType == "bool")
3640  {
3641  // "bool" is special -- see above comments...
3642  //
3643  Emit(os, "(byte)(value ? 1 : 0)");
3644  }
3645  else
3646  {
3647  Emit(os, "value");
3648  }
3649  Emit(os, ";\n");
3650 
3651  EmitIndent(os, 2);
3652  Emit(os, "}\n");
3653 
3654  EmitIndent(os);
3655  Emit(os, "}");
3656  Emit(os, "\n");
3657  }
3658  }
3659 
3660  // Caller emits closing brace for struct so that he can emit
3661  // extraCSharpCode if necessary before the closing brace...
3662 }
3663 
3664 
3665 //----------------------------------------------------------------------------
3667  const cable::Class *c,
3668  gxsys_stl::vector<cable::Method*>& wrapped_methods,
3669  cable::Method*& factoryM,
3670  cable::Method*& disposalM,
3671  cable::Method*& registerM,
3672  cable::Method*& unRegisterM,
3673  bool includeParentMethods
3674  )
3675 {
3676  // When recursion hits the top of the class hierarchy, we're done:
3677  //
3678  if (!c)
3679  {
3680  return;
3681  }
3682 
3683  gxsys_stl::string factoryMethod(this->GetSettings()->GetFactoryMethod(c));
3684  gxsys_stl::string disposalMethod(this->GetSettings()->GetDisposalMethod(c));
3685  gxsys_stl::string registerMethod(this->GetSettings()->GetRegisterMethod(c));
3686  gxsys_stl::string unRegisterMethod(this->GetSettings()->GetUnRegisterMethod(c));
3687 
3688  // Reset state only if we are iterating the methods of the *target* class.
3689  // (And only track factory method if iterating the target class...)
3690  //
3691  if (c == this->GetTargetClass())
3692  {
3693  this->CurrentMethodId = 0;
3694  this->MethodIdMap.clear();
3695  WrappedMethods.clear();
3696  wrapped_methods.clear();
3697  factoryM = 0;
3698  disposalM = 0;
3699  registerM = 0;
3700  unRegisterM = 0;
3701  }
3702 
3703  // If including parents, do so first so that the list of methods is in
3704  // "superclass first" order... And so that tracked pointers get set
3705  // to the most derived override possible.
3706  //
3707  if (includeParentMethods)
3708  {
3709  this->GatherWrappedMethods(GetWrappableParentClass(c), wrapped_methods,
3710  factoryM, disposalM, registerM, unRegisterM, true);
3711  }
3712 
3713  // Iterate class c's methods, adding wrappable ones to wrapped_methods and
3714  // tracking "special" methods as we encounter them:
3715  //
3716  for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it)
3717  {
3718  cable::Method *m = cable::Method::SafeDownCast(*it);
3719 
3720  if (m && MethodIsWrappable(m, it.GetAccess()))
3721  {
3722  gxsys_stl::string signature(GetMethodSignature(c, m));
3723 
3724  if ((c == this->GetTargetClass()) && signature == factoryMethod + "()")
3725  {
3726  LogVerboseInfo(<< "Found factory method, signature: " << signature);
3727  factoryM = m;
3728  this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId));
3729  }
3730  else if (signature == disposalMethod + "()")
3731  {
3732  LogVerboseInfo(<< "Found disposal method, signature: " << signature);
3733  disposalM = m;
3734  this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId));
3735  }
3736  else if (gxsys::SystemTools::StringStartsWith(registerMethod.c_str(),
3737  (gxsys_stl::string(m->GetName())+"(").c_str()))
3738  {
3739  LogVerboseInfo(<< "Found register method, signature: " << signature);
3740  registerM = m;
3741  this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId));
3742  }
3743  else if (gxsys::SystemTools::StringStartsWith(unRegisterMethod.c_str(),
3744  (gxsys_stl::string(m->GetName())+"(").c_str()))
3745  {
3746  LogVerboseInfo(<< "Found unregister method, signature: " << signature);
3747  unRegisterM = m;
3748  this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId));
3749  }
3750  else if (!WrappedMethodExists(signature))
3751  {
3752  WrappedMethods.insert(gxsys_stl::make_pair(signature, MethodInstance(c, m)));
3753  wrapped_methods.push_back(m);
3754  this->MethodIdMap.insert(gxsys_stl::make_pair(m, ++this->CurrentMethodId));
3755  }
3756  else
3757  {
3758  if (this->GetSettings()->GetVerbose())
3759  {
3760  //Emit(os, "//WARNING: ");
3761  //Emit(os, GetAccessString(it.GetAccess()));
3762  //Emit(os, " ");
3763  //Emit(os, (*it)->GetNameOfClass());
3764  //Emit(os, " '");
3765  //Emit(os, (*it)->GetName());
3766  //Emit(os, "' wrappable method *NOT WRAPPED* because its signature matches a method that was already wrapped...\n");
3767  }
3768  }
3769  }
3770 
3771  if (this->GetSettings()->GetVerbose())
3772  {
3773  if (!m)
3774  {
3775  LogInfo(mi_VerboseInfo, << GetAccessString(it.GetAccess())
3776  << " "
3777  << (*it)->GetNameOfClass()
3778  << " '"
3779  << (*it)->GetName()
3780  << "' not wrapped because it's not a method...\n"
3781  );
3782  }
3783  }
3784  }
3785 }
3786 
3787 
3788 //----------------------------------------------------------------------------
3790 {
3791  bool operator()(const cable::Method* m1, const cable::Method* m2)
3792  {
3793  return m1->GetLine() < m2->GetLine();
3794  }
3795 };
3796 
3797 
3798 //----------------------------------------------------------------------------
3800  const cable::Class *,
3801  gxsys_stl::vector<cable::Method*>& wrapped_methods,
3802  cable::Method*&,
3803  cable::Method*&,
3804  cable::Method*&,
3805  cable::Method*&
3806  )
3807 {
3808  bool valid = true;
3809  gxsys_stl::vector<cable::Method*> wrapped_methods_local;
3810  gxsys_stl::vector<cable::Method*>::iterator mit;
3811  cable::Method* m = 0;
3812  gxsys::RegularExpression reGet;
3813  gxsys::RegularExpression reSet;
3814 
3815  reGet.compile("^[Gg]et");
3816  reSet.compile("^[Ss]et");
3817 
3818  // Make a local copy of the wrapped_methods vector so we can sort it by
3819  // "method declaration line number"...
3820  //
3821  gxsys_stl::copy(wrapped_methods.begin(), wrapped_methods.end(),
3822  gxsys_stl::back_inserter(wrapped_methods_local));
3823 
3824  // Sort the vector so that we can emit the fields in the same order
3825  // in which they appear in the original C++ struct/class:
3826  //
3827  gxsys_stl::sort(wrapped_methods_local.begin(), wrapped_methods_local.end(),
3829 
3830  for (mit = wrapped_methods_local.begin(); mit != wrapped_methods_local.end(); ++mit)
3831  {
3832  m = *mit;
3833 
3834  cable::FunctionType *ft = m->GetFunctionType();
3835  unsigned int cArgs = ft->GetNumberOfArguments();
3836  unsigned int cReqArgs = ft->GetNumberOfRequiredArguments();
3837  cable::Type *retType = ft->GetReturns();
3838  bool voidReturn = false;
3839  bool iwhPropGetExempt = false;
3840 
3841  if (IsVoid(retType))
3842  {
3843  voidReturn = true;
3844  }
3845 
3846  if (cArgs != cReqArgs)
3847  {
3848  // Method has at least one default arg... Warn that mummy is ignoring
3849  // any default argument values...
3850  //
3851  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_DefaultArgumentValuesIgnored,
3852  "ignoring default argument values for method '" << m->GetName() << "'.");
3853  }
3854 
3855  if (reGet.find(m->GetName()))
3856  {
3857  //
3858  // It's a "getter" : warn if it returns "void" or if it's not a const
3859  // method or if it's missing the iwhPropGet hint...
3860  //
3861 
3862  if (gxsys_stl::string("GetEnumerator") == m->GetName())
3863  {
3864  iwhPropGetExempt = true;
3865  }
3866 
3867  // The mw_PropGetReturnsVoid and mw_PropGetHasArgs warnings are based on
3868  // the desire that a simple getter method should return one and only one
3869  // thing by return value, not through one or more "byref" arguments...
3870  //
3871  if (voidReturn)
3872  {
3873  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropGetReturnsVoid,
3874  "'Getter' method '" << m->GetName() << "' returns void.");
3875  }
3876 
3877  if (cArgs)
3878  {
3879  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropGetHasArgs,
3880  "'Getter' method '" << m->GetName() << "' has arguments. Should it?");
3881  }
3882 
3883  if (!iwhPropGetExempt && !HasAttribute(m, "gccxml(iwhPropGet)"))
3884  {
3885  if (!voidReturn && 0==cArgs)
3886  {
3887  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_SeriousMissingPropGetHint,
3888  "'Getter' method '" << m->GetName() << "' is a perfect candidate for the 'iwhPropGet' hint. Add the 'iwhPropGet' hint to eliminate this warning.");
3889  }
3890  else
3891  {
3892  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_MissingPropGetHint,
3893  "'Getter' method '" << m->GetName() << "' does not have the 'iwhPropGet' hint. Should it?");
3894  }
3895  }
3896 
3897  if (!m->GetConst() && !m->GetStatic())
3898  {
3899  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropGetNotConst,
3900  "'Getter' method '" << m->GetName() << "' is not const. Should it be const?");
3901  }
3902  }
3903 
3904  if (reSet.find(m->GetName()))
3905  {
3906  // It's a "setter" : warn if it's missing the iwhPropSet hint:
3907  //
3908  if (!HasAttribute(m, "gccxml(iwhPropSet)"))
3909  {
3910  if (voidReturn && 1==cArgs)
3911  {
3912  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_SeriousMissingPropSetHint,
3913  "'Setter' method '" << m->GetName() << "' is a perfect candidate for the 'iwhPropSet' hint. Add the 'iwhPropSet' hint to eliminate this warning.");
3914  }
3915  else
3916  {
3917  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_MissingPropSetHint,
3918  "'Setter' method '" << m->GetName() << "' does not have the 'iwhPropSet' hint. Should it?");
3919  }
3920  }
3921 
3922  if (cArgs!=1)
3923  {
3924  LogFileLineWarningMsg(m->GetFile(), m->GetLine(), mw_PropSetUnexpectedArgCount,
3925  "'Setter' method '" << m->GetName() << "' has " << cArgs << " arguments. Should it have exactly one argument instead?");
3926  }
3927  }
3928  }
3929 
3930  return valid;
3931 }
3932 
3933 
3934 //----------------------------------------------------------------------------
3936  gxsys_stl::vector<cable::Method*>& wrapped_methods,
3937  gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >& wrapped_properties
3938  )
3939 {
3940  gxsys_stl::vector<cable::Method*>::iterator mit;
3941  gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >::iterator gsit;
3942  bool addingPropGet = false;
3943  bool addingPropSet = false;
3944  cable::Method* propGetMethod = 0;
3945  cable::Method* propSetMethod = 0;
3946  gxsys_stl::string propName;
3947 
3948  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
3949  {
3950  addingPropGet = HasAttribute(*mit, "gccxml(iwhPropGet)");
3951  addingPropSet = addingPropGet ? false : HasAttribute(*mit, "gccxml(iwhPropSet)");
3952 
3953  if (addingPropGet || addingPropSet)
3954  {
3955  if (addingPropGet)
3956  {
3957  propGetMethod = *mit;
3958  }
3959  else
3960  {
3961  propGetMethod = 0;
3962  }
3963 
3964  if (addingPropSet)
3965  {
3966  propSetMethod = *mit;
3967  }
3968  else
3969  {
3970  propSetMethod = 0;
3971  }
3972 
3973  propName = ExtractDerivedName(GetWrappedMethodName(*mit).c_str(), *mit,
3974  this->GetSettings()->GetVerbose());
3975 
3976  gsit = wrapped_properties.find(propName);
3977 
3978  if (gsit == wrapped_properties.end())
3979  {
3980  // propName not in our map yet, add it:
3981  //
3982  wrapped_properties.insert(gxsys_stl::make_pair(propName,
3983  gxsys_stl::make_pair(propGetMethod, propSetMethod)));
3984  }
3985  else
3986  {
3987  // We already have an entry for propName...
3988  // This should be the "other" half of the pair.
3989  // So, if we are adding the *get*, then save the
3990  // existing "set" that's already in the map and
3991  // vice versa.
3992  //
3993  if (addingPropGet)
3994  {
3995  propSetMethod = gsit->second.second;
3996  }
3997 
3998  if (addingPropSet)
3999  {
4000  propGetMethod = gsit->second.first;
4001  }
4002 
4003  // The iterator points to the real map entry. Just
4004  // overwrite it:
4005  //
4006  gsit->second = gxsys_stl::make_pair(propGetMethod, propSetMethod);
4007  }
4008  }
4009  }
4010 
4011 
4012  // Analyze wrapped_properties and report anything suspicious.
4013  // Or just report info if verbose...
4014  //
4015  bool verbose = this->GetSettings()->GetVerbose();
4016  if (!wrapped_properties.empty())
4017  {
4018  gxsys_stl::string comment;
4019 
4020  if (verbose)
4021  {
4022  LogInfo(mi_VerboseInfo, << "Properties:");
4023  }
4024 
4025  for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit)
4026  {
4027  if (gsit->second.first!=0 && gsit->second.second!=0)
4028  {
4029  comment = "ReadWrite property.";
4030  }
4031  else if (gsit->second.first!=0)
4032  {
4033  comment = "ReadOnly property.";
4034  }
4035  else if (gsit->second.second!=0)
4036  {
4037  LogFileLineWarningMsg(gsit->second.second->GetFile(),
4038  gsit->second.second->GetLine(),
4040  "A WriteOnly property '" << gsit->first <<
4041  "' is very unusual - did you forget to mark the 'Get' method with 'iwhPropGet'?");
4042  }
4043  else
4044  {
4045  LogError(me_InternalError, "Property with no 'get' and no 'set'... Impossible!");
4046  }
4047 
4048  if (verbose)
4049  {
4050  LogInfo(mi_VerboseInfo, << comment << " propName: " << gsit->first
4051  << " propGetMethod: " << gsit->second.first
4052  << " propSetMethod: " << gsit->second.second
4053  );
4054  }
4055  }
4056  }
4057 }
4058 
4059 
4060 //----------------------------------------------------------------------------
4061 void MummyCsharpGenerator::EmitCSharpWrapperClass(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c)
4062 {
4063  // Gather wrapped elements:
4064  //
4065  gxsys_stl::vector<cable::Method*> wrapped_methods;
4066  gxsys_stl::vector<cable::Method*>::iterator mit;
4067  cable::Method *factoryM = 0;
4068  cable::Method *disposalM = 0;
4069  cable::Method *registerM = 0;
4070  cable::Method *unRegisterM = 0;
4071  bool verbose = this->GetSettings()->GetVerbose();
4072  gxsys_stl::string atts(c->GetAttributes());
4073  gxsys_stl::string mname;
4074 
4075  // The "package" directive from the gccxml input is used as a base
4076  // namespace. If it's not empty, prepend it to the class's namespace.
4077  //
4078  gxsys_stl::string target_namespace;
4079  gxsys_stl::string base_namespace(this->GetSettings()->GetPackage());
4080  gxsys_stl::string class_namespace(GetFullyQualifiedNameForCSharp(c->GetContext()));
4081 
4082  // C++ global scope means "no namespace please"
4083  //
4084  if (class_namespace == "::")
4085  {
4086  class_namespace = "";
4087  }
4088 
4089  if (base_namespace == "")
4090  {
4091  target_namespace = class_namespace;
4092  }
4093  else if (class_namespace == "")
4094  {
4095  target_namespace = base_namespace;
4096  }
4097  else
4098  {
4099  target_namespace = base_namespace + "." + class_namespace;
4100  }
4101 
4102 
4103  // Emit code:
4104  //
4105  EmitMummyVersionComments(os, "//");
4106 
4107 
4108  // If the class maps directly to a builtin type, then DO NOT emit any code.
4109  //
4110  gxsys_stl::string mapToType = ExtractMapToType(c);
4111  if (mapToType != "")
4112  {
4113  Emit(os, "\n");
4114  Emit(os, "//----------------------------------------------------------------------------\n");
4115  Emit(os, "// Unmanaged class '");
4116  Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
4117  Emit(os, "' maps directly to type '");
4118  Emit(os, mapToType.c_str());
4119  Emit(os, "'.\n");
4120  Emit(os, "// No code generated for '");
4121  Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
4122  Emit(os, "'...\n");
4123 
4124  if (verbose)
4125  {
4126  LogInfo(mi_VerboseInfo, << "Skipping code generation because class maps directly to native type.");
4127  }
4128 
4129  return;
4130  }
4131 
4132 
4133  Emit(os, "\n");
4134  Emit(os, "//----------------------------------------------------------------------------\n");
4135  Emit(os, "using System;\n");
4136  Emit(os, "using System.Runtime.InteropServices; // DllImport and HandleRef both live here\n");
4137  Emit(os, "\n");
4138 
4139 
4140  // If this project depends on "using" any other C# namespaces, they will be listed
4141  // as "Reference" elements in MummySettings.xml...
4142  //
4143  gxsys_stl::vector<gxsys_stl::string> refs;
4144  this->GetSettings()->GetReferences(refs);
4145  if (refs.size())
4146  {
4147  Emit(os, "// References\n");
4148  gxsys_stl::vector<gxsys_stl::string>::iterator rit;
4149  for (rit = refs.begin(); rit != refs.end(); ++rit)
4150  {
4151  Emit(os, "using ");
4152  Emit(os, rit->c_str());
4153  Emit(os, ";\n");
4154  }
4155  Emit(os, "\n");
4156  }
4157 
4158 
4159  // Open the (optional) namespace:
4160  //
4161  if (target_namespace != "")
4162  {
4163  Emit(os, "namespace ");
4164  Emit(os, target_namespace.c_str());
4165  Emit(os, "\n");
4166  Emit(os, "{\n");
4167  Emit(os, "\n");
4168  }
4169 
4170 
4171  // Documentation:
4172  //
4173  gxsys_stl::vector<gxsys_stl::string> docblock;
4174  this->ClassLineNumber = c->GetLine();
4175 
4176  if (gxsys::SystemTools::StringStartsWith(GetFullyQualifiedNameForCPlusPlus(c).c_str(), "vtk"))
4177  {
4178  this->GetHeaderFileReader(c)->GetFirstCommentBlock(docblock);
4179  }
4180  else
4181  {
4182  this->GetHeaderFileReader(c)->GetCommentBlockBefore(c->GetLine(), docblock, 1);
4183  }
4184 
4185  EmitDocumentationBlock(os, docblock, 0, true);
4186 
4187 
4188  if (IsUtilityClass(c))
4189  {
4190  // Verify no virtual methods... If any, emit error:
4191  //
4192  cable::Method* um = 0;
4193  bool bVirtual = false;
4194  for (cable::Context::Iterator umit = c->Begin(); !bVirtual && umit != c->End(); ++umit)
4195  {
4196  um = cable::Method::SafeDownCast(*umit);
4197  if (um && um->GetVirtual())
4198  {
4199  bVirtual = true;
4200  }
4201  }
4202 
4203  if (bVirtual)
4204  {
4205  LogFileLineErrorMsg(um->GetFile(), um->GetLine(), me_NoVirtualMethodsAllowed,
4206  "A utility class cannot have any virtual methods. The '" << um->GetName() <<
4207  "' method should not be virtual.");
4208  return;
4209  }
4210 
4211  // Utility classes get wrapped as structs:
4212  //
4214  }
4215  else
4216  {
4217  if (verbose)
4218  {
4219  LogInfo(mi_VerboseInfo, << "Calling GatherWrappedMethods...");
4220  }
4221 
4222  this->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false);
4223 
4224  if (verbose)
4225  {
4227  }
4228 
4229  this->ValidateWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM);
4230 
4231  // Filter out prop gets and sets, putting them in their very own data structure.
4232  // Key in the map is the name of the property. 1st method in pair is propget,
4233  // 2nd method is propset.
4234  //
4235  gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> > wrapped_properties;
4236  this->BuildPropGetsAndSetsMap(wrapped_methods, wrapped_properties);
4237 
4238  // Now remove any entries found in the props *map* from the methods *vector*.
4239  // Otherwise, we'd end up with all of the properties "repeated" as methods, too.
4240  //
4241  gxsys_stl::map<gxsys_stl::string, gxsys_stl::pair<cable::Method*, cable::Method*> >::iterator gsit;
4242  for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit)
4243  {
4244  if (gsit->second.first)
4245  {
4246  mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(),
4247  gsit->second.first);
4248  if (mit != wrapped_methods.end())
4249  {
4250  wrapped_methods.erase(mit);
4251  }
4252  else
4253  {
4254  LogWarning(mw_InternalWarning, << "Unexpected unfound propget method...");
4255  }
4256  }
4257 
4258  if (gsit->second.second)
4259  {
4260  mit = gxsys_stl::find(wrapped_methods.begin(), wrapped_methods.end(),
4261  gsit->second.second);
4262  if (mit != wrapped_methods.end())
4263  {
4264  wrapped_methods.erase(mit);
4265  }
4266  else
4267  {
4268  LogWarning(mw_InternalWarning, << "Unexpected unfound propset method...");
4269  }
4270  }
4271  }
4272 
4273 
4275  if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws))
4276  {
4278  << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str());
4279  }
4280 
4281  const cable::Class *parent = GetWrappableParentClass(c);
4282  bool isPartial = cws.partialClass;
4283  bool emitExceptionParams = !cws.exceptionBaseClass.empty();
4284 
4285  // Class declaration:
4286  //
4287  Emit(os, "public ");
4288  if (c->GetAbstract())
4289  {
4290  Emit(os, "abstract ");
4291  }
4292  if (isPartial)
4293  {
4294  Emit(os, "partial ");
4295  }
4296  Emit(os, "class ");
4297  Emit(os, GetWrappedClassName(c).c_str());
4298  Emit(os, " : ");
4299  if (parent)
4300  {
4301  Emit(os, GetWrappedClassNameFullyQualified(parent).c_str());
4302  }
4303  else
4304  {
4305  gxsys_stl::string wrappedObjectBase(cws.wrappedObjectBase);
4306 
4307  if (wrappedObjectBase.empty())
4308  {
4309  wrappedObjectBase = "Kitware.mummy.Runtime.WrappedObject";
4310  }
4311 
4312  Emit(os, wrappedObjectBase.c_str());
4313  }
4314 
4315 
4316  // Any interface(s)? david.cole::fix - allow potentially many interfaces,
4317  // extract a list here if necessary rather than just one string...
4318  //
4319  gxsys_stl::string iface(ExtractImplementsInterface(atts));
4320 
4321  if (!iface.empty())
4322  {
4323  if (iface == "IEnumerable")
4324  {
4325  this->AddTargetInterface(iface);
4326  Emit(os, ", System.Collections.IEnumerable");
4327  }
4328  else if (iface == "IEnumerator")
4329  {
4330  this->AddTargetInterface(iface);
4331  Emit(os, ", System.Collections.IEnumerator");
4332  }
4333  else
4334  {
4335  this->AddTargetInterface(iface);
4336  Emit(os, ", ");
4337  Emit(os, iface.c_str());
4338  }
4339  }
4340 
4341  Emit(os, "\n");
4342 
4343 
4344  // Open class:
4345  //
4346  Emit(os, "{\n");
4347 
4348 
4349  // david.cole::fix - GetFullyQualifiedNameForCSharp should handle
4350  // target_namespace being set in the gccxml input file, but it currently
4351  // does not. It relies on exact mapping of the C++ namespaces, which does
4352  // not allow for "pushing" stuff in the global C++ namespace into a C#
4353  // namespace as we do in the Vehicles example and Kitware.VTK wrappers...
4354  //
4355  gxsys_stl::string fullCSharpName;
4356  if (target_namespace != "")
4357  {
4358  fullCSharpName = target_namespace + "." + GetWrappedClassName(c);
4359  }
4360  else
4361  {
4362  fullCSharpName = GetWrappedClassName(c);
4363  }
4364 
4365 
4366  // Register type info with the mummy.Runtime for *all* classes,
4367  // even abstract classes. Type registration needs to occur even
4368  // if the first call to the dll is a static method on an abstract
4369  // class (which forces the static constructor to run prior to
4370  // entering the static method...)
4371  //
4372  EmitIndent(os);
4373  Emit(os, "/// <summary>\n");
4374  EmitIndent(os);
4375  Emit(os, "/// Automatically generated type registration mechanics.\n");
4376  EmitIndent(os);
4377  Emit(os, "/// </summary>\n");
4378  EmitIndent(os);
4379  Emit(os, "public new static readonly string MRClassNameKey = \"");
4381  Emit(os, "\";\n");
4382  Emit(os, "\n");
4383 
4384  EmitIndent(os);
4385  Emit(os, "/// <summary>\n");
4386  EmitIndent(os);
4387  Emit(os, "/// Automatically generated type registration mechanics.\n");
4388  EmitIndent(os);
4389  Emit(os, "/// </summary>\n");
4390  EmitIndent(os);
4391  Emit(os, "public new const string MRFullTypeName = \"");
4392  Emit(os, fullCSharpName.c_str());
4393  Emit(os, "\";\n");
4394  Emit(os, "\n");
4395 
4396  EmitIndent(os);
4397  Emit(os, "/// <summary>\n");
4398  EmitIndent(os);
4399  Emit(os, "/// Automatically generated type registration mechanics.\n");
4400  EmitIndent(os);
4401  Emit(os, "/// </summary>\n");
4402  EmitIndent(os);
4403  Emit(os, "static ");
4404  Emit(os, GetWrappedClassName(c).c_str());
4405  Emit(os, "()\n");
4406  EmitIndent(os);
4407  Emit(os, "{\n");
4408 
4409  EmitIndent(os, 2);
4410  Emit(os, "Kitware.mummy.Runtime.Methods.RegisterType(\n");
4411  EmitIndent(os, 3);
4412  Emit(os, "System.Reflection.Assembly.GetExecutingAssembly(),\n");
4413  EmitIndent(os, 3);
4414  Emit(os, "MRClassNameKey,\n");
4415  EmitIndent(os, 3);
4416  Emit(os, "System.Type.GetType(MRFullTypeName)\n");
4417  EmitIndent(os, 3);
4418  Emit(os, ");\n");
4419 
4420  EmitIndent(os);
4421  Emit(os, "}\n");
4422 
4423  Emit(os, "\n");
4424  Emit(os, "\n");
4425 
4426 
4427  // Count events *now* before EmitCSharpDisposalMethod.
4428  // But emit code for the events further below.
4429  //
4430  // Also, examine the full set of events to be generated for this class.
4431  // For any duplicate names, use GetQualifiedEventName instead of
4432  // GetEventName in the methodEventNames map.
4433  //
4434  unsigned int eventCount = 0;
4435  gxsys_stl::map<gxsys_stl::string, int> event_name_counter;
4436  gxsys_stl::map<const cable::Method*, gxsys_stl::string> methodEventNames;
4437  gxsys_stl::string eventName;
4438 
4439  // Count events and fill in event_name_counter as we go:
4440  //
4441  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
4442  {
4443  if (MethodWrappableAsEvent(*mit, cable::Context::Public))
4444  {
4445  ++eventCount;
4446 
4447  eventName = GetEventName(*mit);
4448 
4449  event_name_counter[eventName]++;
4450  }
4451  }
4452 
4453  // Use event_name_counter to build a map of cable::Method* to event names.
4454  // If a method's GetEventName is a duplicate according to event_name_counter
4455  // then use GetQualifiedEventName for that method's event name... With this
4456  // data, we can simply look up the proper event name when given the
4457  // cable::Method* later when we are calling EmitCSharpEvent.
4458  //
4459  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
4460  {
4461  if (MethodWrappableAsEvent(*mit, cable::Context::Public))
4462  {
4463  eventName = GetEventName(*mit);
4464 
4465  if (1 == event_name_counter[eventName])
4466  {
4467  methodEventNames[*mit] = eventName;
4468  }
4469  else
4470  {
4471  methodEventNames[*mit] = GetQualifiedEventName(*mit);
4472  }
4473  }
4474  }
4475 
4476  // Now verify that we have non-duplicate event names. Reset event_name_counter
4477  // and this time analyze whether there are duplicate strings within the
4478  // methodEventNames map.
4479  //
4480  gxsys_stl::map<const cable::Method*, gxsys_stl::string>::iterator menIt;
4481  event_name_counter.clear();
4482  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
4483  {
4484  if (MethodWrappableAsEvent(*mit, cable::Context::Public))
4485  {
4486  menIt = methodEventNames.find(*mit);
4487 
4488  if (menIt != methodEventNames.end())
4489  {
4490  eventName = menIt->second;
4491  event_name_counter[eventName]++;
4492 
4493  if (event_name_counter[eventName] > 1)
4494  {
4495  LogFileLineWarningMsg((*mit)->GetFile(), (*mit)->GetLine(), mw_DuplicateGeneratedName,
4496  << "duplicate event name found: " << eventName.c_str()
4497  << " (a C# compile error will likely follow...)"
4498  );
4499  }
4500  }
4501  else
4502  {
4503  LogFileLineErrorMsg((*mit)->GetFile(), (*mit)->GetLine(), me_InternalError,
4504  << "event method not found in methodEventNames map...");
4505  }
4506  }
4507  }
4508 
4509 
4510  // Constructor(s):
4511  //
4512  gxsys_stl::string ctorModifier(this->GetSettings()->GetCsharpConstructorModifier(c));
4513  if (ctorModifier.empty())
4514  {
4515  ctorModifier = "public";
4516  }
4517  EmitIndent(os);
4518  Emit(os, "/// <summary>\n");
4519  EmitIndent(os);
4520  Emit(os, "/// Automatically generated constructor - called from generated code.\n");
4521  EmitIndent(os);
4522  Emit(os, "/// DO NOT call directly.\n");
4523  EmitIndent(os);
4524  Emit(os, "/// </summary>\n");
4525  EmitIndent(os);
4526  Emit(os, ctorModifier.c_str());
4527  Emit(os, " ");
4528  Emit(os, GetWrappedClassName(c).c_str());
4529  Emit(os, "(IntPtr rawCppThis, bool callDisposalMethod, bool strong) :\n");
4530  EmitIndent(os, 2);
4531  Emit(os, "base(rawCppThis, callDisposalMethod, strong)\n");
4532  EmitIndent(os);
4533  Emit(os, "{\n");
4534  EmitIndent(os);
4535  Emit(os, "}\n");
4536 
4537 
4538  // Factory method:
4539  //
4540  const cable::Method* fmp = 0;
4541  gxsys_stl::string factoryMethod = this->GetSettings()->GetFactoryMethod(c);
4542  const cable::Constructor* ctor = FindNonAbstractPublicDefaultConstructor(c);
4543 
4544  if (!factoryMethod.empty() && factoryMethod!="new")
4545  {
4546  if (factoryM)
4547  {
4548  fmp = factoryM;
4549  mname = fmp->GetName();
4550  }
4551  }
4552  else
4553  {
4554  fmp = ctor;
4555  mname = "new";
4556  }
4557 
4558  if (fmp || this->GetSettings()->GetUseShadow(c))
4559  {
4560  Emit(os, "\n");
4561  Emit(os, "\n");
4562  EmitCSharpConstructor(os, dllname, c, fmp, mname, emitExceptionParams);
4563  }
4564 
4565 
4566  // Register method:
4567  //
4568  if (registerM)
4569  {
4570  mname = registerM->GetName();
4571 
4572  Emit(os, "\n");
4573  Emit(os, "\n");
4574  EmitCSharpRegister(os, dllname, c, registerM, mname, emitExceptionParams);
4575  }
4576 
4577 
4578  // Disposal method:
4579  //
4580  // (disposalM/unRegisterM may be NULL, but we always emit a Dispose...
4581  // the guts of it vary based on disposalM/unRegisterM, but it's always
4582  // there and can be used as a cleaning spot for disconnecting any
4583  // outstanding event RelayHandler delegates...)
4584  //
4585  // If this is a ref-counted class, then use unRegisterM instead of disposalM:
4586  //
4587  const cable::Method* dmp = 0;
4588  gxsys_stl::string disposalMethod = this->GetSettings()->GetDisposalMethod(c);
4589  gxsys_stl::string unRegisterMethod = this->GetSettings()->GetUnRegisterMethod(c);
4590 
4591  if (!unRegisterMethod.empty())
4592  {
4593  if (unRegisterM)
4594  {
4595  dmp = unRegisterM;
4596  mname = dmp->GetName();
4597  }
4598  }
4599  else if (!disposalMethod.empty())
4600  {
4601  if (disposalM)
4602  {
4603  dmp = disposalM;
4604  mname = dmp->GetName();
4605  }
4606  }
4607  else
4608  {
4609  dmp = ctor;
4610  mname = "delete";
4611  }
4612 
4613  // Call EmitCSharpDispose even if dmp is NULL...
4614  //
4615  Emit(os, "\n");
4616  Emit(os, "\n");
4617  EmitCSharpDispose(os, dllname, c, dmp, mname, eventCount, emitExceptionParams);
4618 
4619 
4620  // Enums:
4621  //
4622  EmitCSharpEnums(os, c);
4623 
4624 
4625  // Delegates:
4626  //
4627  for (cable::Context::Iterator it = c->Begin(); it != c->End(); ++it)
4628  {
4629  cable::Typedef *t = cable::Typedef::SafeDownCast(*it);
4630 
4631  if (t && (cable::Context::Public == it.GetAccess()))
4632  {
4633  bool isDelegate = false;
4634  gxsys_stl::string tname(t->GetName());
4635 
4636  //isDelegate = HasAttribute(t, "gccxml(iwhDelegate)");
4637 
4638  cable::PointerType *pt = cable::PointerType::SafeDownCast(t->GetType());
4639  cable::FunctionType *ft = 0;
4640  if (pt)
4641  {
4642  ft = cable::FunctionType::SafeDownCast(pt->GetTarget());
4643  }
4644  if (ft)
4645  {
4646  isDelegate = true;
4647  }
4648 
4649  if (isDelegate)
4650  {
4651  Emit(os, "\n");
4652  Emit(os, "\n");
4653 
4654  docblock.clear();
4655  this->GetHeaderFileReader(c)->GetCommentBlockBefore(t->GetLine(), docblock, this->ClassLineNumber);
4656  EmitDocumentationBlock(os, docblock, 1);
4657 
4658  EmitIndent(os);
4659  Emit(os, "public delegate ");
4660 
4661  unsigned int cArgs = ft->GetNumberOfArguments();
4662  cable::Type *argType = 0;
4663  cable::Type *retType = ft->GetReturns();
4664 
4665  // The following chunk is a near-copy of the bottom of
4666  // EmitCSharpMethodDeclaration...
4667  // <Chunk>
4668 
4669  // Does method return an array?
4670  //
4671  gxsys_stl::string arraySize = "";
4672  atts = t->GetAttributes();
4673  if (atts != "")
4674  {
4675  // Use ExtractArraySize instead of GetMethodArgumentArraySize here.
4676  // This is a delegate definition and cannot be in the VTK hints file.
4677  // (since the hints file only covers "normal" C++ methods...)
4678  // GetMethodArgumentArraySize uses ExtractArraySize internally, and
4679  // if there is no inline hint, it then examines the externalHints
4680  // file to see if there's a match. In this case, there could be no
4681  // match anyhow (as evidenced by the fact that we do not have access
4682  // to a cable::Method here...) so simply use ExtractArraySize directly.
4683  // Same reasoning applies below with the next use of ExtractArraySize.
4684  //
4685  arraySize = ExtractArraySize(atts);
4686  }
4687 
4688  // Return type:
4689  Emit(os, GetPInvokeTypeString(retType, true, arraySize != "", true).c_str());
4690  if (arraySize != "")
4691  {
4692  Emit(os, "[]");
4693  }
4694  Emit(os, " ");
4695 
4696  // Use the typedef name:
4697  Emit(os, t->GetName());
4698 
4699  // Open args:
4700  Emit(os, "(");
4701 
4702  // The C# args:
4703  unsigned int i;
4704  for (i= 0; i<cArgs; ++i)
4705  {
4706  argType = ft->GetArgument(i);
4707 
4708  // Is arg an array?
4709  //
4710  arraySize = "";
4711  atts = ft->GetArgumentAttributes(i);
4712  if (atts != "")
4713  {
4714  // See comments above regarding direct use of ExtractArraySize
4715  // instead of GetMethodArgumentArraySize.
4716  //
4717  arraySize = ExtractArraySize(atts);
4718  }
4719 
4720  // arg type:
4721  Emit(os, GetPInvokeTypeString(argType, false, arraySize != "", true).c_str());
4722 
4723  // array notation:
4724  if (arraySize != "")
4725  {
4726  Emit(os, "[]");
4727  }
4728 
4729  // arg name:
4730  Emit(os, " ");
4731  Emit(os, GetArgName(ft, i));
4732 
4733  if (i<cArgs-1)
4734  {
4735  Emit(os, ", ");
4736  }
4737  }
4738 
4739  // Close args:
4740  Emit(os, ")");
4741 
4742  // </Chunk>
4743 
4744 
4745  Emit(os, ";\n");
4746  }
4747  }
4748  }
4749 
4750 
4751  // Events:
4752  //
4753  if (0 != eventCount)
4754  {
4755  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
4756  {
4757  if (MethodWrappableAsEvent(*mit, cable::Context::Public))
4758  {
4759  Emit(os, "\n");
4760  Emit(os, "\n");
4761 
4762  menIt = methodEventNames.find(*mit);
4763  if (menIt != methodEventNames.end())
4764  {
4765  eventName = menIt->second;
4766  }
4767  else
4768  {
4769  eventName = GetEventName(*mit);
4770  LogFileLineErrorMsg((*mit)->GetFile(), (*mit)->GetLine(), me_InternalError,
4771  << "event method not found in methodEventNames map...");
4772  }
4773 
4774  EmitCSharpEvent(os, dllname, c, *mit, eventName);
4775  }
4776  }
4777 
4778  // Add a special "disconnect all" method that can be called at Dispose
4779  // time so that the unmanaged side does not end up with a stale pointer
4780  // to a garbage collected event RelayHandler...
4781  //
4782  Emit(os, "\n");
4783  Emit(os, "\n");
4784  EmitIndent(os);
4785  Emit(os, "/// <summary>\n");
4786  EmitIndent(os);
4787  Emit(os, "/// Method to disconnect all RelayHandler event members.\n");
4788  EmitIndent(os);
4789  Emit(os, "/// Called automatically from Dispose. DO NOT call directly.\n");
4790  EmitIndent(os);
4791  Emit(os, "/// </summary>\n");
4792  EmitIndent(os);
4793  Emit(os, "private void RemoveAllRelayHandlers()\n");
4794  EmitIndent(os);
4795  Emit(os, "{\n");
4796 
4797  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
4798  {
4799  if (MethodWrappableAsEvent(*mit, cable::Context::Public))
4800  {
4801  menIt = methodEventNames.find(*mit);
4802  if (menIt != methodEventNames.end())
4803  {
4804  eventName = menIt->second;
4805  }
4806  else
4807  {
4808  eventName = GetEventName(*mit);
4809  LogFileLineErrorMsg((*mit)->GetFile(), (*mit)->GetLine(), me_InternalError,
4810  << "event method not found in methodEventNames map...");
4811  }
4812 
4813  EmitIndent(os, 2);
4814  Emit(os, "this.Remove");
4815  Emit(os, eventName.c_str());
4816  Emit(os, "RelayHandler();\n");
4817  }
4818  }
4819 
4820  EmitIndent(os);
4821  Emit(os, "}\n");
4822  }
4823 
4824 
4825  // Properties:
4826  //
4827  for (gsit = wrapped_properties.begin(); gsit != wrapped_properties.end(); ++gsit)
4828  {
4829  Emit(os, "\n");
4830  Emit(os, "\n");
4831  EmitCSharpProperty(os, dllname, c, gsit->second.first, gsit->second.second, emitExceptionParams);
4832  }
4833 
4834 
4835  // Plain old methods:
4836  //
4837  for (mit = wrapped_methods.begin(); mit != wrapped_methods.end(); ++mit)
4838  {
4839  Emit(os, "\n");
4840  Emit(os, "\n");
4841  EmitCSharpMethod(os, dllname, c, *mit, (*mit)->GetName(), "public", emitExceptionParams);
4842  }
4843  }
4844 
4845 
4846  // Hand written shtuff:
4847  //
4848  // If there is extraCSharpCode, emit it *within* the class definition.
4849  // If it's there, it's the name of a file that we are to include in
4850  // its entirety...
4851  //
4852  gxsys_stl::string extraCode = this->GetSettings()->GetExtraCsharpCode(c);
4853  if (extraCode != "")
4854  {
4855  Emit(os, "\n");
4856  Emit(os, "\n");
4857  Emit(os, "// Begin extraCsharpCode\n");
4858  Emit(os, "\n");
4859  EmitFile(os, extraCode.c_str());
4860  Emit(os, "\n");
4861  Emit(os, "// End extraCsharpCode\n");
4862  Emit(os, "\n");
4863  }
4864 
4865 
4866  // Close the struct/class:
4867  //
4868  Emit(os, "}\n");
4869 
4870 
4871  // Close the namespace:
4872  //
4873  if (target_namespace != "")
4874  {
4875  Emit(os, "\n");
4876  Emit(os, "}\n");
4877  }
4878 }
bool IsChar(const cable::Type *t)
virtual void CacheExternalHints(const gxsys_stl::string &hintsfile)
gxsys_stl::string GetQualifiedEventName(const cable::Method *m)
virtual bool WrappedEnumExists(const gxsys_stl::string &name)
virtual void GetFirstCommentBlock(gxsys_stl::vector< gxsys_stl::string > &block)
Retrieve the first block of comment lines, if any, in the file.
virtual MummyLineOrientedTextFileReader * GetHeaderFileReader(const cable::Class *c)
Get or create a header file reader. Only uses class 'c' on the first call. Subsequent calls retrieve ...
virtual void SetFileName(const char *filename)
Set the filename.
bool IsCharPointerPointer(const cable::Type *t)
void Emit(gxsys_ios::ostream &os, const char *s)
virtual void AddLookupEntries(const cable::Class *c)
virtual const char * GetArgName(cable::FunctionType *ftype, unsigned int i)
bool IsCharPointer(const cable::Type *t)
virtual void EmitCSharpDispose(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string &mname, const unsigned int eventCount, bool emitExceptionParams)
virtual bool WrappedMethodExists(const gxsys_stl::string &signature)
virtual void EmitCSharpMethodDeclaration(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, bool asProperty, bool useArg0AsReturn, const gxsys_stl::string &accessLevel)
#define LogVerboseInfo(m)
Definition: MummyLog.h:51
virtual gxsys_stl::string GetExportLayerFunctionName(const cable::Class *c, const cable::Method *m, const gxsys_stl::string &mname)
gxsys_stl::string GetEnumerationTypeString(const cable::Type *t)
void EmitIndent(gxsys_ios::ostream &os, const unsigned int n)
const cable::Class * GetParentClass(const cable::Class *c)
virtual void EmitCSharpConstructor(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string &mname, bool emitExceptionParams)
const cable::Method * Method
virtual void EmitCSharpWrapperClassAsStruct(gxsys_ios::ostream &os, const cable::Class *c)
gxsys_stl::map< gxsys_stl::string, MethodInstance > VirtualMethods
gxsys_stl::map< gxsys_stl::string, MethodInstance > WrappedMethods
virtual gxsys_stl::string GetMethodSignature(const cable::Class *c, const cable::Method *m)
virtual bool TypeIsWrappable(const cable::Type *t)
gxsys_stl::string GetEventName(const cable::Method *m)
#define RETURN_VALUE
virtual bool VirtualMethodOverridden(const gxsys_stl::string &signature)
bool IsObject(const cable::Type *t)
bool EquivalentTypedefNameExists(const cable::Class *c, const cable::FunctionType *target, gxsys_stl::string &s)
gxsys_stl::map< gxsys_stl::string, MethodInstance > WrappedEnums
virtual bool IsDisposalMethod(const cable::Class *c, const cable::Method *m)
bool HasAttribute(const cable::SourceObject *o, const char *attr)
virtual bool MethodIsWrappable(const cable::Method *m, const cable::Context::Access &access)
bool HasMapToType(const cable::Type *t)
virtual gxsys_stl::string GetWrappedMethodName(const cable::Method *m)
bool IsObjectPointerReference(const cable::Type *t)
virtual void EmitCSharpWrapperClass(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c)
gxsys_stl::string GetFullyQualifiedNameForCPlusPlus(const cable::Named *n)
gxsys_stl::string GetFullyQualifiedNameForCSharp(const cable::Named *n)
virtual const cable::Class * GetWrappableParentClass(const cable::Class *c)
virtual gxsys_stl::string GetDisposalMethod(const cable::Class *c)
virtual void SetTargetClass(const cable::Class *c)
Set the current target class.
virtual void EmitCSharpEnums(gxsys_ios::ostream &os, const cable::Class *c)
bool operator()(const cable::Field *f1, const cable::Field *f2)
bool ReturnTypeMatchesHintType(cable::Type *t, const gxsys_stl::string &type)
bool IsUtilityClass(const cable::Class *c)
bool IsVoid(const cable::Type *t)
gxsys_stl::string GetFullyQualifiedName(const cable::Named *n, const char *sep)
bool ExtractTypeAndCountFromHintLine(const gxsys_stl::string &hint, gxsys_stl::string &type, gxsys_stl::string &count)
#define LogFileLineErrorMsg(file, line, n, m)
Definition: MummyLog.h:28
gxsys_stl::map< gxsys_stl::string, MethodInstance > OtherMethods
bool IsObjectPointer(const cable::Type *t)
virtual unsigned int GetNumberOfLines()
Retrieve the total number of lines currently cached.
gxsys_stl::string GetWrappedEnumName(const cable::Enumeration *e)
MethodInstance(const cable::Class *c, const cable::Method *m)
gxsys_stl::map< const gxsys_stl::string, gxsys_stl::string > HintsMap
virtual void EmitCSharpRegister(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string &mname, bool emitExceptionParams)
const char * GetAccessString(cable::Context::Access access)
virtual bool ValidateWrappedMethods(const cable::Class *c, gxsys_stl::vector< cable::Method * > &wrapped_methods, cable::Method *&factoryM, cable::Method *&disposalM, cable::Method *&registerM, cable::Method *&unRegisterM)
virtual void SetTargetClass(const cable::Class *c)
Set the current target class.
gxsys_stl::string ExtractMapToType(const cable::SourceObject *o)
gxsys_stl::map< const cable::Method *, unsigned int > MethodIdMap
gxsys_stl::string ExtractArraySize(const gxsys_stl::string &atts)
virtual bool GetPartialClass(const cable::Class *c)
virtual void AddTargetInterface(const gxsys_stl::string &iface)
bool IsCxxMainStyleParamPair(const cable::FunctionType *ft, unsigned int i)
virtual gxsys_stl::string GetMethodArgumentArraySize(const cable::Class *c, const cable::Method *m, const cable::FunctionType *ft, unsigned int i)
virtual void BuildPropGetsAndSetsMap(gxsys_stl::vector< cable::Method * > &wrapped_methods, gxsys_stl::map< gxsys_stl::string, gxsys_stl::pair< cable::Method *, cable::Method * > > &wrapped_properties)
virtual void GetReferences(gxsys_stl::vector< gxsys_stl::string > &references)
gxsys_stl::map< gxsys_stl::string, MethodInstance > StaticMethods
virtual bool GetVerbose()
virtual void EmitCSharpMethodBody(gxsys_ios::ostream &os, unsigned int indent, const cable::Class *c, const cable::Method *m, gxsys_stl::string &f, const char *impliedArg0, bool emitExceptionParams)
gxsys_stl::string GetFullyQualifiedCPlusPlusTypeIdName(const cable::Named *n)
virtual bool FunctionTypeIsWrappable(const cable::FunctionType *ft)
virtual bool HasTargetInterface(const char *iface) const
gxsys_stl::string GetWrappedClassName(const cable::Class *c)
virtual bool IsLineExcluded(unsigned int lineNumber)
Query whether the given line number should be excluded based on the exclude flag and the line number'...
gxsys_stl::string ExtractDerivedName(const char *s, const cable::Named *n, bool verbose)
virtual gxsys_stl::string GetFundamentalTypeString(const cable::Type *t)
bool ExtractCountFromMethodDeclarationLine(const gxsys_stl::string &line, gxsys_stl::string &count)
#define LogFileLineInfoMsg(file, line, n, m)
Definition: MummyLog.h:34
virtual gxsys_stl::string GetFactoryMethod(const cable::Class *c)
virtual const cable::Class * GetTargetClass()
Get the current target class.
virtual gxsys_stl::string GetCSharpTypeString(const cable::Type *t, bool forReturn, bool isArray)
virtual bool ClassIsWrappable(const cable::Class *c)
virtual bool StaticMethodRedefined(const gxsys_stl::string &signature)
virtual gxsys_stl::string GetPInvokeTypeString(const cable::Type *t, bool forReturn, bool isArray, bool forDelegate)
void EmitFile(gxsys_ios::ostream &os, const char *filename)
Class that reads a text file and caches its lines and information about those lines for quick queries...
virtual gxsys_stl::string GetUnRegisterMethod(const cable::Class *c)
#define LogError(n, m)
Definition: MummyLog.h:41
virtual bool MethodReturnValueIsCounted(const cable::Class *c, const cable::Method *m)
const cable::Constructor * FindNonAbstractPublicDefaultConstructor(const cable::Class *c)
virtual void EmitCSharpMethod(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string &mname, const gxsys_stl::string &accessLevel, bool emitExceptionParams)
virtual gxsys_stl::string GetExtraCsharpCode(const cable::Class *c)
gxsys_stl::string ExtractImplementsInterface(const gxsys_stl::string &atts)
virtual void GatherWrappedMethods(const cable::Class *c, gxsys_stl::vector< cable::Method * > &wrapped_methods, cable::Method *&factoryM, cable::Method *&disposalM, cable::Method *&registerM, cable::Method *&unRegisterM, bool includeParentMethods)
gxsys_stl::string wrappedObjectBase
Definition: MummySettings.h:59
void EmitDocumentationBlock(gxsys_ios::ostream &os, const gxsys_stl::vector< gxsys_stl::string > &block, const unsigned int indent, bool isClassDoc)
virtual bool MethodWrappableAsEvent(const cable::Method *m, const cable::Context::Access &access)
virtual bool OtherMethodRedefined(const gxsys_stl::string &signature)
bool IsFundamentalPointer(const cable::Type *t, cxx::FundamentalType::Id tid)
virtual bool GetIsRefArg(const cable::Type *t)
virtual void EmitMummyVersionComments(gxsys_ios::ostream &os, const char *lineCommentString)
virtual void GetCommentBlockBefore(unsigned int lineNumber, gxsys_stl::vector< gxsys_stl::string > &block, unsigned int smallestAcceptableLineNumber)
Retrieve the nearest preceding block of comment lines relative to line number 'lineNumber'. Valid 'lineNumber' values are 2 through GetNumberOfLines inclusive.
virtual gxsys_stl::string GetRegisterMethod(const cable::Class *c)
bool IsVoidPointer(const cable::Type *t)
gxsys_stl::string GetWrappedClassNameFullyQualified(const cable::Class *c)
virtual bool ClassIsWrappable(const cable::Class *c)
gxsys_stl::string exceptionBaseClass
Definition: MummySettings.h:56
const cable::Class * Class
bool operator()(const cable::Method *m1, const cable::Method *m2)
virtual void EmitCSharpDllImportDeclaration(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string &mname, const char *f, bool emitExceptionParams)
virtual gxsys_stl::string GetLine(unsigned int lineNumber)
Retrieve line number 'lineNumber' as a string from the currently cached text file. Valid 'lineNumber' values are 1 through GetNumberOfLines inclusive.
virtual void EmitCSharpEvent(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *m, const gxsys_stl::string &eventName)
virtual bool FundamentalTypeIsWrappable(const cable::Type *t)
virtual void EmitCSharpProperty(gxsys_ios::ostream &os, const char *dllname, const cable::Class *c, const cable::Method *propGetMethod, const cable::Method *propSetMethod, bool emitExceptionParams)
#define LogInfo(n, m)
Definition: MummyLog.h:47
void EmitThrowClonedException(gxsys_ios::ostream &os, unsigned int indent)
virtual bool IsKeyword(const char *p)
#define LogWarning(n, m)
Definition: MummyLog.h:44
virtual MummySettings * GetSettings()
Get the associated settings object.
gxsys_stl::string TargetInterface
#define LogFileLineWarningMsg(file, line, n, m)
Definition: MummyLog.h:31
virtual bool GetUseShadow(const cable::Class *c)
virtual bool IsReservedMethodName(const gxsys_stl::string &name)
void EmitInt(gxsys_ios::ostream &os, const int i)
virtual bool IsFactoryMethod(const cable::Class *c, const cable::Method *m)