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