PageRenderTime 43ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Data.Linq/src/DbMetal/Generator/Implementation/CodeTextGenerator/CodeGenerator.cs

https://github.com/ztfuqingvip/mono
C# | 466 lines | 358 code | 45 blank | 63 comment | 47 complexity | 4ad39ac20c811d785348b9508a302bdf MD5 | raw file
Possible License(s): GPL-2.0, Unlicense, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0
  1. #region MIT license
  2. //
  3. // MIT license
  4. //
  5. // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. #endregion
  26. using System;
  27. using System.Collections.Generic;
  28. using System.IO;
  29. using System.Linq;
  30. using DbLinq.Data.Linq;
  31. using DbLinq.Schema;
  32. using DbLinq.Schema.Dbml;
  33. using DbLinq.Schema.Dbml.Adapter;
  34. using DbLinq.Util;
  35. using Type = System.Type;
  36. #if MONO_STRICT
  37. using System.Data.Linq;
  38. #endif
  39. namespace DbMetal.Generator.Implementation.CodeTextGenerator
  40. {
  41. #if !MONO_STRICT
  42. public
  43. #endif
  44. abstract partial class CodeGenerator : ICodeGenerator
  45. {
  46. public abstract string LanguageCode { get; }
  47. public abstract string Extension { get; }
  48. protected class MassDisposer : IDisposable
  49. {
  50. public IList<IDisposable> Disposables = new List<IDisposable>();
  51. public void Dispose()
  52. {
  53. for (int index = Disposables.Count - 1; index > 0; index--)
  54. {
  55. Disposables[index].Dispose();
  56. }
  57. }
  58. }
  59. protected abstract CodeWriter CreateCodeWriter(TextWriter textWriter);
  60. public void Write(TextWriter textWriter, Database dbSchema, GenerationContext context)
  61. {
  62. if (dbSchema == null || dbSchema.Tables == null)
  63. {
  64. //Logger.Write(Level.Error, "CodeGenAll ERROR: incomplete dbSchema, cannot start generating code");
  65. return;
  66. }
  67. context["namespace"] = string.IsNullOrEmpty(context.Parameters.Namespace)
  68. ? dbSchema.ContextNamespace
  69. : context.Parameters.Namespace;
  70. context["database"] = dbSchema.Name;
  71. context["generationTime"] = context.Parameters.GenerateTimestamps
  72. ? DateTime.Now.ToString("u")
  73. : "[TIMESTAMP]";
  74. context["class"] = dbSchema.Class;
  75. using (var codeWriter = CreateCodeWriter(textWriter))
  76. {
  77. WriteBanner(codeWriter, context);
  78. WriteUsings(codeWriter, context);
  79. string contextNamespace = context.Parameters.Namespace;
  80. if (string.IsNullOrEmpty(contextNamespace))
  81. contextNamespace = dbSchema.ContextNamespace;
  82. string entityNamespace = context.Parameters.Namespace;
  83. if (string.IsNullOrEmpty(entityNamespace))
  84. entityNamespace = dbSchema.EntityNamespace;
  85. bool generateDataContext = true;
  86. var types = context.Parameters.GenerateTypes;
  87. if (types.Count > 0)
  88. generateDataContext = types.Contains(dbSchema.Class);
  89. if (contextNamespace == entityNamespace)
  90. {
  91. using (WriteNamespace(codeWriter, contextNamespace))
  92. {
  93. if (generateDataContext)
  94. WriteDataContext(codeWriter, dbSchema, context);
  95. WriteClasses(codeWriter, dbSchema, context);
  96. }
  97. }
  98. else
  99. {
  100. if (generateDataContext)
  101. using (WriteNamespace(codeWriter, contextNamespace))
  102. WriteDataContext(codeWriter, dbSchema, context);
  103. using (WriteNamespace(codeWriter, entityNamespace))
  104. WriteClasses(codeWriter, dbSchema, context);
  105. }
  106. }
  107. }
  108. private void WriteBanner(CodeWriter writer, GenerationContext context)
  109. {
  110. using (writer.WriteRegion(context.Evaluate("Auto-generated classes for ${database} database on ${generationTime}")))
  111. {
  112. // http://www.network-science.de/ascii/
  113. // http://www.network-science.de/ascii/ascii.php?TEXT=MetalSequel&x=14&y=14&FONT=_all+fonts+with+your+text_&RICH=no&FORM=left&STRE=no&WIDT=80
  114. writer.WriteCommentLines(
  115. @"
  116. ____ _ __ __ _ _
  117. | _ \| |__ | \/ | ___| |_ __ _| |
  118. | | | | '_ \| |\/| |/ _ \ __/ _` | |
  119. | |_| | |_) | | | | __/ || (_| | |
  120. |____/|_.__/|_| |_|\___|\__\__,_|_|
  121. ");
  122. writer.WriteCommentLines(context.Evaluate("Auto-generated from ${database} on ${generationTime}"));
  123. writer.WriteCommentLines("Please visit http://linq.to/db for more information");
  124. }
  125. }
  126. private void WriteUsings(CodeWriter writer, GenerationContext context)
  127. {
  128. writer.WriteUsingNamespace("System");
  129. writer.WriteUsingNamespace("System.Data");
  130. writer.WriteUsingNamespace("System.Data.Linq.Mapping");
  131. writer.WriteUsingNamespace("System.Diagnostics");
  132. writer.WriteUsingNamespace("System.Reflection");
  133. #if MONO_STRICT
  134. writer.WriteUsingNamespace("System.Data.Linq");
  135. #else
  136. writer.WriteLine("#if MONO_STRICT");
  137. writer.WriteUsingNamespace("System.Data.Linq");
  138. writer.WriteLine("#else // MONO_STRICT");
  139. writer.WriteUsingNamespace("DbLinq.Data.Linq");
  140. writer.WriteUsingNamespace("DbLinq.Vendor");
  141. writer.WriteLine("#endif // MONO_STRICT");
  142. #endif
  143. // writer.WriteUsingNamespace("System");
  144. // writer.WriteUsingNamespace("System.Collections.Generic");
  145. // writer.WriteUsingNamespace("System.ComponentModel");
  146. // writer.WriteUsingNamespace("System.Data");
  147. // writer.WriteUsingNamespace("System.Data.Linq.Mapping");
  148. // writer.WriteUsingNamespace("System.Diagnostics");
  149. // writer.WriteUsingNamespace("System.Linq");
  150. // writer.WriteUsingNamespace("System.Reflection");
  151. // writer.WriteUsingNamespace("System.Text");
  152. //#if MONO_STRICT
  153. // writer.WriteUsingNamespace("System.Data.Linq");
  154. //#else
  155. // writer.WriteUsingNamespace("DbLinq.Data.Linq");
  156. // writer.WriteUsingNamespace("DbLinq.Data.Linq.Mapping");
  157. //#endif
  158. // now, we write usings required by implemented interfaces
  159. foreach (var implementation in context.Implementations())
  160. implementation.WriteHeader(writer, context);
  161. // write namespaces for members attributes
  162. foreach (var memberAttribute in context.Parameters.MemberAttributes)
  163. WriteUsingNamespace(writer, GetNamespace(memberAttribute));
  164. writer.WriteLine();
  165. }
  166. /// <summary>
  167. /// Writes a using, if given namespace is not null or empty
  168. /// </summary>
  169. /// <param name="writer"></param>
  170. /// <param name="nameSpace"></param>
  171. protected virtual void WriteUsingNamespace(CodeWriter writer, string nameSpace)
  172. {
  173. if (!string.IsNullOrEmpty(nameSpace))
  174. writer.WriteUsingNamespace(nameSpace);
  175. }
  176. protected virtual string GetNamespace(string fullName)
  177. {
  178. var namePartIndex = fullName.LastIndexOf('.');
  179. // if we have a dot, we have a namespace
  180. if (namePartIndex < 0)
  181. return null;
  182. return fullName.Substring(0, namePartIndex);
  183. }
  184. private IDisposable WriteNamespace(CodeWriter writer, string nameSpace)
  185. {
  186. if (!string.IsNullOrEmpty(nameSpace))
  187. return writer.WriteNamespace(nameSpace);
  188. return null;
  189. }
  190. private void WriteDataContext(CodeWriter writer, Database schema, GenerationContext context)
  191. {
  192. if (schema.Tables.Count == 0)
  193. {
  194. writer.WriteCommentLine("L69 no tables found");
  195. return;
  196. }
  197. string contextBase = schema.BaseType;
  198. var contextBaseType = string.IsNullOrEmpty(contextBase)
  199. ? typeof(DataContext)
  200. : TypeLoader.Load(contextBase);
  201. // in all cases, get the literal type name from loaded type
  202. contextBase = writer.GetLiteralType(contextBaseType);
  203. var specifications = SpecificationDefinition.Partial;
  204. if (schema.AccessModifierSpecified)
  205. specifications |= GetSpecificationDefinition(schema.AccessModifier);
  206. else
  207. specifications |= SpecificationDefinition.Public;
  208. if (schema.ModifierSpecified)
  209. specifications |= GetSpecificationDefinition(schema.Modifier);
  210. using (writer.WriteClass(specifications, schema.Class, contextBase))
  211. {
  212. WriteDataContextExtensibilityDeclarations(writer, schema, context);
  213. WriteDataContextCtors(writer, schema, contextBaseType, context);
  214. WriteDataContextTables(writer, schema, context);
  215. WriteDataContextProcedures(writer, schema, context);
  216. }
  217. }
  218. private void WriteDataContextTables(CodeWriter writer, Database schema, GenerationContext context)
  219. {
  220. foreach (var table in schema.Tables)
  221. WriteDataContextTable(writer, table);
  222. writer.WriteLine();
  223. }
  224. protected abstract void WriteDataContextTable(CodeWriter writer, Table table);
  225. protected virtual Type GetType(string literalType, bool canBeNull)
  226. {
  227. bool isNullable = literalType.EndsWith("?");
  228. if (isNullable)
  229. literalType = literalType.Substring(0, literalType.Length - 1);
  230. bool isArray = literalType.EndsWith("[]");
  231. if (isArray)
  232. literalType = literalType.Substring(0, literalType.Length - 2);
  233. Type type = GetSimpleType(literalType);
  234. if (type == null)
  235. return type;
  236. if (isArray)
  237. type = type.MakeArrayType();
  238. if (isNullable)
  239. type = typeof(Nullable<>).MakeGenericType(type);
  240. else if (canBeNull)
  241. {
  242. if (type.IsValueType)
  243. type = typeof(Nullable<>).MakeGenericType(type);
  244. }
  245. return type;
  246. }
  247. private Type GetSimpleType(string literalType)
  248. {
  249. switch (literalType)
  250. {
  251. case "string":
  252. return typeof(string);
  253. case "long":
  254. return typeof(long);
  255. case "short":
  256. return typeof(short);
  257. case "int":
  258. return typeof(int);
  259. case "char":
  260. return typeof(char);
  261. case "byte":
  262. return typeof(byte);
  263. case "float":
  264. return typeof(float);
  265. case "double":
  266. return typeof(double);
  267. case "decimal":
  268. return typeof(decimal);
  269. case "bool":
  270. return typeof(bool);
  271. case "DateTime":
  272. return typeof(DateTime);
  273. case "object":
  274. return typeof(object);
  275. default:
  276. return Type.GetType(literalType);
  277. }
  278. }
  279. protected string GetAttributeShortName<T>()
  280. where T : Attribute
  281. {
  282. string literalAttribute = typeof(T).Name;
  283. string end = "Attribute";
  284. if (literalAttribute.EndsWith(end))
  285. literalAttribute = literalAttribute.Substring(0, literalAttribute.Length - end.Length);
  286. return literalAttribute;
  287. }
  288. protected AttributeDefinition NewAttributeDefinition<T>()
  289. where T : Attribute
  290. {
  291. return new AttributeDefinition(GetAttributeShortName<T>());
  292. }
  293. protected IDisposable WriteAttributes(CodeWriter writer, params AttributeDefinition[] definitions)
  294. {
  295. var massDisposer = new MassDisposer();
  296. foreach (var definition in definitions)
  297. massDisposer.Disposables.Add(writer.WriteAttribute(definition));
  298. return massDisposer;
  299. }
  300. protected IDisposable WriteAttributes(CodeWriter writer, params string[] definitions)
  301. {
  302. var attributeDefinitions = new List<AttributeDefinition>();
  303. foreach (string definition in definitions)
  304. attributeDefinitions.Add(new AttributeDefinition(definition));
  305. return WriteAttributes(writer, attributeDefinitions.ToArray());
  306. }
  307. protected virtual SpecificationDefinition GetSpecificationDefinition(AccessModifier accessModifier)
  308. {
  309. switch (accessModifier)
  310. {
  311. case AccessModifier.Public:
  312. return SpecificationDefinition.Public;
  313. case AccessModifier.Internal:
  314. return SpecificationDefinition.Internal;
  315. case AccessModifier.Protected:
  316. return SpecificationDefinition.Protected;
  317. case AccessModifier.ProtectedInternal:
  318. return SpecificationDefinition.Protected | SpecificationDefinition.Internal;
  319. case AccessModifier.Private:
  320. return SpecificationDefinition.Private;
  321. default:
  322. throw new ArgumentOutOfRangeException("accessModifier");
  323. }
  324. }
  325. protected virtual SpecificationDefinition GetSpecificationDefinition(ClassModifier classModifier)
  326. {
  327. switch (classModifier)
  328. {
  329. case ClassModifier.Sealed:
  330. return SpecificationDefinition.Sealed;
  331. case ClassModifier.Abstract:
  332. return SpecificationDefinition.Abstract;
  333. default:
  334. throw new ArgumentOutOfRangeException("classModifier");
  335. }
  336. }
  337. protected virtual SpecificationDefinition GetSpecificationDefinition(MemberModifier memberModifier)
  338. {
  339. switch (memberModifier)
  340. {
  341. case MemberModifier.Virtual:
  342. return SpecificationDefinition.Virtual;
  343. case MemberModifier.Override:
  344. return SpecificationDefinition.Override;
  345. case MemberModifier.New:
  346. return SpecificationDefinition.New;
  347. case MemberModifier.NewVirtual:
  348. return SpecificationDefinition.New | SpecificationDefinition.Virtual;
  349. default:
  350. throw new ArgumentOutOfRangeException("memberModifier");
  351. }
  352. }
  353. /// <summary>
  354. /// The "custom types" are types related to a class
  355. /// Currently, we only support enums (non-standard)
  356. /// </summary>
  357. /// <param name="writer"></param>
  358. /// <param name="table"></param>
  359. /// <param name="schema"></param>
  360. /// <param name="context"></param>
  361. protected virtual void WriteCustomTypes(CodeWriter writer, Table table, Database schema, GenerationContext context)
  362. {
  363. // detect required custom types
  364. foreach (var column in table.Type.Columns)
  365. {
  366. var extendedType = column.ExtendedType;
  367. var enumType = extendedType as EnumType;
  368. if (enumType != null)
  369. {
  370. context.ExtendedTypes[column] = new GenerationContext.ExtendedTypeAndName
  371. {
  372. Type = column.ExtendedType,
  373. Table = table
  374. };
  375. }
  376. }
  377. var customTypesNames = new List<string>();
  378. // create names and avoid conflits
  379. foreach (var extendedTypePair in context.ExtendedTypes)
  380. {
  381. if (extendedTypePair.Value.Table != table)
  382. continue;
  383. if (string.IsNullOrEmpty(extendedTypePair.Value.Type.Name))
  384. {
  385. string name = extendedTypePair.Key.Member + "Type";
  386. for (; ; )
  387. {
  388. if ((from t in context.ExtendedTypes.Values where t.Type.Name == name select t).FirstOrDefault() == null)
  389. {
  390. extendedTypePair.Value.Type.Name = name;
  391. break;
  392. }
  393. // at 3rd loop, it will look ugly, however we will never go there
  394. name = extendedTypePair.Value.Table.Type.Name + name;
  395. }
  396. }
  397. customTypesNames.Add(extendedTypePair.Value.Type.Name);
  398. }
  399. // write custom types
  400. if (customTypesNames.Count > 0)
  401. {
  402. using (writer.WriteRegion(string.Format("Custom type definition for {0}", string.Join(", ", customTypesNames.ToArray()))))
  403. {
  404. // write types
  405. foreach (var extendedTypePair in context.ExtendedTypes)
  406. {
  407. if (extendedTypePair.Value.Table != table)
  408. continue;
  409. var extendedType = extendedTypePair.Value.Type;
  410. var enumValue = extendedType as EnumType;
  411. if (enumValue != null)
  412. {
  413. writer.WriteEnum(GetSpecificationDefinition(extendedTypePair.Key.AccessModifier),
  414. enumValue.Name, enumValue);
  415. }
  416. }
  417. }
  418. }
  419. }
  420. }
  421. }