/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs

http://github.com/icsharpcode/ILSpy · C# · 189 lines · 145 code · 21 blank · 23 comment · 20 complexity · e60f28b2646011884fe4d0665dc474ac MD5 · raw file

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Linq;
  21. using ICSharpCode.NRefactory;
  22. using ICSharpCode.NRefactory.TypeSystem;
  23. using Mono.Cecil;
  24. namespace ICSharpCode.Decompiler.Ast
  25. {
  26. /// <summary>
  27. /// ITypeResolveContext implementation that lazily loads types from Cecil.
  28. /// </summary>
  29. public class CecilTypeResolveContext : AbstractAnnotatable, ISynchronizedTypeResolveContext, IProjectContent
  30. {
  31. readonly ModuleDefinition module;
  32. readonly string[] namespaces;
  33. readonly CecilLoader loader;
  34. Dictionary<TypeDefinition, WeakReference> dict = new Dictionary<TypeDefinition, WeakReference>();
  35. int countUntilNextCleanup = 4;
  36. public CecilTypeResolveContext(ModuleDefinition module)
  37. {
  38. this.loader = new CecilLoader();
  39. this.loader.IncludeInternalMembers = true;
  40. this.module = module;
  41. this.namespaces = module.Types.Select(t => t.Namespace).Distinct().ToArray();
  42. List<IAttribute> assemblyAttributes = new List<IAttribute>();
  43. foreach (var attr in module.Assembly.CustomAttributes) {
  44. assemblyAttributes.Add(loader.ReadAttribute(attr));
  45. }
  46. this.AssemblyAttributes = assemblyAttributes.AsReadOnly();
  47. }
  48. ITypeDefinition GetClass(TypeDefinition cecilType)
  49. {
  50. lock (dict) {
  51. WeakReference wr;
  52. ITypeDefinition type;
  53. if (dict.TryGetValue(cecilType, out wr)) {
  54. type = (ITypeDefinition)wr.Target;
  55. } else {
  56. wr = null;
  57. type = null;
  58. }
  59. if (type == null) {
  60. type = loader.LoadType(cecilType, this);
  61. }
  62. if (wr == null) {
  63. if (--countUntilNextCleanup <= 0)
  64. CleanupDict();
  65. wr = new WeakReference(type);
  66. dict.Add(cecilType, wr);
  67. } else {
  68. wr.Target = type;
  69. }
  70. return type;
  71. }
  72. }
  73. void CleanupDict()
  74. {
  75. List<TypeDefinition> deletedKeys = new List<TypeDefinition>();
  76. foreach (var pair in dict) {
  77. if (!pair.Value.IsAlive) {
  78. deletedKeys.Add(pair.Key);
  79. }
  80. }
  81. foreach (var key in deletedKeys) {
  82. dict.Remove(key);
  83. }
  84. countUntilNextCleanup = dict.Count + 4;
  85. }
  86. public string AssemblyName {
  87. get { return module.Assembly.Name.Name; }
  88. }
  89. public IList<IAttribute> ModuleAttributes { get; private set; }
  90. public IList<IAttribute> AssemblyAttributes { get; private set; }
  91. public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer)
  92. {
  93. if (typeParameterCount > 0)
  94. name = name + "`" + typeParameterCount.ToString();
  95. if (nameComparer == StringComparer.Ordinal) {
  96. TypeDefinition cecilType = module.GetType(nameSpace, name);
  97. if (cecilType != null)
  98. return GetClass(cecilType);
  99. else
  100. return null;
  101. }
  102. foreach (TypeDefinition cecilType in module.Types) {
  103. if (nameComparer.Equals(name, cecilType.Name)
  104. && nameComparer.Equals(nameSpace, cecilType.Namespace)
  105. && cecilType.GenericParameters.Count == typeParameterCount)
  106. {
  107. return GetClass(cecilType);
  108. }
  109. }
  110. return null;
  111. }
  112. public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode)
  113. {
  114. return GetTypeDefinition("System", ReflectionHelper.GetShortNameByTypeCode(typeCode), 0, StringComparer.Ordinal);
  115. }
  116. public IEnumerable<ITypeDefinition> GetTypes()
  117. {
  118. foreach (TypeDefinition cecilType in module.Types) {
  119. yield return GetClass(cecilType);
  120. }
  121. }
  122. public IEnumerable<ITypeDefinition> GetTypes(string nameSpace, StringComparer nameComparer)
  123. {
  124. foreach (TypeDefinition cecilType in module.Types) {
  125. if (nameComparer.Equals(nameSpace, cecilType.Namespace))
  126. yield return GetClass(cecilType);
  127. }
  128. }
  129. public IEnumerable<string> GetNamespaces()
  130. {
  131. return namespaces;
  132. }
  133. public string GetNamespace(string nameSpace, StringComparer nameComparer)
  134. {
  135. foreach (string ns in namespaces) {
  136. if (nameComparer.Equals(ns, nameSpace))
  137. return ns;
  138. }
  139. return null;
  140. }
  141. ICSharpCode.NRefactory.Utils.CacheManager ITypeResolveContext.CacheManager {
  142. get {
  143. // We don't support caching
  144. return null;
  145. }
  146. }
  147. ISynchronizedTypeResolveContext ITypeResolveContext.Synchronize()
  148. {
  149. // This class is logically immutable
  150. return this;
  151. }
  152. void IDisposable.Dispose()
  153. {
  154. // exit from Synchronize() block
  155. }
  156. IEnumerable<IParsedFile> IProjectContent.Files {
  157. get { return new IParsedFile[0]; }
  158. }
  159. void IProjectContent.UpdateProjectContent(IParsedFile oldFile, IParsedFile newFile)
  160. {
  161. throw new NotSupportedException();
  162. }
  163. IParsedFile IProjectContent.GetFile(string fileName)
  164. {
  165. return null;
  166. }
  167. }
  168. }