/Mono.Cecil/Mono.Cecil/TypeParser.cs

http://github.com/icsharpcode/ILSpy · C# · 555 lines · 418 code · 110 blank · 27 comment · 87 complexity · ffa7a02e0b7ce7d14ff0eff395881460 MD5 · raw file

  1. //
  2. // TypeParser.cs
  3. //
  4. // Author:
  5. // Jb Evain (jbevain@gmail.com)
  6. //
  7. // Copyright (c) 2008 - 2011 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 System.Text;
  30. using Mono.Cecil.Metadata;
  31. namespace Mono.Cecil {
  32. class TypeParser {
  33. class Type {
  34. public const int Ptr = -1;
  35. public const int ByRef = -2;
  36. public const int SzArray = -3;
  37. public string type_fullname;
  38. public string [] nested_names;
  39. public int arity;
  40. public int [] specs;
  41. public Type [] generic_arguments;
  42. public string assembly;
  43. }
  44. readonly string fullname;
  45. readonly int length;
  46. int position;
  47. TypeParser (string fullname)
  48. {
  49. this.fullname = fullname;
  50. this.length = fullname.Length;
  51. }
  52. Type ParseType (bool fq_name)
  53. {
  54. var type = new Type ();
  55. type.type_fullname = ParsePart ();
  56. type.nested_names = ParseNestedNames ();
  57. if (TryGetArity (type))
  58. type.generic_arguments = ParseGenericArguments (type.arity);
  59. type.specs = ParseSpecs ();
  60. if (fq_name)
  61. type.assembly = ParseAssemblyName ();
  62. return type;
  63. }
  64. static bool TryGetArity (Type type)
  65. {
  66. int arity = 0;
  67. TryAddArity (type.type_fullname, ref arity);
  68. var nested_names = type.nested_names;
  69. if (!nested_names.IsNullOrEmpty ()) {
  70. for (int i = 0; i < nested_names.Length; i++)
  71. TryAddArity (nested_names [i], ref arity);
  72. }
  73. type.arity = arity;
  74. return arity > 0;
  75. }
  76. static bool TryGetArity (string name, out int arity)
  77. {
  78. arity = 0;
  79. var index = name.LastIndexOf ('`');
  80. if (index == -1)
  81. return false;
  82. return ParseInt32 (name.Substring (index + 1), out arity);
  83. }
  84. static bool ParseInt32 (string value, out int result)
  85. {
  86. #if CF
  87. try {
  88. result = int.Parse (value);
  89. return true;
  90. } catch {
  91. result = 0;
  92. return false;
  93. }
  94. #else
  95. return int.TryParse (value, out result);
  96. #endif
  97. }
  98. static void TryAddArity (string name, ref int arity)
  99. {
  100. int type_arity;
  101. if (!TryGetArity (name, out type_arity))
  102. return;
  103. arity += type_arity;
  104. }
  105. string ParsePart ()
  106. {
  107. int start = position;
  108. while (position < length && !IsDelimiter (fullname [position]))
  109. position++;
  110. return fullname.Substring (start, position - start);
  111. }
  112. static bool IsDelimiter (char chr)
  113. {
  114. return "+,[]*&".IndexOf (chr) != -1;
  115. }
  116. void TryParseWhiteSpace ()
  117. {
  118. while (position < length && Char.IsWhiteSpace (fullname [position]))
  119. position++;
  120. }
  121. string [] ParseNestedNames ()
  122. {
  123. string [] nested_names = null;
  124. while (TryParse ('+'))
  125. Add (ref nested_names, ParsePart ());
  126. return nested_names;
  127. }
  128. bool TryParse (char chr)
  129. {
  130. if (position < length && fullname [position] == chr) {
  131. position++;
  132. return true;
  133. }
  134. return false;
  135. }
  136. static void Add<T> (ref T [] array, T item)
  137. {
  138. if (array == null) {
  139. array = new [] { item };
  140. return;
  141. }
  142. #if !CF
  143. Array.Resize (ref array, array.Length + 1);
  144. #else
  145. var copy = new T [array.Length + 1];
  146. Array.Copy (array, copy, array.Length);
  147. array = copy;
  148. #endif
  149. array [array.Length - 1] = item;
  150. }
  151. int [] ParseSpecs ()
  152. {
  153. int [] specs = null;
  154. while (position < length) {
  155. switch (fullname [position]) {
  156. case '*':
  157. position++;
  158. Add (ref specs, Type.Ptr);
  159. break;
  160. case '&':
  161. position++;
  162. Add (ref specs, Type.ByRef);
  163. break;
  164. case '[':
  165. position++;
  166. switch (fullname [position]) {
  167. case ']':
  168. position++;
  169. Add (ref specs, Type.SzArray);
  170. break;
  171. case '*':
  172. position++;
  173. Add (ref specs, 1);
  174. break;
  175. default:
  176. var rank = 1;
  177. while (TryParse (','))
  178. rank++;
  179. Add (ref specs, rank);
  180. TryParse (']');
  181. break;
  182. }
  183. break;
  184. default:
  185. return specs;
  186. }
  187. }
  188. return specs;
  189. }
  190. Type [] ParseGenericArguments (int arity)
  191. {
  192. Type [] generic_arguments = null;
  193. if (position == length || fullname [position] != '[')
  194. return generic_arguments;
  195. TryParse ('[');
  196. for (int i = 0; i < arity; i++) {
  197. var fq_argument = TryParse ('[');
  198. Add (ref generic_arguments, ParseType (fq_argument));
  199. if (fq_argument)
  200. TryParse (']');
  201. TryParse (',');
  202. TryParseWhiteSpace ();
  203. }
  204. TryParse (']');
  205. return generic_arguments;
  206. }
  207. string ParseAssemblyName ()
  208. {
  209. if (!TryParse (','))
  210. return string.Empty;
  211. TryParseWhiteSpace ();
  212. var start = position;
  213. while (position < length) {
  214. var chr = fullname [position];
  215. if (chr == '[' || chr == ']')
  216. break;
  217. position++;
  218. }
  219. return fullname.Substring (start, position - start);
  220. }
  221. public static TypeReference ParseType (ModuleDefinition module, string fullname)
  222. {
  223. if (string.IsNullOrEmpty (fullname))
  224. return null;
  225. var parser = new TypeParser (fullname);
  226. return GetTypeReference (module, parser.ParseType (true));
  227. }
  228. static TypeReference GetTypeReference (ModuleDefinition module, Type type_info)
  229. {
  230. TypeReference type;
  231. if (!TryGetDefinition (module, type_info, out type))
  232. type = CreateReference (type_info, module, GetMetadataScope (module, type_info));
  233. return CreateSpecs (type, type_info);
  234. }
  235. static TypeReference CreateSpecs (TypeReference type, Type type_info)
  236. {
  237. type = TryCreateGenericInstanceType (type, type_info);
  238. var specs = type_info.specs;
  239. if (specs.IsNullOrEmpty ())
  240. return type;
  241. for (int i = 0; i < specs.Length; i++) {
  242. switch (specs [i]) {
  243. case Type.Ptr:
  244. type = new PointerType (type);
  245. break;
  246. case Type.ByRef:
  247. type = new ByReferenceType (type);
  248. break;
  249. case Type.SzArray:
  250. type = new ArrayType (type);
  251. break;
  252. default:
  253. var array = new ArrayType (type);
  254. array.Dimensions.Clear ();
  255. for (int j = 0; j < specs [i]; j++)
  256. array.Dimensions.Add (new ArrayDimension ());
  257. type = array;
  258. break;
  259. }
  260. }
  261. return type;
  262. }
  263. static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info)
  264. {
  265. var generic_arguments = type_info.generic_arguments;
  266. if (generic_arguments.IsNullOrEmpty ())
  267. return type;
  268. var instance = new GenericInstanceType (type);
  269. var instance_arguments = instance.GenericArguments;
  270. for (int i = 0; i < generic_arguments.Length; i++)
  271. instance_arguments.Add (GetTypeReference (type.Module, generic_arguments [i]));
  272. return instance;
  273. }
  274. public static void SplitFullName (string fullname, out string @namespace, out string name)
  275. {
  276. var last_dot = fullname.LastIndexOf ('.');
  277. if (last_dot == -1) {
  278. @namespace = string.Empty;
  279. name = fullname;
  280. } else {
  281. @namespace = fullname.Substring (0, last_dot);
  282. name = fullname.Substring (last_dot + 1);
  283. }
  284. }
  285. static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope)
  286. {
  287. string @namespace, name;
  288. SplitFullName (type_info.type_fullname, out @namespace, out name);
  289. var type = new TypeReference (@namespace, name, module, scope);
  290. MetadataSystem.TryProcessPrimitiveTypeReference (type);
  291. AdjustGenericParameters (type);
  292. var nested_names = type_info.nested_names;
  293. if (nested_names.IsNullOrEmpty ())
  294. return type;
  295. for (int i = 0; i < nested_names.Length; i++) {
  296. type = new TypeReference (string.Empty, nested_names [i], module, null) {
  297. DeclaringType = type,
  298. };
  299. AdjustGenericParameters (type);
  300. }
  301. return type;
  302. }
  303. static void AdjustGenericParameters (TypeReference type)
  304. {
  305. int arity;
  306. if (!TryGetArity (type.Name, out arity))
  307. return;
  308. for (int i = 0; i < arity; i++)
  309. type.GenericParameters.Add (new GenericParameter (type));
  310. }
  311. static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info)
  312. {
  313. if (string.IsNullOrEmpty (type_info.assembly))
  314. return module.TypeSystem.Corlib;
  315. return MatchReference (module, AssemblyNameReference.Parse (type_info.assembly));
  316. }
  317. static AssemblyNameReference MatchReference (ModuleDefinition module, AssemblyNameReference pattern)
  318. {
  319. var references = module.AssemblyReferences;
  320. for (int i = 0; i < references.Count; i++) {
  321. var reference = references [i];
  322. if (reference.FullName == pattern.FullName)
  323. return reference;
  324. }
  325. return pattern;
  326. }
  327. static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type)
  328. {
  329. type = null;
  330. if (!TryCurrentModule (module, type_info))
  331. return false;
  332. var typedef = module.GetType (type_info.type_fullname);
  333. if (typedef == null)
  334. return false;
  335. var nested_names = type_info.nested_names;
  336. if (!nested_names.IsNullOrEmpty ()) {
  337. for (int i = 0; i < nested_names.Length; i++)
  338. typedef = typedef.GetNestedType (nested_names [i]);
  339. }
  340. type = typedef;
  341. return true;
  342. }
  343. static bool TryCurrentModule (ModuleDefinition module, Type type_info)
  344. {
  345. if (string.IsNullOrEmpty (type_info.assembly))
  346. return true;
  347. if (module.assembly != null && module.assembly.Name.FullName == type_info.assembly)
  348. return true;
  349. return false;
  350. }
  351. public static string ToParseable (TypeReference type)
  352. {
  353. if (type == null)
  354. return null;
  355. var name = new StringBuilder ();
  356. AppendType (type, name, true, true);
  357. return name.ToString ();
  358. }
  359. static void AppendType (TypeReference type, StringBuilder name, bool fq_name, bool top_level)
  360. {
  361. var declaring_type = type.DeclaringType;
  362. if (declaring_type != null) {
  363. AppendType (declaring_type, name, false, top_level);
  364. name.Append ('+');
  365. }
  366. var @namespace = type.Namespace;
  367. if (!string.IsNullOrEmpty (@namespace)) {
  368. name.Append (@namespace);
  369. name.Append ('.');
  370. }
  371. name.Append (type.GetElementType ().Name);
  372. if (!fq_name)
  373. return;
  374. if (type.IsTypeSpecification ())
  375. AppendTypeSpecification ((TypeSpecification) type, name);
  376. if (RequiresFullyQualifiedName (type, top_level)) {
  377. name.Append (", ");
  378. name.Append (GetScopeFullName (type));
  379. }
  380. }
  381. static string GetScopeFullName (TypeReference type)
  382. {
  383. var scope = type.Scope;
  384. switch (scope.MetadataScopeType) {
  385. case MetadataScopeType.AssemblyNameReference:
  386. return ((AssemblyNameReference) scope).FullName;
  387. case MetadataScopeType.ModuleDefinition:
  388. return ((ModuleDefinition) scope).Assembly.Name.FullName;
  389. }
  390. throw new ArgumentException ();
  391. }
  392. static void AppendTypeSpecification (TypeSpecification type, StringBuilder name)
  393. {
  394. if (type.ElementType.IsTypeSpecification ())
  395. AppendTypeSpecification ((TypeSpecification) type.ElementType, name);
  396. switch (type.etype) {
  397. case ElementType.Ptr:
  398. name.Append ('*');
  399. break;
  400. case ElementType.ByRef:
  401. name.Append ('&');
  402. break;
  403. case ElementType.SzArray:
  404. case ElementType.Array:
  405. var array = (ArrayType) type;
  406. if (array.IsVector) {
  407. name.Append ("[]");
  408. } else {
  409. name.Append ('[');
  410. for (int i = 1; i < array.Rank; i++)
  411. name.Append (',');
  412. name.Append (']');
  413. }
  414. break;
  415. case ElementType.GenericInst:
  416. var instance = (GenericInstanceType) type;
  417. var arguments = instance.GenericArguments;
  418. name.Append ('[');
  419. for (int i = 0; i < arguments.Count; i++) {
  420. if (i > 0)
  421. name.Append (',');
  422. var argument = arguments [i];
  423. var requires_fqname = argument.Scope != argument.Module;
  424. if (requires_fqname)
  425. name.Append ('[');
  426. AppendType (argument, name, true, false);
  427. if (requires_fqname)
  428. name.Append (']');
  429. }
  430. name.Append (']');
  431. break;
  432. default:
  433. return;
  434. }
  435. }
  436. static bool RequiresFullyQualifiedName (TypeReference type, bool top_level)
  437. {
  438. if (type.Scope == type.Module)
  439. return false;
  440. if (type.Scope.Name == "mscorlib" && top_level)
  441. return false;
  442. return true;
  443. }
  444. }
  445. }