Merge remote-tracking branch 'joncham/sgen-msvc2'
[mono.git] / mcs / class / System.Runtime.Serialization / System.Runtime.Serialization / XsdDataContractImporter.cs
1 //
2 // XsdDataContractImporter.cs
3 //
4 // Authors:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //      Martin Baulig <martin.baulig@xamarin.com>
7 //
8 // Copyright (C) 2010 Novell, Inc.  http://www.novell.com
9 //               2012 Xamarin, Inc.
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;
32 using System.CodeDom;
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.IO;
37 using System.Linq;
38 using System.Reflection;
39 using System.Xml;
40 using System.Xml.Schema;
41 using System.Xml.Serialization;
42
43 using QName = System.Xml.XmlQualifiedName;
44
45 namespace System.Runtime.Serialization
46 {
47         [MonoTODO ("support arrays")]
48         public class XsdDataContractImporter
49         {
50                 static readonly XmlQualifiedName qname_anytype = new XmlQualifiedName ("anyType", XmlSchema.Namespace);
51
52                 public XsdDataContractImporter ()
53                         : this (null)
54                 {
55                 }
56
57                 public XsdDataContractImporter (CodeCompileUnit codeCompileUnit)
58                 {
59                         // null argument is ok.
60                         CodeCompileUnit = codeCompileUnit ?? new CodeCompileUnit ();
61
62                         // Options is null by default
63                 }
64
65                 public CodeCompileUnit CodeCompileUnit { get; private set; }
66
67                 CodeDomProvider code_provider = CodeDomProvider.CreateProvider ("csharp");
68                 Dictionary<CodeNamespace,CodeIdentifiers> identifiers_table = new Dictionary<CodeNamespace,CodeIdentifiers> ();
69                 ImportOptions import_options;
70
71                 public ImportOptions Options {
72                         get { return import_options; }
73                         set {
74                                 import_options = value;
75                                 code_provider = value.CodeProvider ?? code_provider;
76                         }
77                 }
78
79                 void GenerateXmlType (XmlQualifiedName qname)
80                 {
81                         var cns = GetCodeNamespace (qname.Namespace);
82                         var td = new CodeTypeDeclaration () {
83                                 Name = GetUniqueName (CodeIdentifier.MakeValid (qname.Name), cns),
84                                 TypeAttributes = GenerateInternal ? TypeAttributes.NotPublic : TypeAttributes.Public,
85                                 IsPartial = true };
86                         cns.Types.Add (td);
87                         td.BaseTypes.Add (new CodeTypeReference (typeof (IXmlSerializable)));
88
89                         var thisNodes = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Nodes"); // property this.Nodes
90                         var xmlSerializableServices = new CodeTypeReferenceExpression (typeof (XmlSerializableServices)); // static XmlSerializableServices.
91                         var qnameType = new CodeTypeReference (typeof (XmlQualifiedName));
92
93                         // XmlQualifiedName qname = new XmlQualifiedName ({qname.Name}, {qname.Namespace});
94                         td.Members.Add (new CodeMemberField () { Name = "qname", Type = qnameType, InitExpression = new CodeObjectCreateExpression (qnameType, new CodePrimitiveExpression (qname.Name), new CodePrimitiveExpression (qname.Namespace)) });
95
96                         // public XmlNode[] Nodes { get; set; }
97                         td.Members.Add (new CodeMemberProperty () { Name = "Nodes", Type = new CodeTypeReference (typeof (XmlNode [])), Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final, HasGet = true, HasSet = true });
98
99                         // public void ReadXml(XmlReader reader) {
100                         var read = new CodeMemberMethod () { Name = "ReadXml", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final };
101                         read.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (XmlReader)), "reader"));
102                         //   this.Nodes = XmlSerializableServices.ReadXml(reader);
103                         read.Statements.Add (
104                                 new CodeAssignStatement (thisNodes,
105                                         new CodeMethodInvokeExpression (
106                                                 new CodeMethodReferenceExpression (xmlSerializableServices, "ReadXml"),
107                                                 new CodeArgumentReferenceExpression ("reader"))));
108                         // }
109                         td.Members.Add (read);
110
111                         // public void WriteXml(XmlWriter writer) {
112                         var write = new CodeMemberMethod () { Name = "WriteXml",Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final };
113                         write.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (XmlWriter)), "writer"));
114                         //   XmlSerializableServices.WriteXml(writer, this.Nodes);
115                         write.Statements.Add (
116                                 new CodeMethodInvokeExpression (
117                                         new CodeMethodReferenceExpression (xmlSerializableServices, "WriteXml"),
118                                         new CodeArgumentReferenceExpression ("writer"),
119                                         thisNodes));
120                         // }
121                         td.Members.Add (write);
122
123                         // public XmlSchema GetSchema () { return null; }
124                         var getSchema = new CodeMemberMethod () { Name = "GetSchema", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final, ReturnType = new CodeTypeReference (typeof (XmlSchema)) };
125                         getSchema.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (null)));
126                         td.Members.Add (getSchema);
127
128                         // public static XmlQualifiedName ExportSchema (XmlSchemaSet schemas) {
129                         var export = new CodeMemberMethod () { Name = "ExportSchema", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final | MemberAttributes.Static, ReturnType = qnameType };
130                         export.Parameters.Add (new CodeParameterDeclarationExpression (new CodeTypeReference (typeof (XmlSchemaSet)), "schemas"));
131                         //   XmlSerializableServices.AddDefaultSchema (schemas);
132                         export.Statements.Add (new CodeMethodInvokeExpression (xmlSerializableServices, "AddDefaultSchema", new CodeArgumentReferenceExpression ("schemas")));
133                         //   return qname;
134                         export.Statements.Add (new CodeMethodReturnStatement (new CodeFieldReferenceExpression (new CodeThisReferenceExpression (), "qname")));
135                         // }
136                         td.Members.Add (export);
137                 }
138
139                 // CanImport
140
141                 public bool CanImport (XmlSchemaSet schemas)
142                 {
143                         if (schemas == null)
144                                 throw new ArgumentNullException ("schemas");
145
146                         if (!schemas.IsCompiled)
147                                 schemas.Compile ();
148
149                         foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
150                                 if (!CanImport (schemas, xe))
151                                         return false;
152                         return true;
153                 }
154
155                 public bool CanImport (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
156                 {
157                         if (schemas == null)
158                                 throw new ArgumentNullException ("schemas");
159                         if (typeNames == null)
160                                 throw new ArgumentNullException ("typeNames");
161
162                         if (!schemas.IsCompiled)
163                                 schemas.Compile ();
164
165                         foreach (var name in typeNames)
166                                 if (!CanImport (schemas, name))
167                                         return false;
168                         return true;
169                 }
170
171                 public bool CanImport (XmlSchemaSet schemas, XmlQualifiedName typeName)
172                 {
173                         if (schemas == null)
174                                 throw new ArgumentNullException ("schemas");
175                         if (typeName == null)
176                                 throw new ArgumentNullException ("typeName");
177
178                         if (!schemas.IsCompiled)
179                                 schemas.Compile ();
180
181                         if (IsPredefinedType (typeName))
182                                 return true; // while it just ignores...
183
184                         if (!schemas.GlobalTypes.Contains (typeName))
185                                 return false;
186
187                         return CanImport (schemas, schemas.GlobalTypes [typeName] as XmlSchemaType);
188                 }
189
190                 public bool CanImport (XmlSchemaSet schemas, XmlSchemaElement element)
191                 {
192                         if (schemas == null)
193                                 throw new ArgumentNullException ("schemas");
194                         if (element == null)
195                                 throw new ArgumentNullException ("element");
196
197                         if (!schemas.IsCompiled)
198                                 schemas.Compile ();
199
200                         if (element.ElementSchemaType != null)
201                                 return CanImport (schemas, element.ElementSchemaType as XmlSchemaType);
202                         else if (element.SchemaTypeName != null && !element.SchemaTypeName.Equals (QName.Empty))
203                                 return CanImport (schemas, element.SchemaTypeName);
204                         else
205                                 // anyType
206                                 return true;
207                 }
208
209
210 #if true // new
211                 bool CanImport (XmlSchemaSet schemas, XmlSchemaType type)
212                 {
213                         if (IsPredefinedType (type.QualifiedName))
214                                 return true;
215
216                         var st = type as XmlSchemaSimpleType;
217                         if (st != null) {
218                                 return CanImportSimpleType (schemas, st);
219                         } else {
220                                 var ct = (XmlSchemaComplexType) type;
221                                 var sc = ct.ContentModel as XmlSchemaSimpleContent;
222                                 if (sc != null) {
223                                         if (sc.Content is XmlSchemaSimpleContentExtension)
224                                                 return false;
225                                 }
226                                 if (!CanImportComplexType (schemas, ct))
227                                         return false;
228                                 return true;
229                         }
230                 }
231
232                 bool CanImportSimpleType (XmlSchemaSet schemas, XmlSchemaSimpleType type)
233                 {
234                         var scl = type.Content as XmlSchemaSimpleTypeList;
235                         if (scl != null) {
236                                 if (scl.ItemType == null)
237                                         return false;
238                                 var itemType = scl.ItemType as XmlSchemaSimpleType;
239                                 var ir = itemType.Content as XmlSchemaSimpleTypeRestriction;
240                                 if (ir == null)
241                                         return false;
242                                 return true; // as enum
243                         }
244                         var scr = type.Content as XmlSchemaSimpleTypeRestriction;
245                         if (scr != null)
246                                 return true; // as enum
247
248                         return false;
249                 }
250
251                 bool CanImportComplexType (XmlSchemaSet schemas, XmlSchemaComplexType type)
252                 {
253                         foreach (XmlSchemaAttribute att in type.AttributeUses.Values)
254                                 if (att.Use != XmlSchemaUse.Optional || att.QualifiedName.Namespace != KnownTypeCollection.MSSimpleNamespace)
255                                         return false;
256
257                         CodeTypeReference baseClrType = null;
258                         var particle = type.Particle;
259                         if (type.ContentModel != null) {
260                                 var xsscr = type.ContentModel.Content as XmlSchemaSimpleContentRestriction;
261                                 if (xsscr != null) {
262                                         if (xsscr.BaseType != null) {
263                                                 if (!CanImport (schemas, xsscr.BaseType))
264                                                         return false;
265                                         } else {
266                                                 if (!CanImport (schemas, xsscr.BaseTypeName))
267                                                         return false;
268                                         }
269                                         // The above will result in an error, but make sure to show we don't support it.
270                                         return false;
271                                 }
272                                 var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
273                                 if (xscce != null) {
274                                         if (!CanImport (schemas, xscce.BaseTypeName))
275                                                 return false;
276                                         baseClrType = GetCodeTypeReferenceInternal (xscce.BaseTypeName, false);
277
278                                         var baseInfo = GetTypeInfo (xscce.BaseTypeName, false);
279                                         particle = xscce.Particle;
280                                 }
281                                 var xsccr = type.ContentModel.Content as XmlSchemaComplexContentRestriction;
282                                 if (xsccr != null)
283                                         return false;
284                         }
285
286                         var seq = particle as XmlSchemaSequence;
287                         if (seq == null && particle != null)
288                                 return false;
289
290                         if (seq != null) {
291
292                         if (seq.Items.Count == 1 && seq.Items [0] is XmlSchemaAny && type.Parent is XmlSchemaElement) {
293
294                                 // looks like it is not rejected (which contradicts the error message on .NET). See XsdDataContractImporterTest.ImportTestX32(). Also ImporTestX13() for Parent check.
295
296                         } else {
297
298                         foreach (var child in seq.Items)
299                                 if (!(child is XmlSchemaElement))
300                                         return false;
301
302                         bool isDictionary = false;
303                         if (type.Annotation != null) {
304                                 foreach (var ann in type.Annotation.Items) {
305                                         var ai = ann as XmlSchemaAppInfo;
306                                         if (ai != null && ai.Markup != null &&
307                                             ai.Markup.Length > 0 &&
308                                             ai.Markup [0].NodeType == XmlNodeType.Element &&
309                                             ai.Markup [0].LocalName == "IsDictionary" &&
310                                             ai.Markup [0].NamespaceURI == KnownTypeCollection.MSSimpleNamespace)
311                                                 isDictionary = true;
312                                 }
313                         }
314
315                         if (seq.Items.Count == 1) {
316                                 var pt = (XmlSchemaParticle) seq.Items [0];
317                                 var xe = pt as XmlSchemaElement;
318                                 if (pt.MaxOccursString == "unbounded") {
319                                         // import as a collection contract.
320                                         if (pt is XmlSchemaAny) {
321                                         } else if (isDictionary) {
322                                                 var kvt = xe.ElementSchemaType as XmlSchemaComplexType;
323                                                 var seq2 = kvt != null ? kvt.Particle as XmlSchemaSequence : null;
324                                                 var k = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [0] as XmlSchemaElement : null;
325                                                 var v = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [1] as XmlSchemaElement : null;
326                                                 if (k == null || v == null)
327                                                         return false;
328                                                 if (!CanImport (schemas, k.ElementSchemaType))
329                                                         return false;
330                                                 if (!CanImport (schemas, v.ElementSchemaType))
331                                                         return false;
332                                                 
333                                                 return true;
334                                         } else if (type.QualifiedName.Namespace == KnownTypeCollection.MSArraysNamespace &&
335                                                    IsPredefinedType (xe.ElementSchemaType.QualifiedName)) {
336                                                 // then this CodeTypeDeclaration is to be removed, and CodeTypeReference to this type should be an array instead.
337                                                 return true;
338                                         }
339                                         else
340                                                 if (!CanImport (schemas, xe.ElementSchemaType))
341                                                         return false;
342                                         return true;
343                                 }
344                         }
345                         if (isDictionary)
346                                 return false;
347
348                         // import as a (normal) contract.
349                         var elems = new List<XmlSchemaElement> ();
350                         foreach (XmlSchemaElement xe in seq.Items) {
351                                 if (xe.MaxOccurs != 1)
352                                         return false;
353
354                                 if (elems.Any (e => e.QualifiedName.Name == xe.QualifiedName.Name))
355                                         return false;
356
357                                 elems.Add (xe);
358                         }
359                         foreach (var xe in elems) {
360                                 // import property type in prior.
361                                 if (!CanImport (schemas, xe.ElementSchemaType.QualifiedName))
362                                         return false;
363                         }
364
365                         } // if (seq contains only an xs:any)
366                         } // if (seq != 0)
367
368                         return true;
369                 }
370 #else
371                 bool CanImport (XmlSchemaSet schemas, XmlSchemaComplexType type)
372                 {
373                         if (type == null || type.QualifiedName.Namespace == XmlSchema.Namespace) // xs:anyType -> not supported.
374                                 return false;
375
376                         if (type.ContentModel is XmlSchemaSimpleContent) // simple content derivation is not supported.
377                                 return false;
378                         if (type.ContentModel != null && type.ContentModel.Content != null) {
379                                 var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
380                                 if (xscce == null) // complex DBR is not supported.
381                                         return false;
382                                 // check base type
383                                 if (xscce.BaseTypeName != qname_anytype && !CanImport (schemas, xscce.BaseTypeName))
384                                         return false;
385                         }
386
387                         return true;
388                 }
389 #endif
390
391                 // Import
392
393                 public void Import (XmlSchemaSet schemas)
394                 {
395                         if (schemas == null)
396                                 throw new ArgumentNullException ("schemas");
397
398                         if (!schemas.IsCompiled)
399                                 schemas.Compile ();
400
401                         foreach (XmlSchemaElement xe in schemas.GlobalElements.Values)
402                                 Import (schemas, xe);
403                 }
404
405                 public void Import (XmlSchemaSet schemas, ICollection<XmlQualifiedName> typeNames)
406                 {
407                         if (schemas == null)
408                                 throw new ArgumentNullException ("schemas");
409                         if (typeNames == null)
410                                 throw new ArgumentNullException ("typeNames");
411                         foreach (var name in typeNames)
412                                 Import (schemas, name);
413                 }
414
415                 // This checks type existence and raises an error if it is missing.
416                 public void Import (XmlSchemaSet schemas, XmlQualifiedName typeName)
417                 {
418                         if (schemas == null)
419                                 throw new ArgumentNullException ("schemas");
420                         if (typeName == null)
421                                 throw new ArgumentNullException ("typeName");
422
423                         if (!schemas.IsCompiled)
424                                 schemas.Compile ();
425
426                         if (IsPredefinedType (typeName))
427                                 return;
428
429                         if (!schemas.GlobalTypes.Contains (typeName))
430                                 throw new InvalidDataContractException (String.Format ("Type {0} is not found in the schemas", typeName));
431
432                         Import (schemas, schemas.GlobalTypes [typeName] as XmlSchemaType, typeName);
433                 }
434
435                 public XmlQualifiedName Import (XmlSchemaSet schemas, XmlSchemaElement element)
436                 {
437                         if (schemas == null)
438                                 throw new ArgumentNullException ("schemas");
439                         if (element == null)
440                                 throw new ArgumentNullException ("element");
441
442                         var elname = element.QualifiedName;
443
444                         if (IsPredefinedType (element.SchemaTypeName))
445                                 return elname;
446
447                         switch (elname.Namespace) {
448                         case KnownTypeCollection.MSSimpleNamespace:
449                                 switch (elname.Name) {
450                                 case "char":
451                                 case "duration":
452                                 case "guid":
453                                         return elname;
454                                 }
455                                 break;
456                         }
457
458                         if (!CanImport (schemas, element) && Options != null && Options.ImportXmlType) {
459                                 var qn = element.QualifiedName;
460                                 GenerateXmlType (qn);
461                                 return qn;
462                         }
463
464                         if (element.ElementSchemaType != null) {
465                                 if (IsCollectionType (element.ElementSchemaType))
466                                         elname = element.ElementSchemaType.QualifiedName;
467                         }
468
469                         // FIXME: use element to fill nillable and arrays.
470                         var qname =
471                                 elname != null && !elname.Equals (QName.Empty) ? elname :
472                                 element.ElementSchemaType != null ? element.ElementSchemaType.QualifiedName :
473                                 qname_anytype;
474
475                         if (element.ElementSchemaType != null)
476                                 Import (schemas, element.ElementSchemaType, qname);
477                         else if (element.SchemaTypeName != null && !element.SchemaTypeName.Equals (QName.Empty))
478                                 Import (schemas, schemas.GlobalTypes [element.SchemaTypeName] as XmlSchemaType, qname);
479                         // otherwise it is typeless == anyType.
480                         else
481                                 Import (schemas, XmlSchemaType.GetBuiltInComplexType (qname_anytype), qname);
482
483                         return qname;
484                 }
485
486                 void Import (XmlSchemaSet schemas, XmlSchemaType type)
487                 {
488                         if (!CanImport (schemas, type) && Options != null && Options.ImportXmlType) {
489                                 GenerateXmlType (type.QualifiedName);
490                                 return;
491                         }
492                         Import (schemas, type, type.QualifiedName);
493                 }
494
495                 void Import (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
496                 {
497                         var existing = imported_types.FirstOrDefault (it => it.XsdType == type);
498                         if (existing != null)
499                                 return;// existing.XsdTypeName;
500
501                         if (IsPredefinedType (type.QualifiedName))
502                                 return;
503
504                         DoImport (schemas, type, qname);
505                 }
506
507                 string GetUniqueName (string name, CodeNamespace cns)
508                 {
509                         CodeIdentifiers i;
510                         if (!identifiers_table.TryGetValue (cns, out i)) {
511                                 i = new CodeIdentifiers ();
512                                 identifiers_table.Add (cns, i);
513                         }
514                         return i.AddUnique (name, null);
515                 }
516
517                 void DoImport (XmlSchemaSet schemas, XmlSchemaType type, XmlQualifiedName qname)
518                 {
519                         CodeNamespace cns = null;
520                         CodeTypeReference clrRef;
521                         cns = GetCodeNamespace (qname.Namespace);
522                         clrRef = new CodeTypeReference (cns.Name.Length > 0 ? cns.Name + "." + qname.Name : qname.Name);
523
524                         var td = new CodeTypeDeclaration () {
525                                 Name = GetUniqueName (CodeIdentifier.MakeValid (qname.Name), cns),
526                                 TypeAttributes = GenerateInternal ? TypeAttributes.NotPublic : TypeAttributes.Public,
527                                 IsPartial = true };
528                         cns.Types.Add (td);
529
530                         var info = new TypeImportInfo () { ClrType = clrRef, XsdType = type,  XsdTypeName = qname };
531                         imported_types.Add (info);
532
533                         var st = type as XmlSchemaSimpleType;
534                         if (st != null) {
535                                 ImportSimpleType (td, schemas, st, qname);
536                         } else {
537                                 var ct = (XmlSchemaComplexType) type;
538                                 var sc = ct.ContentModel as XmlSchemaSimpleContent;
539                                 if (sc != null) {
540                                         if (sc.Content is XmlSchemaSimpleContentExtension)
541                                                 throw new InvalidDataContractException (String.Format ("complex type '{0}' with simple content extension is not supported", type.QualifiedName));
542                                 }
543                                 if (!ImportComplexType (td, schemas, ct, qname)) {
544                                         cns.Types.Remove (td);
545                                         if (cns.Types.Count == 0)
546                                                 CodeCompileUnit.Namespaces.Remove (cns);
547                                 }
548
549                                 foreach (var impinfo in imported_types)
550                                         for (; impinfo.KnownTypeOutputIndex < impinfo.KnownClrTypes.Count; impinfo.KnownTypeOutputIndex++)
551                                                 td.CustomAttributes.Add (new CodeAttributeDeclaration (
552                                                         new CodeTypeReference (typeof (KnownTypeAttribute)),
553                                                         new CodeAttributeArgument (new CodeTypeOfExpression (impinfo.KnownClrTypes [impinfo.KnownTypeOutputIndex]))));
554                         }
555                 }
556
557                 static readonly string ass_name = typeof (DataContractAttribute).Assembly.GetName ().Name;
558                 static readonly string ass_version = typeof (DataContractAttribute).Assembly.GetName ().Version.ToString ();
559                 static readonly CodeTypeReference typeref_data_contract = new CodeTypeReference (typeof (DataContractAttribute));
560                 static readonly CodeTypeReference typeref_coll_contract = new CodeTypeReference (typeof (CollectionDataContractAttribute));
561
562                 void AddTypeAttributes (CodeTypeDeclaration td, XmlSchemaType type, params XmlSchemaElement [] collectionArgs)
563                 {
564                         var name = type.QualifiedName;
565                         // [GeneratedCode (assembly_name, assembly_version)]
566                         td.CustomAttributes.Add (new CodeAttributeDeclaration (
567                                 new CodeTypeReference (typeof (GeneratedCodeAttribute)),
568                                 new CodeAttributeArgument (new CodePrimitiveExpression (ass_name)),
569                                 new CodeAttributeArgument (new CodePrimitiveExpression (ass_version))));
570
571                         var ct = type as XmlSchemaComplexType;
572
573                         // [DataContract(Name="foobar",Namespace="urn:foobar")] (optionally IsReference=true),
574                         // or [CollectionDataContract(ditto, ItemType/KeyType/ValueType)]
575                         var dca = new CodeAttributeDeclaration (
576                                 collectionArgs != null && collectionArgs.Length > 0 ? typeref_coll_contract : typeref_data_contract,
577                                 new CodeAttributeArgument ("Name", new CodePrimitiveExpression (name.Name)),
578                                 new CodeAttributeArgument ("Namespace", new CodePrimitiveExpression (name.Namespace)));
579                         if (collectionArgs != null) {
580                                 if (collectionArgs.Length > 0)
581                                         dca.Arguments.Add (new CodeAttributeArgument ("ItemName", new CodePrimitiveExpression (CodeIdentifier.MakeValid (collectionArgs [0].QualifiedName.Name))));
582                                 if (collectionArgs.Length > 2) {
583                                         dca.Arguments.Add (new CodeAttributeArgument ("KeyName", new CodePrimitiveExpression (CodeIdentifier.MakeValid (collectionArgs [1].QualifiedName.Name))));
584                                         dca.Arguments.Add (new CodeAttributeArgument ("ValueName", new CodePrimitiveExpression (CodeIdentifier.MakeValid (collectionArgs [2].QualifiedName.Name))));
585                                 }
586                         }
587                         if (ct != null && ct.AttributeUses [new XmlQualifiedName ("Ref", KnownTypeCollection.MSSimpleNamespace)] != null)
588                                 dca.Arguments.Add (new CodeAttributeArgument ("IsReference", new CodePrimitiveExpression (true)));
589                         td.CustomAttributes.Add (dca);
590
591                         // optional [Serializable]
592                         if (Options != null && Options.GenerateSerializable)
593                                 td.CustomAttributes.Add (new CodeAttributeDeclaration ("System.SerializableAttribute"));
594                 }
595
596                 static readonly CodeTypeReference typeref_ext_iface = new CodeTypeReference ("System.Runtime.Serialization.IExtensibleDataObject");
597                 static readonly CodeTypeReference typeref_ext_class = new CodeTypeReference ("System.Runtime.Serialization.ExtensionDataObject");
598
599                 void AddExtensionData (CodeTypeDeclaration td)
600                 {
601                         td.BaseTypes.Add (typeref_ext_iface);
602
603                         var field = new CodeMemberField (typeref_ext_class, "extensionDataField");
604                         td.Members.Add (field);
605
606                         var prop = new CodeMemberProperty () { Type = field.Type, Name = "ExtensionData", Attributes = (GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public) | MemberAttributes.Final };
607                         prop.GetStatements.Add (new CodeMethodReturnStatement (
608                                 new CodeFieldReferenceExpression (
609                                 new CodeThisReferenceExpression (),
610                                 "extensionDataField")));
611                         prop.SetStatements.Add (new CodeAssignStatement (
612                                 new CodeFieldReferenceExpression (
613                                 new CodeThisReferenceExpression (),
614                                 "extensionDataField"),
615                                 new CodePropertySetValueReferenceExpression ()));
616
617                         td.Members.Add (prop);
618                 }
619
620                 void ImportSimpleType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleType type, XmlQualifiedName qname)
621                 {
622                         var scl = type.Content as XmlSchemaSimpleTypeList;
623                         if (scl != null) {
624                                 if (scl.ItemType == null)
625                                         throw new InvalidDataContractException (String.Format ("simple type list is allowed only with an anonymous simple type with enumeration restriction content as its item type definition (type is {0})", type.QualifiedName));
626                                 var itemType = scl.ItemType as XmlSchemaSimpleType;
627                                 var ir = itemType.Content as XmlSchemaSimpleTypeRestriction;
628                                 if (ir == null)
629                                         throw new InvalidDataContractException (String.Format ("simple type list is allowed only with an anonymous simple type with enumeration restriction content as its item type definition (type is {0})", type.QualifiedName));
630                                 ImportEnum (td, schemas, ir, type, qname, true);
631                                 return;
632                         }
633                         var scr = type.Content as XmlSchemaSimpleTypeRestriction;
634                         if (scr != null) {
635                                 ImportEnum (td, schemas, scr, type, qname, false);
636                                 return;
637                         }
638
639                         throw new InvalidDataContractException (String.Format ("simple type is supported only if it has enumeration or list of an anonymous simple type with enumeration restriction content as its item type definition (type is {0})", qname));
640                 }
641
642                 static readonly CodeTypeReference enum_member_att_ref = new CodeTypeReference (typeof (EnumMemberAttribute));
643
644                 void ImportEnum (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaSimpleTypeRestriction r, XmlSchemaType type, XmlQualifiedName qname, bool isFlag)
645                 {
646                         if (isFlag && !r.BaseTypeName.Equals (new XmlQualifiedName ("string", XmlSchema.Namespace)))
647                                 throw new InvalidDataContractException (String.Format ("For flags enumeration '{0}', the base type for the simple type restriction must be XML schema string", qname));
648
649                         td.IsEnum = true;
650                         AddTypeAttributes (td, type);
651                         if (isFlag)
652                                 td.CustomAttributes.Add (new CodeAttributeDeclaration (new CodeTypeReference (typeof (FlagsAttribute))));
653
654                         foreach (var facet in r.Facets) {
655                                 var e = facet as XmlSchemaEnumerationFacet;
656                                 if (e == null)
657                                         throw new InvalidDataContractException (String.Format ("Invalid simple type restriction (type {0}). Only enumeration is allowed.", qname));
658                                 var em = new CodeMemberField () { Name = CodeIdentifier.MakeValid (e.Value) };
659                                 var ea = new CodeAttributeDeclaration (enum_member_att_ref);
660                                 if (e.Value != em.Name)
661                                         ea.Arguments.Add (new CodeAttributeArgument ("Value", new CodePrimitiveExpression (e.Value)));
662                                 em.CustomAttributes.Add (ea);
663                                 td.Members.Add (em);
664                         }
665                 }
666
667                 // Returns false if it should remove the imported type.
668                 bool IsCollectionType (XmlSchemaType type)
669                 {
670                         var complex = type as XmlSchemaComplexType;
671                         if (complex == null)
672                                 return false;
673
674                         var seq = complex.Particle as XmlSchemaSequence;
675                         if (seq == null)
676                                 return false;
677
678                         if (seq.Items.Count == 1 && seq.Items [0] is XmlSchemaAny && complex.Parent is XmlSchemaElement)
679                                 return false;
680
681                         if (type.Annotation != null) {
682                                 foreach (var ann in type.Annotation.Items) {
683                                         var ai = ann as XmlSchemaAppInfo;
684                                         if (ai != null && ai.Markup != null &&
685                                             ai.Markup.Length > 0 &&
686                                             ai.Markup [0].NodeType == XmlNodeType.Element &&
687                                             ai.Markup [0].LocalName == "IsDictionary" &&
688                                             ai.Markup [0].NamespaceURI == KnownTypeCollection.MSSimpleNamespace)
689                                                 return true;
690                                 }
691                         }
692                                         
693                         if (seq.Items.Count != 1)
694                                 return false;
695
696                         var pt = (XmlSchemaParticle) seq.Items [0];
697                         var xe = pt as XmlSchemaElement;
698                         if (pt.MaxOccursString != "unbounded")
699                                 return false;
700
701                         return !(pt is XmlSchemaAny);
702                 }
703
704                 // Returns false if it should remove the imported type.
705                 bool ImportComplexType (CodeTypeDeclaration td, XmlSchemaSet schemas, XmlSchemaComplexType type, XmlQualifiedName qname)
706                 {
707                         foreach (XmlSchemaAttribute att in type.AttributeUses.Values)
708                                 if (att.Use != XmlSchemaUse.Optional || att.QualifiedName.Namespace != KnownTypeCollection.MSSimpleNamespace)
709                                         throw new InvalidDataContractException (String.Format ("attribute in DataContract complex type '{0}' is limited to those in {1} namespace, and optional.", qname, KnownTypeCollection.MSSimpleNamespace));
710
711                         CodeTypeReference baseClrType = null;
712                         var particle = type.Particle;
713                         if (type.ContentModel != null) {
714                                 var xsscr = type.ContentModel.Content as XmlSchemaSimpleContentRestriction;
715                                 if (xsscr != null) {
716                                         if (xsscr.BaseType != null)
717                                                 Import (schemas, xsscr.BaseType);
718                                         else
719                                                 Import (schemas, xsscr.BaseTypeName);
720                                         // The above will result in an error, but make sure to show we don't support it.
721                                         throw new InvalidDataContractException (String.Format ("complex type simple content restriction is not supported in DataContract (type '{0}')", qname));
722                                 }
723                                 var xscce = type.ContentModel.Content as XmlSchemaComplexContentExtension;
724                                 if (xscce != null) {
725                                         Import (schemas, xscce.BaseTypeName);
726                                         baseClrType = GetCodeTypeReferenceInternal (xscce.BaseTypeName, false);
727                                         if (baseClrType != null)
728                                                 td.BaseTypes.Add (baseClrType);
729
730                                         var baseInfo = GetTypeInfo (xscce.BaseTypeName, false);
731                                         if (baseInfo != null)
732                                                 baseInfo.KnownClrTypes.Add (imported_types.First (it => it.XsdType == type).ClrType);
733                                         particle = xscce.Particle;
734                                 }
735                                 var xsccr = type.ContentModel.Content as XmlSchemaComplexContentRestriction;
736                                 if (xsccr != null)
737                                         throw new InvalidDataContractException (String.Format ("complex content type (for type '{0}') has a restriction content model, which is not supported in DataContract.", qname));
738                         }
739
740                         var seq = particle as XmlSchemaSequence;
741                         if (seq == null && particle != null)
742                                 throw new InvalidDataContractException (String.Format ("Not supported particle {1}. In DataContract, only sequence particle is allowed as the top-level content of a complex type (type '{0}')", qname, particle));
743
744                         if (seq != null) {
745
746                         if (seq.Items.Count == 1 && seq.Items [0] is XmlSchemaAny && type.Parent is XmlSchemaElement) {
747
748                                 // looks like it is not rejected (which contradicts the error message on .NET). See XsdDataContractImporterTest.ImportTestX32(). Also ImporTestX13() for Parent check.
749
750                         } else {
751
752                         foreach (var child in seq.Items)
753                                 if (!(child is XmlSchemaElement))
754                                         throw new InvalidDataContractException (String.Format ("Only local element is allowed as the content of the sequence of the top-level content of a complex type '{0}'. Other particles (sequence, choice, all, any, group ref) are not supported.", qname));
755
756                         bool isDictionary = false;
757                         if (type.Annotation != null) {
758                                 foreach (var ann in type.Annotation.Items) {
759                                         var ai = ann as XmlSchemaAppInfo;
760                                         if (ai != null && ai.Markup != null &&
761                                             ai.Markup.Length > 0 &&
762                                             ai.Markup [0].NodeType == XmlNodeType.Element &&
763                                             ai.Markup [0].LocalName == "IsDictionary" &&
764                                             ai.Markup [0].NamespaceURI == KnownTypeCollection.MSSimpleNamespace)
765                                                 isDictionary = true;
766                                 }
767                         }
768
769                         /*
770                          * Collection Type Support:
771                          * 
772                          * We need to distinguish between normal array/dictionary collections and
773                          * custom collection types which use [CollectionDataContract].
774                          * 
775                          * The name of a normal collection type starts with "ArrayOf" and uses the
776                          * element type's namespace.  We use the collection type directly and don't
777                          * generate a proxy class for these.
778                          * 
779                          * The collection type (and the base class or a custom collection's proxy type)
780                          * is dermined by 'ImportOptions.ReferencedCollectionTypes'.  The default is to
781                          * use an array for list collections and Dictionary<,> for dictionaries.
782                          * 
783                          * Note that my implementation currently only checks for generic type definitions
784                          * in the 'ImportOptions.ReferencedCollectionTypes' - it looks for something that
785                          * implements IEnumerable<T> or IDictionary<K,V>.  This is not complete, but it's
786                          * all that's necessary to support different collection types in a GUI.
787                          * 
788                          * Simply use
789                          *     var options = new ImportOptions ();
790                          *     options.ReferencedCollectionTypes.Add (typeof (LinkedList<>));
791                          *     options.ReferencedCollectionTypes.Add (typeof (SortedList<,>));
792                          * to configure these; see XsdDataContractImportTest2.cs for some examples.
793                          * 
794                          */
795
796                         if (seq.Items.Count == 1) {
797                                 var pt = (XmlSchemaParticle) seq.Items [0];
798                                 var xe = pt as XmlSchemaElement;
799                                 if (pt.MaxOccursString == "unbounded") {
800                                         // import as a collection contract.
801                                         if (pt is XmlSchemaAny) {
802                                         } else if (isDictionary) {
803                                                 var kvt = xe.ElementSchemaType as XmlSchemaComplexType;
804                                                 var seq2 = kvt != null ? kvt.Particle as XmlSchemaSequence : null;
805                                                 var k = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [0] as XmlSchemaElement : null;
806                                                 var v = seq2 != null && seq2.Items.Count == 2 ? seq2.Items [1] as XmlSchemaElement : null;
807                                                 if (k == null || v == null)
808                                                         throw new InvalidDataContractException (String.Format ("Invalid Dictionary contract type '{0}'. A Dictionary schema type must have a sequence particle which contains exactly two schema elements for key and value.", type.QualifiedName));
809                                                 return ImportCollectionType (td, schemas, type, k, v);
810                                         }
811                                         return ImportCollectionType (td, schemas, type, xe);
812                                 }
813                         }
814                         if (isDictionary)
815                                 throw new InvalidDataContractException (String.Format ("complex type '{0}' is an invalid Dictionary type definition. A Dictionary must have a sequence particle with exactly two child elements", qname));
816
817                         // import as a (normal) contract.
818                         var elems = new List<XmlSchemaElement> ();
819                         foreach (XmlSchemaElement xe in seq.Items) {
820                                 if (xe.MaxOccurs != 1)
821                                         throw new InvalidDataContractException (String.Format ("schema complex type '{0}' has a content sequence containing an element '{1}' with 'maxOccurs' value as more than 1, which is not supported in DataContract.", qname, xe.QualifiedName));
822
823                                 if (elems.Any (e => e.QualifiedName.Name == xe.QualifiedName.Name))
824                                         throw new InvalidDataContractException (String.Format ("In schema type '{0}', there already is an element whose name is {1}, where duplicate of element names are not supported.", qname, xe.QualifiedName.Name));
825
826                                 elems.Add (xe);
827                         }
828                         foreach (var xe in elems) {
829                                 // import property type in prior.
830                                 Import (schemas, xe.ElementSchemaType.QualifiedName);
831                                 AddProperty (td, xe);
832                         }
833
834                         } // if (seq contains only an xs:any)
835                         } // if (seq != 0)
836
837                         AddTypeAttributes (td, type);
838                         AddExtensionData (td);
839
840                         return true;
841                 }
842
843                 bool ImportCollectionType (CodeTypeDeclaration td, XmlSchemaSet schemas,
844                                            XmlSchemaComplexType type,
845                                            XmlSchemaElement key, XmlSchemaElement value)
846                 {
847                         Import (schemas, key.ElementSchemaType);
848                         Import (schemas, value.ElementSchemaType);
849                         var keyType = GetCodeTypeReference (key.ElementSchemaType.QualifiedName);
850                         var valueType = GetCodeTypeReference (value.ElementSchemaType.QualifiedName);
851
852                         var collectionType = GetDictionaryCollectionType ();
853                         var baseTypeName = collectionType != null ?
854                                 collectionType.FullName : "System.Collections.Generic.Dictionary";
855
856                         if (type.QualifiedName.Name.StartsWith ("ArrayOf")) {
857                                 // Standard collection, use the collection type instead of
858                                 // creating a proxy class.
859                                 var cti = imported_types.First (i => i.XsdType == type);
860                                 cti.ClrType = new CodeTypeReference (baseTypeName, keyType, valueType);
861                                 return false;
862                         }
863
864                         td.BaseTypes.Add (new CodeTypeReference (baseTypeName, keyType, valueType));
865                         AddTypeAttributes (td, type, key);
866                         AddTypeAttributes (td, type, value);
867                         return true;
868                 }
869
870                 bool ImportCollectionType (CodeTypeDeclaration td, XmlSchemaSet schemas,
871                                            XmlSchemaComplexType type, XmlSchemaElement xe)
872                 {
873                         Import (schemas, xe.ElementSchemaType);
874                         var element = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName);
875
876                         var collectionType = GetListCollectionType ();
877
878                         if (type.QualifiedName.Name.StartsWith ("ArrayOf")) {
879                                 // Standard collection, use the collection type instead of
880                                 // creating a proxy class.
881                                 var cti = imported_types.First (i => i.XsdType == type);
882                                 if (collectionType != null)
883                                         cti.ClrType = new CodeTypeReference (collectionType.FullName, element);
884                                 else
885                                         cti.ClrType = new CodeTypeReference (element, 1);
886                                 return false;
887                         }
888
889                         var baseTypeName = collectionType != null ?
890                                 collectionType.FullName : "System.Collections.Generic.List";
891
892                         td.BaseTypes.Add (new CodeTypeReference (baseTypeName, element));
893                         AddTypeAttributes (td, type, xe);
894                         return true;
895                 }
896
897                 bool ImplementsInterface (Type type, Type iface)
898                 {
899                         foreach (var i in type.GetInterfaces ()) {
900                                 if (i.Equals (iface))
901                                         return true;
902                                 if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (iface))
903                                         return true;
904                         }
905
906                         return false;
907                 }
908
909                 Type GetListCollectionType ()
910                 {
911                         if (import_options == null)
912                                 return null;
913                         var listTypes = import_options.ReferencedCollectionTypes.Where (
914                                 t => t.IsGenericTypeDefinition && t.GetGenericArguments ().Length == 1 &&
915                                 ImplementsInterface (t, typeof (IEnumerable<>)));
916                         return listTypes.FirstOrDefault ();
917                 }
918
919                 Type GetDictionaryCollectionType ()
920                 {
921                         if (import_options == null)
922                                 return null;
923                         var dictTypes = import_options.ReferencedCollectionTypes.Where (
924                                 t => t.IsGenericTypeDefinition && t.GetGenericArguments ().Length == 2 &&
925                                 ImplementsInterface (t, typeof (IDictionary<,>)));
926                         return dictTypes.FirstOrDefault ();
927                 }
928
929                 static readonly CodeExpression this_expr = new CodeThisReferenceExpression ();
930                 static readonly CodeExpression arg_value_expr = new CodePropertySetValueReferenceExpression ();
931
932                 bool GenerateInternal {
933                         get { return Options != null && Options.GenerateInternal; }
934                 }
935
936                 void AddProperty (CodeTypeDeclaration td, XmlSchemaElement xe)
937                 {
938                         var att = GenerateInternal ? MemberAttributes.Assembly : MemberAttributes.Public;
939                         var fi = new CodeMemberField () { Name = CodeIdentifier.MakeValid (xe.QualifiedName.Name + "Field"), Type = GetCodeTypeReference (xe.ElementSchemaType.QualifiedName, xe) };
940                         td.Members.Add (fi);
941                         var pi = new CodeMemberProperty () { Name = xe.QualifiedName.Name, Attributes = att, HasGet = true, HasSet = true, Type = fi.Type };
942                         // [DataMember(Name=foobar, IsRequired=!nillable)]
943                         var dma = new CodeAttributeDeclaration (
944                                 new CodeTypeReference (typeof (DataMemberAttribute)));
945                         if (fi.Name != xe.QualifiedName.Name)
946                                 new CodeAttributeArgument ("Name", new CodePrimitiveExpression (xe.QualifiedName.Name));
947                         if (!xe.IsNillable)
948                                 new CodeAttributeArgument ("IsRequired", new CodePrimitiveExpression (true));
949                         pi.CustomAttributes.Add (dma);
950
951                         pi.GetStatements.Add (new CodeMethodReturnStatement () { Expression = new CodeFieldReferenceExpression (this_expr, fi.Name) });
952                         pi.SetStatements.Add (new CodeAssignStatement (new CodeFieldReferenceExpression (this_expr, fi.Name), arg_value_expr));
953
954
955                         td.Members.Add (pi);
956                 }
957
958                 bool IsPredefinedType (XmlQualifiedName qname)
959                 {
960                         if (qname == null)
961                                 return false;
962                         switch (qname.Namespace) {
963                         case KnownTypeCollection.MSSimpleNamespace:
964                                 return KnownTypeCollection.GetPrimitiveTypeFromName (qname) != null;
965                         case XmlSchema.Namespace:
966                                 return XmlSchemaType.GetBuiltInSimpleType (qname) != null || XmlSchemaType.GetBuiltInComplexType (qname) != null;
967                         }
968                         return false;
969                 }
970
971                 CodeNamespace GetCodeNamespace (string xmlns)
972                 {
973                         string ns = null;
974                         if (Options == null || !Options.Namespaces.TryGetValue (xmlns, out ns))
975                                 ns = GetCodeNamespaceFromXmlns (xmlns);
976
977                         foreach (CodeNamespace cns in CodeCompileUnit.Namespaces)
978                                 if (cns.Name == ns)
979                                         return cns;
980                         var newCns = new CodeNamespace () { Name = ns };
981                         CodeCompileUnit.Namespaces.Add (newCns);
982                         return newCns;
983                 }
984
985                 const string default_ns_prefix = "http://schemas.datacontract.org/2004/07/";
986
987                 string GetCodeNamespaceFromXmlns (string xns)
988                 {
989                         if (xns.StartsWith (default_ns_prefix, StringComparison.Ordinal))
990                                 xns = xns.Substring (default_ns_prefix.Length);
991                         else {
992                                 Uri u;
993                                 string tmp;
994                                 if (Uri.TryCreate (xns, UriKind.Absolute, out u) && (tmp = MakeStringNamespaceComponentsValid (u.GetComponents (UriComponents.Host | UriComponents.Path, UriFormat.Unescaped))).Length > 0)
995                                         xns = tmp;
996                         }
997                         return MakeStringNamespaceComponentsValid (xns);
998                 }
999
1000                 static readonly char [] split_tokens = new char [] {'/', '.'};
1001
1002                 string MakeStringNamespaceComponentsValid (string ns)
1003                 {
1004                         var arr = ns.Split (split_tokens, StringSplitOptions.RemoveEmptyEntries);
1005                         for (int i = 0; i < arr.Length; i++)
1006                                 arr [i] = CodeIdentifier.MakeValid (arr [i]);
1007                         return String.Join (".", arr);
1008                 }
1009
1010                 // Post-compilation information retrieval
1011
1012                 TypeImportInfo GetTypeInfo (XmlQualifiedName typeName, bool throwError)
1013                 {
1014                         var info = imported_types.FirstOrDefault (
1015                                 i => i.XsdTypeName.Equals (typeName) || i.XsdType.QualifiedName.Equals (typeName));
1016                         if (info == null) {
1017                                 if (throwError)
1018                                         throw new InvalidOperationException (String.Format ("schema type '{0}' has not been imported yet. Import it first.", typeName));
1019                                 return null;
1020                         }
1021                         return info;
1022                 }
1023
1024                 public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName)
1025                 {
1026                         return GetCodeTypeReferenceInternal (typeName, true);
1027                 }
1028
1029                 CodeTypeReference GetCodeTypeReferenceInternal (XmlQualifiedName typeName, bool throwError)
1030                 {
1031                         if (typeName == null)
1032                                 throw new ArgumentNullException ("typeName");
1033
1034                         switch (typeName.Namespace) {
1035                         case XmlSchema.Namespace:
1036                         case KnownTypeCollection.MSSimpleNamespace:
1037                                 var pt = KnownTypeCollection.GetPrimitiveTypeFromName (typeName);
1038                                 if (pt == null)
1039                                         throw new ArgumentException (String.Format ("Invalid type name in a predefined namespace: {0}", typeName));
1040                                 return new CodeTypeReference (pt);
1041                         }
1042
1043                         var info = GetTypeInfo (typeName, throwError);
1044                         return info != null ? info.ClrType : null;
1045                 }
1046
1047                 [MonoTODO ("use element argument and fill Nullable etc.")]
1048                 public CodeTypeReference GetCodeTypeReference (XmlQualifiedName typeName, XmlSchemaElement element)
1049                 {
1050                         if (typeName == null)
1051                                 throw new ArgumentNullException ("typeName");
1052                         if (element == null)
1053                                 throw new ArgumentNullException ("element");
1054
1055                         return GetCodeTypeReference (typeName);
1056                 }
1057
1058                 public ICollection<CodeTypeReference> GetKnownTypeReferences (XmlQualifiedName typeName)
1059                 {
1060                         if (typeName == null)
1061                                 throw new ArgumentNullException ("typeName");
1062
1063                         return GetTypeInfo (typeName, true).KnownClrTypes;
1064                 }
1065
1066                 List<TypeImportInfo> imported_types = new List<TypeImportInfo> ();
1067
1068                 class TypeImportInfo
1069                 {
1070                         public TypeImportInfo ()
1071                         {
1072                                 KnownClrTypes = new List<CodeTypeReference> ();
1073                         }
1074
1075                         public CodeTypeReference ClrType { get; set; }
1076                         public XmlQualifiedName XsdTypeName { get; set; }
1077                         public XmlSchemaType XsdType { get; set; }
1078                         public List<CodeTypeReference> KnownClrTypes { get; private set; }
1079                         public int KnownTypeOutputIndex { get; set; } // updated while importing.
1080                 }
1081         }
1082 }