Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data.Entity.Design / System / Data / EntityModel / Emitters / NamespaceEmitter.cs
1 //---------------------------------------------------------------------
2 // <copyright file="NamespaceEmitter.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       [....]
7 // @backupOwner [....]
8 //---------------------------------------------------------------------
9
10 using System;
11 using System.CodeDom;
12 using System.Data;
13 using Som = System.Data.EntityModel.SchemaObjectModel;
14 using System.Collections.Generic;
15 using System.Data.Entity.Design;
16 using System.Data.Metadata.Edm;
17 using System.Collections.ObjectModel;
18 using System.Diagnostics;
19 using System.Data.Entity.Design.SsdlGenerator;
20 using System.Data.Entity.Design.Common;
21
22
23 namespace System.Data.EntityModel.Emitters
24 {
25     /// <summary>
26     /// This class is responsible for Emitting the code to create the CLR namespace container and assembly level attributes
27     /// </summary>
28     internal sealed class NamespaceEmitter : Emitter
29     {
30         #region Static Fields
31         private static Pair<Type, CreateEmitter>[] EmitterCreators = new Pair<Type, CreateEmitter>[]
32         {
33             new Pair<Type,CreateEmitter>(typeof(EntityType), delegate (ClientApiGenerator generator, GlobalItem element) { return new EntityTypeEmitter(generator,(EntityType)element); }),
34             new Pair<Type,CreateEmitter>(typeof(ComplexType), delegate (ClientApiGenerator generator, GlobalItem element) { return new ComplexTypeEmitter(generator,(ComplexType)element); }),
35             new Pair<Type,CreateEmitter>(typeof(EntityContainer), delegate (ClientApiGenerator generator, GlobalItem element) { return new EntityContainerEmitter(generator,(EntityContainer)element); }),            
36             new Pair<Type,CreateEmitter>(typeof(AssociationType), delegate (ClientApiGenerator generator, GlobalItem element) { return new AssociationTypeEmitter(generator,(AssociationType)element); }),            
37         };        
38         #endregion
39
40         #region Private Fields
41
42         private string _codeNamespace = null;
43         private string _targetFilePath = null;
44         #endregion
45
46         #region Public Methods
47         /// <summary>
48         /// 
49         /// </summary>
50         /// <param name="generator"></param>
51         public NamespaceEmitter(ClientApiGenerator generator, string codeNamespace, string targetFilePath)
52             : base(generator)
53         {
54             _codeNamespace = codeNamespace;
55             _targetFilePath = targetFilePath != null ? targetFilePath : string.Empty;
56         }
57
58         /// <summary>
59         /// Creates the CodeTypeDeclarations necessary to generate the code
60         /// </summary>
61         public void Emit()
62         {
63             // it is a valid scenario for namespaceName to be empty
64             string namespaceName = Generator.SourceObjectNamespaceName;
65
66             // emit the namespace definition
67             CodeNamespace codeNamespace = new CodeNamespace( namespaceName );
68
69             // output some boiler plate comments
70             string comments = Strings.NamespaceComments(
71                 System.IO.Path.GetFileName( _targetFilePath ),
72                 DateTime.Now.ToString( System.Globalization.CultureInfo.CurrentCulture ));
73             CommentEmitter.EmitComments( CommentEmitter.GetFormattedLines( comments, false ), codeNamespace.Comments, false );
74             CompileUnit.Namespaces.Add( codeNamespace );
75
76             // Add the assembly attribute.
77             CodeAttributeDeclaration assemblyAttribute;
78             // SQLBUDT 505339: VB compiler fails if multiple assembly attributes exist in the same project.
79             // This adds a GUID to the assembly attribute so that each generated file will have a unique EdmSchemaAttribute in VB.
80             if (this.Generator.Language == System.Data.Entity.Design.LanguageOption.GenerateVBCode) //The GUID is only added in VB
81             {
82                 assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute", System.Guid.NewGuid().ToString());
83             }
84             else
85             {
86                 assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute");
87             }
88             CompileUnit.AssemblyCustomAttributes.Add(assemblyAttribute);
89
90             Dictionary<string, string> usedClassName = new Dictionary<string, string>(StringComparer.Ordinal);
91             // Emit the classes in the schema
92             foreach (GlobalItem element in Generator.GetSourceTypes())
93             {
94                 Debug.Assert(!(element is EdmFunction), "Are you trying to emit functions now? If so add an emitter for it.");
95
96                 if (AddElementNameToCache(element, usedClassName))
97                 {
98                     SchemaTypeEmitter emitter = CreateElementEmitter(element);
99                     CodeTypeDeclarationCollection typeDeclaration = emitter.EmitApiClass();
100                     if (typeDeclaration.Count > 0)
101                     {
102                         codeNamespace.Types.AddRange(typeDeclaration);
103                     }
104                 }
105             }
106         }
107
108         #endregion
109
110
111         #region Private Properties
112         /// <summary>
113         /// Gets the compile unit (top level codedom object)
114         /// </summary>
115         /// <value></value>
116         private CodeCompileUnit CompileUnit
117         {
118             get
119             {
120                 return Generator.CompileUnit;
121             }
122         }        
123         #endregion
124
125         private bool AddElementNameToCache(GlobalItem element, Dictionary<string, string> cache)
126         {
127             if (element.BuiltInTypeKind == BuiltInTypeKind.EntityContainer)
128             {
129                 return TryAddNameToCache((element as EntityContainer).Name, element.BuiltInTypeKind.ToString(), cache);
130             }
131             else if (element.BuiltInTypeKind == BuiltInTypeKind.EntityType ||
132                 element.BuiltInTypeKind == BuiltInTypeKind.ComplexType ||
133                 element.BuiltInTypeKind == BuiltInTypeKind.AssociationType)
134             {
135                 return TryAddNameToCache((element as StructuralType).Name, element.BuiltInTypeKind.ToString(), cache);
136             }
137             return true;
138         }
139
140         private bool TryAddNameToCache(string name, string type, Dictionary<string, string> cache)
141         {
142             if (!cache.ContainsKey(name))
143             {
144                 cache.Add(name, type);
145             }
146             else
147             {
148                 this.Generator.AddError(Strings.DuplicateClassName(type, name, cache[name]), ModelBuilderErrorCode.DuplicateClassName, 
149                     EdmSchemaErrorSeverity.Error, name);
150                 return false;
151             }
152             return true;
153         }
154
155         /// <summary>
156         /// Create an Emitter for a schema type element
157         /// </summary>
158         /// <param name="element"></param>
159         /// <returns></returns>
160         private SchemaTypeEmitter CreateElementEmitter( GlobalItem element )
161         {
162             Type typeOfElement = element.GetType();
163             foreach ( Pair<Type, CreateEmitter> pair in EmitterCreators )
164             {
165                 if ( pair.First.IsAssignableFrom( typeOfElement ) )
166                     return pair.Second( Generator, element );
167             }
168             return null;
169         }
170
171         private delegate SchemaTypeEmitter CreateEmitter( ClientApiGenerator generator, GlobalItem item );
172
173         /// <summary>
174         /// Reponsible for relating two objects together into a pair
175         /// </summary>
176         /// <typeparam name="T1"></typeparam>
177         /// <typeparam name="T2"></typeparam>
178         private class Pair<T1, T2>
179         {
180             public T1 First;
181             public T2 Second;
182             internal Pair( T1 first, T2 second )
183             {
184                 First = first;
185                 Second = second;
186             }
187         }
188     }
189 }