PageRenderTime 35ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/tools/linker/Mono.Linker/TypeParser.cs

https://bitbucket.org/puffnfresh/mono-dependency-analysis
C# | 444 lines | 325 code | 92 blank | 27 comment | 72 complexity | 417958d212cf956bf84ccad030cf375a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, Unlicense, Apache-2.0, LGPL-2.0
  1. //
  2. // TypeParser.cs
  3. //
  4. // Author:
  5. // Jb Evain (jbevain@gmail.com)
  6. //
  7. // Copyright (c) 2008 - 2010 Jb Evain
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using Mono.Cecil;
  30. namespace Mono.Linker {
  31. class TypeParser {
  32. class Type {
  33. public const int Ptr = -1;
  34. public const int ByRef = -2;
  35. public const int SzArray = -3;
  36. public string type_fullname;
  37. public string [] nested_names;
  38. public int arity;
  39. public int [] specs;
  40. public Type [] generic_arguments;
  41. public string assembly;
  42. }
  43. readonly string fullname;
  44. readonly int length;
  45. int position;
  46. TypeParser (string fullname)
  47. {
  48. this.fullname = fullname;
  49. this.length = fullname.Length;
  50. }
  51. Type ParseType (bool fq_name)
  52. {
  53. var type = new Type ();
  54. type.type_fullname = ParsePart ();
  55. type.nested_names = ParseNestedNames ();
  56. if (TryGetArity (type))
  57. type.generic_arguments = ParseGenericArguments (type.arity);
  58. type.specs = ParseSpecs ();
  59. if (fq_name)
  60. type.assembly = ParseAssemblyName ();
  61. return type;
  62. }
  63. static bool TryGetArity (Type type)
  64. {
  65. int arity = 0;
  66. TryAddArity (type.type_fullname, ref arity);
  67. var nested_names = type.nested_names;
  68. if (!IsNullOrEmpty (nested_names)) {
  69. for (int i = 0; i < nested_names.Length; i++)
  70. TryAddArity (nested_names [i], ref arity);
  71. }
  72. type.arity = arity;
  73. return arity > 0;
  74. }
  75. static bool TryGetArity (string name, out int arity)
  76. {
  77. arity = 0;
  78. var index = name.LastIndexOf ('`');
  79. if (index == -1)
  80. return false;
  81. return int.TryParse (name.Substring (index + 1), out arity);
  82. }
  83. static void TryAddArity (string name, ref int arity)
  84. {
  85. int type_arity;
  86. if (!TryGetArity (name, out type_arity))
  87. return;
  88. arity += type_arity;
  89. }
  90. string ParsePart ()
  91. {
  92. int start = position;
  93. while (position < length && !IsDelimiter (fullname [position]))
  94. position++;
  95. return fullname.Substring (start, position - start);
  96. }
  97. static bool IsDelimiter (char chr)
  98. {
  99. return "+,[]*&".IndexOf (chr) != -1;
  100. }
  101. void TryParseWhiteSpace ()
  102. {
  103. while (position < length && Char.IsWhiteSpace (fullname [position]))
  104. position++;
  105. }
  106. string [] ParseNestedNames ()
  107. {
  108. string [] nested_names = null;
  109. while (TryParse ('+'))
  110. Add (ref nested_names, ParsePart ());
  111. return nested_names;
  112. }
  113. bool TryParse (char chr)
  114. {
  115. if (position < length && fullname [position] == chr) {
  116. position++;
  117. return true;
  118. }
  119. return false;
  120. }
  121. static void Add<T> (ref T [] array, T item)
  122. {
  123. if (array == null) {
  124. array = new [] { item };
  125. return;
  126. }
  127. Array.Resize (ref array, array.Length + 1);
  128. array [array.Length - 1] = item;
  129. }
  130. int [] ParseSpecs ()
  131. {
  132. int [] specs = null;
  133. while (position < length) {
  134. switch (fullname [position]) {
  135. case '*':
  136. position++;
  137. Add (ref specs, Type.Ptr);
  138. break;
  139. case '&':
  140. position++;
  141. Add (ref specs, Type.ByRef);
  142. break;
  143. case '[':
  144. position++;
  145. switch (fullname [position]) {
  146. case ']':
  147. position++;
  148. Add (ref specs, Type.SzArray);
  149. break;
  150. case '*':
  151. position++;
  152. Add (ref specs, 1);
  153. break;
  154. default:
  155. var rank = 1;
  156. while (TryParse (','))
  157. rank++;
  158. Add (ref specs, rank);
  159. TryParse (']');
  160. break;
  161. }
  162. break;
  163. default:
  164. return specs;
  165. }
  166. }
  167. return specs;
  168. }
  169. Type [] ParseGenericArguments (int arity)
  170. {
  171. Type [] generic_arguments = null;
  172. if (position == length || fullname [position] != '[')
  173. return generic_arguments;
  174. TryParse ('[');
  175. for (int i = 0; i < arity; i++) {
  176. var fq_argument = TryParse ('[');
  177. Add (ref generic_arguments, ParseType (fq_argument));
  178. if (fq_argument)
  179. TryParse (']');
  180. TryParse (',');
  181. TryParseWhiteSpace ();
  182. }
  183. TryParse (']');
  184. return generic_arguments;
  185. }
  186. string ParseAssemblyName ()
  187. {
  188. if (!TryParse (','))
  189. return string.Empty;
  190. TryParseWhiteSpace ();
  191. var start = position;
  192. while (position < length) {
  193. var chr = fullname [position];
  194. if (chr == '[' || chr == ']')
  195. break;
  196. position++;
  197. }
  198. return fullname.Substring (start, position - start);
  199. }
  200. public static TypeReference ParseType (ModuleDefinition module, string fullname)
  201. {
  202. if (fullname == null)
  203. return null;
  204. var parser = new TypeParser (fullname);
  205. return GetTypeReference (module, parser.ParseType (true));
  206. }
  207. static TypeReference GetTypeReference (ModuleDefinition module, Type type_info)
  208. {
  209. TypeReference type;
  210. if (!TryGetDefinition (module, type_info, out type))
  211. type = CreateReference (type_info, module, GetMetadataScope (module, type_info));
  212. return CreateSpecs (type, type_info);
  213. }
  214. static TypeReference CreateSpecs (TypeReference type, Type type_info)
  215. {
  216. type = TryCreateGenericInstanceType (type, type_info);
  217. var specs = type_info.specs;
  218. if (IsNullOrEmpty (specs))
  219. return type;
  220. for (int i = 0; i < specs.Length; i++) {
  221. switch (specs [i]) {
  222. case Type.Ptr:
  223. type = new PointerType (type);
  224. break;
  225. case Type.ByRef:
  226. type = new ReferenceType (type);
  227. break;
  228. case Type.SzArray:
  229. type = new ArrayType (type);
  230. break;
  231. default:
  232. var array = new ArrayType (type);
  233. array.Dimensions.Clear ();
  234. for (int j = 0; j < specs [i]; j++)
  235. array.Dimensions.Add (new ArrayDimension (0, 0));
  236. type = array;
  237. break;
  238. }
  239. }
  240. return type;
  241. }
  242. static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info)
  243. {
  244. var generic_arguments = type_info.generic_arguments;
  245. if (IsNullOrEmpty (generic_arguments))
  246. return type;
  247. var instance = new GenericInstanceType (type);
  248. for (int i = 0; i < generic_arguments.Length; i++)
  249. instance.GenericArguments.Add (GetTypeReference (type.Module, generic_arguments [i]));
  250. return instance;
  251. }
  252. public static void SplitFullName (string fullname, out string @namespace, out string name)
  253. {
  254. var last_dot = fullname.LastIndexOf ('.');
  255. if (last_dot == -1) {
  256. @namespace = string.Empty;
  257. name = fullname;
  258. } else {
  259. @namespace = fullname.Substring (0, last_dot);
  260. name = fullname.Substring (last_dot + 1);
  261. }
  262. }
  263. static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope)
  264. {
  265. string @namespace, name;
  266. SplitFullName (type_info.type_fullname, out @namespace, out name);
  267. var type = new TypeReference (name, @namespace, scope, false) {
  268. Module = module,
  269. };
  270. AdjustGenericParameters (type);
  271. var nested_names = type_info.nested_names;
  272. if (IsNullOrEmpty (nested_names))
  273. return type;
  274. for (int i = 0; i < nested_names.Length; i++) {
  275. type = new TypeReference (nested_names [i], string.Empty, null, false) {
  276. DeclaringType = type,
  277. Module = module,
  278. };
  279. AdjustGenericParameters (type);
  280. }
  281. return type;
  282. }
  283. static void AdjustGenericParameters (TypeReference type)
  284. {
  285. int arity;
  286. if (!TryGetArity (type.Name, out arity))
  287. return;
  288. for (int i = 0; i < arity; i++)
  289. type.GenericParameters.Add (new GenericParameter (null, type));
  290. }
  291. static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info)
  292. {
  293. if (string.IsNullOrEmpty (type_info.assembly))
  294. return GetCorlib (module);
  295. return MatchReference (module, AssemblyNameReference.Parse (type_info.assembly));
  296. }
  297. static AssemblyNameReference GetCorlib (ModuleDefinition module)
  298. {
  299. foreach (AssemblyNameReference reference in module.AssemblyReferences)
  300. if (reference.Name == "mscorlib")
  301. return reference;
  302. return null;
  303. }
  304. static AssemblyNameReference MatchReference (ModuleDefinition module, AssemblyNameReference pattern)
  305. {
  306. var references = module.AssemblyReferences;
  307. for (int i = 0; i < references.Count; i++) {
  308. var reference = references [i];
  309. if (reference.FullName == pattern.FullName)
  310. return reference;
  311. }
  312. return pattern;
  313. }
  314. static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type)
  315. {
  316. type = null;
  317. if (!TryCurrentModule (module, type_info))
  318. return false;
  319. var typedef = module.Types [type_info.type_fullname];
  320. if (typedef == null)
  321. return false;
  322. var nested_names = type_info.nested_names;
  323. if (!IsNullOrEmpty (nested_names)) {
  324. for (int i = 0; i < nested_names.Length; i++)
  325. typedef = GetNestedType (typedef, nested_names [i]);
  326. }
  327. type = typedef;
  328. return true;
  329. }
  330. static bool TryCurrentModule (ModuleDefinition module, Type type_info)
  331. {
  332. if (string.IsNullOrEmpty (type_info.assembly))
  333. return true;
  334. if (module.Assembly != null && module.Assembly.Name.FullName == type_info.assembly)
  335. return true;
  336. return false;
  337. }
  338. static TypeDefinition GetNestedType (TypeDefinition type, string nestedTypeName)
  339. {
  340. if (!type.HasNestedTypes)
  341. return null;
  342. foreach (TypeDefinition nested_type in type.NestedTypes)
  343. if (nested_type.Name == nestedTypeName)
  344. return nested_type;
  345. return null;
  346. }
  347. static bool IsNullOrEmpty<T> (T [] array)
  348. {
  349. return array == null || array.Length == 0;
  350. }
  351. }
  352. }