Merge pull request #799 from kebby/master
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / MapCodeGenerator.cs
1 // 
2 // System.Xml.Serialization.MapCodeGenerator 
3 //
4 // Author:
5 //   Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // Copyright (C) Ximian, Inc., 2003
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.CodeDom;
32 using System.CodeDom.Compiler;
33 using System.Collections;
34 #if NET_2_0
35 using System.ComponentModel;
36 using System.Diagnostics;
37 #endif
38 using System.Globalization;
39 using System.Xml.Schema;
40
41 using Microsoft.CSharp;
42
43 namespace System.Xml.Serialization {
44         internal class MapCodeGenerator {
45
46                 CodeNamespace codeNamespace;
47 //              CodeCompileUnit codeCompileUnit;
48                 CodeAttributeDeclarationCollection includeMetadata;
49                 XmlTypeMapping exportedAnyType;
50                 protected bool includeArrayTypes;
51 #if NET_2_0             
52                 CodeDomProvider codeProvider;
53 #endif          
54                 CodeGenerationOptions options;
55                 CodeIdentifiers identifiers;
56
57                 Hashtable exportedMaps = new Hashtable ();
58                 Hashtable includeMaps = new Hashtable ();
59
60                 public MapCodeGenerator (CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeGenerationOptions options)
61                 {
62 //                      this.codeCompileUnit = codeCompileUnit;
63                         this.codeNamespace = codeNamespace;
64                         this.options = options;
65                         this.identifiers = new CodeIdentifiers ();
66                 }
67
68                 public MapCodeGenerator (CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, CodeDomProvider codeProvider, CodeGenerationOptions options, Hashtable mappings)
69                 {
70 //                      this.codeCompileUnit = codeCompileUnit;
71                         this.codeNamespace = codeNamespace;
72                         this.options = options;
73 #if NET_2_0
74                         this.codeProvider = codeProvider;
75                         this.identifiers = new CodeIdentifiers ((codeProvider.LanguageOptions & LanguageOptions.CaseInsensitive) == 0);
76 #else
77                         this.identifiers = new CodeIdentifiers ();
78 #endif
79 //                      this.mappings = mappings;
80                 }
81
82                 public CodeAttributeDeclarationCollection IncludeMetadata 
83                 {
84                         get 
85                         { 
86                                 if (includeMetadata != null) return includeMetadata;
87                                 includeMetadata = new CodeAttributeDeclarationCollection ();
88                                 
89                                 foreach (XmlTypeMapping map in includeMaps.Values)
90                                         GenerateClassInclude (includeMetadata, map);
91                                 
92                                 return includeMetadata; 
93                         }
94                 }
95                 
96                 #region Code generation methods
97
98                 public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
99                 {
100                         CodeTypeDeclaration dummyClass = new CodeTypeDeclaration ();
101                         ExportMembersMapCode (dummyClass, (ClassMap)xmlMembersMapping.ObjectMap, xmlMembersMapping.Namespace, null);
102                 }
103
104                 public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping, bool isTopLevel)
105                 {
106                         ExportMapCode (xmlTypeMapping, isTopLevel);
107                         RemoveInclude (xmlTypeMapping);
108                 }
109
110                 void ExportMapCode (XmlTypeMapping map, bool isTopLevel)
111                 {
112                         switch (map.TypeData.SchemaType)
113                         {
114                                 case SchemaTypes.Enum:
115                                         ExportEnumCode (map, isTopLevel);
116                                         break;
117
118                                 case SchemaTypes.Array:
119                                         ExportArrayCode (map);
120                                         break;
121
122                                 case SchemaTypes.Class:
123                                         ExportClassCode (map, isTopLevel);
124                                         break;
125
126                                 case SchemaTypes.XmlSerializable:
127                                 case SchemaTypes.XmlNode:
128                                 case SchemaTypes.Primitive:
129                                         // Ignore
130                                         break;
131                         }
132                 }
133
134                 void ExportClassCode (XmlTypeMapping map, bool isTopLevel)
135                 {
136                         CodeTypeDeclaration codeClass;
137                         if (IsMapExported (map)) {
138                                 codeClass = GetMapDeclaration (map);
139                                 if (codeClass != null) {
140                                         // Regenerate attributes, since things may have changed
141                                         codeClass.CustomAttributes.Clear ();
142 #if NET_2_0
143                                         AddClassAttributes (codeClass);
144 #endif
145                                         GenerateClass (map, codeClass, isTopLevel);
146                                         ExportDerivedTypeAttributes (map, codeClass);
147                                 }
148                                 return;
149                         }
150
151                         if (map.TypeData.Type == typeof(object))
152                         {
153                                 exportedAnyType = map;
154                                 SetMapExported (map, null);
155                                 foreach (XmlTypeMapping dmap in exportedAnyType.DerivedTypes) {
156                                         if (IsMapExported (dmap) || !dmap.IncludeInSchema) continue;
157                                         ExportTypeMapping (dmap, false);
158                                         AddInclude (dmap);
159                                 }
160                                 return;
161                         }
162                         
163                         codeClass = new CodeTypeDeclaration (map.TypeData.TypeName);
164                         SetMapExported (map, codeClass);
165
166                         AddCodeType (codeClass, map.Documentation);
167                         codeClass.Attributes = MemberAttributes.Public;
168
169 #if NET_2_0
170                         codeClass.IsPartial = CodeProvider.Supports(GeneratorSupport.PartialTypes);
171                         AddClassAttributes (codeClass);
172 #endif
173
174                         GenerateClass (map, codeClass, isTopLevel);
175                         ExportDerivedTypeAttributes (map, codeClass);
176                         
177                         ExportMembersMapCode (codeClass, (ClassMap)map.ObjectMap, map.XmlTypeNamespace, map.BaseMap);
178
179                         if (map.BaseMap != null && map.BaseMap.TypeData.SchemaType != SchemaTypes.XmlNode)
180                         {
181                                 CodeTypeReference ctr = GetDomType (map.BaseMap.TypeData, false);
182                                 codeClass.BaseTypes.Add (ctr);
183                                 if (map.BaseMap.IncludeInSchema) {
184                                         ExportMapCode (map.BaseMap, false);
185                                         AddInclude (map.BaseMap);
186                                 }
187                         }
188                         ExportDerivedTypes (map, codeClass);
189                 }
190                 
191                 void ExportDerivedTypeAttributes (XmlTypeMapping map, CodeTypeDeclaration codeClass)
192                 {
193                         foreach (XmlTypeMapping tm in map.DerivedTypes)
194                         {
195                                 GenerateClassInclude (codeClass.CustomAttributes, tm);
196                                 ExportDerivedTypeAttributes (tm, codeClass);
197                         }
198                 }
199
200                 void ExportDerivedTypes (XmlTypeMapping map, CodeTypeDeclaration codeClass)
201                 {
202                         foreach (XmlTypeMapping tm in map.DerivedTypes)
203                         {
204                                 if (codeClass.CustomAttributes == null) 
205                                         codeClass.CustomAttributes = new CodeAttributeDeclarationCollection ();
206
207                                 ExportMapCode (tm, false);
208                                 ExportDerivedTypes (tm, codeClass);
209                         }
210                 }
211
212                 void ExportMembersMapCode (CodeTypeDeclaration codeClass, ClassMap map, string defaultNamespace, XmlTypeMapping baseMap)
213                 {
214                         ICollection attributes = map.AttributeMembers;
215                         ICollection members = map.ElementMembers;
216
217                         // collect names
218                         if (attributes != null)
219                                 foreach (XmlTypeMapMemberAttribute attr in attributes)
220                                         identifiers.AddUnique (attr.Name, attr);
221                         if (members != null)
222                                 foreach (XmlTypeMapMemberElement member in members)
223                                         identifiers.AddUnique (member.Name, member);
224
225                         // Write attributes
226
227                         if (attributes != null) {
228                                 foreach (XmlTypeMapMemberAttribute attr in attributes) {
229                                         if (baseMap != null && DefinedInBaseMap (baseMap, attr)) continue;
230                                         AddAttributeFieldMember (codeClass, attr, defaultNamespace);
231                                 }
232                         }
233
234                         members = map.ElementMembers;
235                                 
236                         if (members != null)
237                         {
238                                 foreach (XmlTypeMapMemberElement member in members)
239                                 {
240                                         if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
241
242                                         Type memType = member.GetType();
243                                         if (memType == typeof(XmlTypeMapMemberList))
244                                         {
245                                                 AddArrayElementFieldMember (codeClass, (XmlTypeMapMemberList) member, defaultNamespace);
246                                         }
247                                         else if (memType == typeof(XmlTypeMapMemberFlatList))
248                                         {
249                                                 AddElementFieldMember (codeClass, member, defaultNamespace);
250                                         }
251                                         else if (memType == typeof(XmlTypeMapMemberAnyElement))
252                                         {
253                                                 AddAnyElementFieldMember (codeClass, member, defaultNamespace);
254                                         }
255                                         else if (memType == typeof(XmlTypeMapMemberElement))
256                                         {
257                                                 AddElementFieldMember (codeClass, member, defaultNamespace);
258                                         }
259                                         else
260                                         {
261                                                 throw new InvalidOperationException ("Member type " + memType + " not supported");
262                                         }
263                                 }
264                         }
265
266                         XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
267                         if (anyAttrMember != null)
268                         {
269                                 CodeTypeMember codeField = CreateFieldMember (codeClass, anyAttrMember.TypeData, anyAttrMember.Name);
270                                 AddComments (codeField, anyAttrMember.Documentation);
271                                 codeField.Attributes = MemberAttributes.Public;
272                                 GenerateAnyAttribute (codeField);
273                         }
274                 }
275                 
276                 CodeTypeMember CreateFieldMember (CodeTypeDeclaration codeClass, Type type, string name)
277                 {
278                         return CreateFieldMember (codeClass, new CodeTypeReference(type), name, System.DBNull.Value, null, null);
279                 }
280
281                 CodeTypeMember CreateFieldMember (CodeTypeDeclaration codeClass, TypeData type, string name)
282                 {
283                         return CreateFieldMember (codeClass, GetDomType (type, false), name, System.DBNull.Value, null, null);
284                 }
285
286                 CodeTypeMember CreateFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMember member)
287                 {
288                         return CreateFieldMember (codeClass, GetDomType (member.TypeData, member.RequiresNullable), member.Name, member.DefaultValue, member.TypeData, member.Documentation);
289                 }
290                 
291                 CodeTypeMember CreateFieldMember (CodeTypeDeclaration codeClass, CodeTypeReference type, string name, object defaultValue, TypeData defaultType, string documentation)
292                 {
293                         CodeMemberField codeField = null;
294                         CodeTypeMember codeProp = null;
295
296                         if ((options & CodeGenerationOptions.GenerateProperties) > 0) {
297                                 string field = identifiers.AddUnique (CodeIdentifier.MakeCamel (name + "Field"), name);
298                                 codeField = new CodeMemberField (type, field);
299                                 codeField.Attributes = MemberAttributes.Private;
300                                 codeClass.Members.Add (codeField);
301                                 
302                                 CodeMemberProperty prop = new CodeMemberProperty ();
303                                 prop.Name = name;
304                                 prop.Type = type;
305                                 prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
306                                 codeProp = prop;
307                                 prop.HasGet = prop.HasSet = true;
308                                 
309                                 CodeExpression ce = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), field);
310                                 prop.SetStatements.Add (new CodeAssignStatement (ce, new CodePropertySetValueReferenceExpression()));
311                                 prop.GetStatements.Add (new CodeMethodReturnStatement (ce));
312                         }
313                         else {
314                                 codeField = new CodeMemberField (type, name);
315                                 codeField.Attributes = MemberAttributes.Public;
316                                 codeProp = codeField;
317                         }
318                         
319                         if (defaultValue != System.DBNull.Value)
320                                 GenerateDefaultAttribute (codeField, codeProp, defaultType, defaultValue);
321
322                         AddComments (codeProp, documentation);
323                         codeClass.Members.Add (codeProp);
324                         return codeProp;
325                 }
326
327                 void AddAttributeFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberAttribute attinfo, string defaultNamespace)
328                 {
329                         CodeTypeMember codeField = CreateFieldMember (codeClass, attinfo);
330
331                         CodeAttributeDeclarationCollection attributes = codeField.CustomAttributes;
332                         if (attributes == null) attributes = new CodeAttributeDeclarationCollection ();
333                         
334                         GenerateAttributeMember (attributes, attinfo, defaultNamespace, false);
335                         if (attributes.Count > 0) codeField.CustomAttributes = attributes;
336
337                         if (attinfo.MappedType != null) {
338                                 ExportMapCode (attinfo.MappedType, false);
339                                 RemoveInclude (attinfo.MappedType);
340                         }
341
342                         if (attinfo.TypeData.IsValueType && attinfo.IsOptionalValueType)
343                         {
344                                 codeField = CreateFieldMember (codeClass, typeof(bool), identifiers.MakeUnique (attinfo.Name + "Specified"));
345                                 codeField.Attributes = MemberAttributes.Public;
346                                 GenerateSpecifierMember (codeField);
347                         }
348                 }
349                 
350                 public void AddAttributeMemberAttributes (XmlTypeMapMemberAttribute attinfo, string defaultNamespace, CodeAttributeDeclarationCollection attributes, bool forceUseMemberName)
351                 {
352                         GenerateAttributeMember (attributes, attinfo, defaultNamespace, forceUseMemberName);
353                 }
354
355                 void AddElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberElement member, string defaultNamespace)
356                 {
357                         CodeTypeMember codeField = CreateFieldMember (codeClass, member);
358                         
359                         CodeAttributeDeclarationCollection attributes = codeField.CustomAttributes;
360                         if (attributes == null) attributes = new CodeAttributeDeclarationCollection ();
361                         
362                         AddElementMemberAttributes (member, defaultNamespace, attributes, false);
363                         if (attributes.Count > 0) codeField.CustomAttributes = attributes;
364                         
365                         if (member.TypeData.IsValueType && member.IsOptionalValueType)
366                         {
367                                 codeField = CreateFieldMember (codeClass, typeof(bool), identifiers.MakeUnique (member.Name + "Specified"));
368                                 codeField.Attributes = MemberAttributes.Public;
369                                 GenerateSpecifierMember (codeField);
370                         }
371                 }
372
373                 public void AddElementMemberAttributes (XmlTypeMapMemberElement member, string defaultNamespace, CodeAttributeDeclarationCollection attributes, bool forceUseMemberName)
374                 {
375                         TypeData defaultType = member.TypeData;
376                         bool addAlwaysAttr = false;
377                         
378                         if (member is XmlTypeMapMemberFlatList)
379                         {
380                                 defaultType = defaultType.ListItemTypeData;
381                                 addAlwaysAttr = true;
382                         }
383                         
384                         foreach (XmlTypeMapElementInfo einfo in member.ElementInfo)
385                         {
386                                 if (einfo.MappedType != null) {
387                                         ExportMapCode (einfo.MappedType, false);
388                                         RemoveInclude (einfo.MappedType);
389                                 }
390
391                                 if (ExportExtraElementAttributes (attributes, einfo, defaultNamespace, defaultType))
392                                         continue;
393
394                                 GenerateElementInfoMember (attributes, member, einfo, defaultType, defaultNamespace, addAlwaysAttr, forceUseMemberName | addAlwaysAttr);
395                         }
396
397                         GenerateElementMember (attributes, member);
398                 }
399
400                 void AddAnyElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberElement member, string defaultNamespace)
401                 {
402                         CodeTypeMember codeField = CreateFieldMember (codeClass, member);
403
404                         CodeAttributeDeclarationCollection attributes = new CodeAttributeDeclarationCollection ();
405                         foreach (XmlTypeMapElementInfo einfo in member.ElementInfo)
406                                 ExportExtraElementAttributes (attributes, einfo, defaultNamespace, einfo.TypeData);
407                                 
408                         if (attributes.Count > 0) codeField.CustomAttributes = attributes;
409                 }
410
411                 bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
412                 {
413                         if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
414                                 return true;
415                         else if (map.BaseMap != null)
416                                 return DefinedInBaseMap (map.BaseMap, member);
417                         else
418                                 return false;
419                 }
420
421                 void AddArrayElementFieldMember (CodeTypeDeclaration codeClass, XmlTypeMapMemberList member, string defaultNamespace)
422                 {
423                         CodeTypeMember codeField = CreateFieldMember (codeClass, member.TypeData, member.Name);
424
425                         CodeAttributeDeclarationCollection attributes = new CodeAttributeDeclarationCollection ();
426                         AddArrayAttributes (attributes, member, defaultNamespace, false);
427
428                         ListMap listMap = (ListMap) member.ListTypeMapping.ObjectMap;
429                         AddArrayItemAttributes (attributes, listMap, member.TypeData.ListItemTypeData, defaultNamespace, 0);
430                         
431                         if (attributes.Count > 0) codeField.CustomAttributes = attributes;
432                 }
433
434                 public void AddArrayAttributes (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member, string defaultNamespace, bool forceUseMemberName)
435                 {
436                         GenerateArrayElement (attributes, member, defaultNamespace, forceUseMemberName);
437                 }
438
439                 public void AddArrayItemAttributes (CodeAttributeDeclarationCollection attributes, ListMap listMap, TypeData type, string defaultNamespace, int nestingLevel)
440                 {
441                         foreach (XmlTypeMapElementInfo ainfo in listMap.ItemInfo)
442                         {
443                                 string defaultName;
444                                 if (ainfo.MappedType != null) defaultName = ainfo.MappedType.ElementName;
445                                 else defaultName = ainfo.TypeData.XmlType;
446
447                                 GenerateArrayItemAttributes (attributes, listMap, type, ainfo, defaultName, defaultNamespace, nestingLevel);
448                                 if (ainfo.MappedType != null) {
449                                         if (!IsMapExported (ainfo.MappedType) && includeArrayTypes)
450                                                 AddInclude (ainfo.MappedType);
451                                         ExportMapCode (ainfo.MappedType, false);
452                                 }
453                         }
454
455                         if (listMap.IsMultiArray)
456                         {
457                                 XmlTypeMapping nmap = listMap.NestedArrayMapping;
458                                 AddArrayItemAttributes (attributes, (ListMap) nmap.ObjectMap, nmap.TypeData.ListItemTypeData, defaultNamespace, nestingLevel + 1);
459                         }
460                 }
461                 
462                 void ExportArrayCode (XmlTypeMapping map)
463                 {
464                         ListMap listMap = (ListMap) map.ObjectMap;
465                         foreach (XmlTypeMapElementInfo ainfo in listMap.ItemInfo)
466                         {
467                                 if (ainfo.MappedType != null) {
468                                         if (!IsMapExported (ainfo.MappedType) && includeArrayTypes)
469                                                 AddInclude (ainfo.MappedType);
470                                         ExportMapCode (ainfo.MappedType, false);
471                                 }
472                         }
473                 }
474
475                 bool ExportExtraElementAttributes (CodeAttributeDeclarationCollection attributes, XmlTypeMapElementInfo einfo, string defaultNamespace, TypeData defaultType)
476                 {
477                         if (einfo.IsTextElement) {
478                                 GenerateTextElementAttribute (attributes, einfo, defaultType);
479                                 return true;
480                         }
481                         else if (einfo.IsUnnamedAnyElement) {
482                                 GenerateUnnamedAnyElementAttribute (attributes, einfo, defaultNamespace);
483                                 return true;
484                         }
485                         return false;
486                 }
487
488                 void ExportEnumCode (XmlTypeMapping map, bool isTopLevel)
489                 {
490                         if (IsMapExported (map)) return;
491
492                         CodeTypeDeclaration codeEnum = new CodeTypeDeclaration (map.TypeData.TypeName);
493                         SetMapExported (map, codeEnum);
494                         
495                         codeEnum.Attributes = MemberAttributes.Public;
496                         codeEnum.IsEnum = true;
497                         AddCodeType (codeEnum, map.Documentation);
498
499                         EnumMap emap = (EnumMap) map.ObjectMap;
500                         if (emap.IsFlags)
501                                 codeEnum.CustomAttributes.Add (new CodeAttributeDeclaration ("System.FlagsAttribute"));
502
503 #if NET_2_0
504                         CodeAttributeDeclaration generatedCodeAttribute = new CodeAttributeDeclaration (
505                                 new CodeTypeReference (typeof(GeneratedCodeAttribute)));
506                         generatedCodeAttribute.Arguments.Add (new CodeAttributeArgument (
507                                 new CodePrimitiveExpression ("System.Xml")));
508                         generatedCodeAttribute.Arguments.Add (new CodeAttributeArgument (
509                                 new CodePrimitiveExpression (Consts.FxFileVersion)));
510                         codeEnum.CustomAttributes.Add (generatedCodeAttribute);
511
512                         codeEnum.CustomAttributes.Add (new CodeAttributeDeclaration (
513                                 new CodeTypeReference (typeof (SerializableAttribute))));
514 #endif
515
516                         GenerateEnum (map, codeEnum, isTopLevel);
517                         
518                         int flag = 1;
519                         foreach (EnumMap.EnumMapMember emem in emap.Members)
520                         {
521                                 CodeMemberField codeField = new CodeMemberField ("", emem.EnumName);
522                                 if (emap.IsFlags) {
523                                         codeField.InitExpression = new CodePrimitiveExpression (flag);
524                                         flag *= 2;
525                                 }
526                                 
527                                 AddComments (codeField, emem.Documentation);
528
529                                 GenerateEnumItem (codeField, emem);
530                                 codeEnum.Members.Add (codeField);
531                         }
532                 }
533                 
534                 void AddInclude (XmlTypeMapping map)
535                 {
536                         if (!includeMaps.ContainsKey (map.TypeData.FullTypeName))
537                                 includeMaps [map.TypeData.FullTypeName] = map;
538                 }
539
540                 void RemoveInclude (XmlTypeMapping map)
541                 {
542                         includeMaps.Remove (map.TypeData.FullTypeName);
543                 }
544
545                 #endregion
546                 
547                 #region Helper methods
548                 
549                 bool IsMapExported (XmlTypeMapping map)
550                 {
551                         if (exportedMaps.Contains (map.TypeData.FullTypeName)) return true;
552                         return false;
553                 }
554
555                 void SetMapExported (XmlTypeMapping map, CodeTypeDeclaration declaration)
556                 {
557                         exportedMaps.Add (map.TypeData.FullTypeName, declaration);
558                 }
559
560                 CodeTypeDeclaration GetMapDeclaration (XmlTypeMapping map)
561                 {
562                         return exportedMaps [map.TypeData.FullTypeName] as CodeTypeDeclaration;
563                 }
564
565                 public static void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
566                 {
567                         if (att.Arguments.Count == 0 && !addIfNoParams) return;
568                         
569                         if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
570                         ctm.CustomAttributes.Add (att);
571                 }
572
573                 public static void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
574                 {
575                         if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
576                         ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
577                 }
578
579                 public static CodeAttributeArgument GetArg (string name, object value)
580                 {
581                         return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
582                 }
583
584                 public static CodeAttributeArgument GetArg (object value)
585                 {
586                         return new CodeAttributeArgument (new CodePrimitiveExpression(value));
587                 }
588
589                 public static CodeAttributeArgument GetTypeArg (string name, string typeName)
590                 {
591                         return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
592                 }
593
594                 public static CodeAttributeArgument GetEnumArg (string name, string enumType, string enumValue)
595                 {
596                         return new CodeAttributeArgument (name, new CodeFieldReferenceExpression (new CodeTypeReferenceExpression(enumType), enumValue));
597                 }
598                 
599                 public static void AddComments (CodeTypeMember member, string comments)
600                 {
601                         if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
602                         else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
603                 }
604
605                 void AddCodeType (CodeTypeDeclaration type, string comments)
606                 {
607                         AddComments (type, comments);
608                         codeNamespace.Types.Add (type);
609                 }
610
611 #if NET_2_0
612                 void AddClassAttributes (CodeTypeDeclaration codeClass)
613                 {
614                         CodeAttributeDeclaration generatedCodeAttribute = new CodeAttributeDeclaration (
615                                 new CodeTypeReference (typeof (GeneratedCodeAttribute)));
616                         generatedCodeAttribute.Arguments.Add (new CodeAttributeArgument (
617                                 new CodePrimitiveExpression ("System.Xml")));
618                         generatedCodeAttribute.Arguments.Add (new CodeAttributeArgument (
619                                 new CodePrimitiveExpression (Consts.FxFileVersion)));
620                         codeClass.CustomAttributes.Add (generatedCodeAttribute);
621
622                         codeClass.CustomAttributes.Add (new CodeAttributeDeclaration (
623                                 new CodeTypeReference (typeof (SerializableAttribute))));
624                         codeClass.CustomAttributes.Add (new CodeAttributeDeclaration (
625                                 new CodeTypeReference (typeof (DebuggerStepThroughAttribute))));
626
627                         CodeAttributeDeclaration designerCategoryAttribute = new CodeAttributeDeclaration (
628                                 new CodeTypeReference (typeof (DesignerCategoryAttribute)));
629                         designerCategoryAttribute.Arguments.Add (new CodeAttributeArgument (
630                                 new CodePrimitiveExpression ("code")));
631                         codeClass.CustomAttributes.Add (designerCategoryAttribute);
632                 }
633 #endif
634                 
635                 CodeTypeReference GetDomType (TypeData data, bool requiresNullable)
636                 {
637 #if NET_2_0
638                         if (data.IsValueType && (data.IsNullable || requiresNullable))
639                                 return new CodeTypeReference ("System.Nullable", new CodeTypeReference (data.FullTypeName));
640 #endif
641                         if (data.SchemaType == SchemaTypes.Array)
642                                 return new CodeTypeReference (GetDomType (data.ListItemTypeData, false),1);
643                         else
644                                 return new CodeTypeReference (data.FullTypeName);
645                 }
646                 
647                 #endregion
648
649                 #region Private Properties
650
651 #if NET_2_0
652                 private CodeDomProvider CodeProvider {
653                         get {
654                                 if (codeProvider == null) {
655                                         codeProvider = new CSharpCodeProvider ();
656                                 }
657                                 return codeProvider;
658                         }
659                 }
660 #endif
661
662                 #endregion
663
664                 #region Overridable methods
665
666                 protected virtual void GenerateClass (XmlTypeMapping map, CodeTypeDeclaration codeClass, bool isTopLevel)
667                 {
668                 }
669                 
670                 protected virtual void GenerateClassInclude (CodeAttributeDeclarationCollection attributes, XmlTypeMapping map)
671                 {
672                 }
673                 
674                 protected virtual void GenerateAnyAttribute (CodeTypeMember codeField)
675                 {
676                 }
677                 
678                 protected virtual void GenerateDefaultAttribute (CodeMemberField internalField, CodeTypeMember externalField, TypeData typeData, object defaultValue)
679                 {
680                         if (typeData.Type == null)
681                         {
682                                 // It must be an enumeration defined in the schema.
683                                 if (typeData.SchemaType != SchemaTypes.Enum) 
684                                         throw new InvalidOperationException ("Type " + typeData.TypeName + " not supported");
685
686                                 IFormattable defaultValueFormattable = defaultValue as IFormattable;
687                                 CodeFieldReferenceExpression fref = new CodeFieldReferenceExpression (new CodeTypeReferenceExpression (GetDomType (typeData, false)), defaultValueFormattable != null ? defaultValueFormattable.ToString(null, CultureInfo.InvariantCulture) : defaultValue.ToString ());
688                                 CodeAttributeArgument arg = new CodeAttributeArgument (fref);
689                                 AddCustomAttribute (externalField, "System.ComponentModel.DefaultValue", arg);
690                                 //internalField.InitExpression = fref;
691                         }
692                         else
693                         {
694                                 defaultValue = defaultValue is decimal ? (object) ('"' + ((decimal) defaultValue).ToString (CultureInfo.InvariantCulture) + '"') : defaultValue;
695                                 AddCustomAttribute (externalField, "System.ComponentModel.DefaultValue", GetArg (defaultValue));
696                                 //internalField.InitExpression = new CodePrimitiveExpression (defaultValue);
697                         }
698                 }
699                 
700                 protected virtual void GenerateAttributeMember (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberAttribute attinfo, string defaultNamespace, bool forceUseMemberName)
701                 {
702                 }
703                 
704                 protected virtual void GenerateElementInfoMember (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member, XmlTypeMapElementInfo einfo, TypeData defaultType, string defaultNamespace, bool addAlwaysAttr, bool forceUseMemberName)
705                 {
706                 }
707                 
708                 protected virtual void GenerateElementMember (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member)
709                 {
710                 }
711                 
712                 protected virtual void GenerateArrayElement (CodeAttributeDeclarationCollection attributes, XmlTypeMapMemberElement member, string defaultNamespace, bool forceUseMemberName)
713                 {
714                 }
715                 
716                 protected virtual void GenerateArrayItemAttributes (CodeAttributeDeclarationCollection attributes, ListMap listMap, TypeData type, XmlTypeMapElementInfo ainfo, string defaultName, string defaultNamespace, int nestingLevel)
717                 {
718                 }
719
720                 protected virtual void GenerateTextElementAttribute (CodeAttributeDeclarationCollection attributes, XmlTypeMapElementInfo einfo, TypeData defaultType)
721                 {
722                 }
723                 
724                 protected virtual void GenerateUnnamedAnyElementAttribute (CodeAttributeDeclarationCollection attributes, XmlTypeMapElementInfo einfo, string defaultNamespace)
725                 {
726                 }
727
728                 protected virtual void GenerateEnum (XmlTypeMapping map, CodeTypeDeclaration codeEnum, bool isTopLevel)
729                 {
730                 }
731                 
732                 protected virtual void GenerateEnumItem (CodeMemberField codeField, EnumMap.EnumMapMember emem)
733                 {
734                 }
735
736                 protected virtual void GenerateSpecifierMember (CodeTypeMember codeField)
737                 {
738                 }
739
740                 #endregion
741         }
742 }