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