PageRenderTime 51ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/ICSharpCode.Decompiler/Ast/AstBuilder.cs

http://github.com/icsharpcode/ILSpy
C# | 1700 lines | 1460 code | 153 blank | 87 comment | 569 complexity | 50910808915b0c926ccbcfa8436d2756 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-SA-3.0
  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.Concurrent;
  20. using System.Collections.Generic;
  21. using System.Collections.ObjectModel;
  22. using System.Diagnostics;
  23. using System.IO;
  24. using System.Linq;
  25. using System.Runtime.CompilerServices;
  26. using System.Runtime.InteropServices;
  27. using System.Threading;
  28. using ICSharpCode.Decompiler;
  29. using ICSharpCode.Decompiler.Ast.Transforms;
  30. using ICSharpCode.Decompiler.ILAst;
  31. using ICSharpCode.NRefactory.CSharp;
  32. using ICSharpCode.NRefactory.Utils;
  33. using Mono.Cecil;
  34. using Mono.Cecil.Cil;
  35. namespace ICSharpCode.Decompiler.Ast
  36. {
  37. using Ast = ICSharpCode.NRefactory.CSharp;
  38. using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
  39. [Flags]
  40. public enum ConvertTypeOptions
  41. {
  42. None = 0,
  43. IncludeNamespace = 1,
  44. IncludeTypeParameterDefinitions = 2,
  45. DoNotUsePrimitiveTypeNames = 4
  46. }
  47. public class AstBuilder
  48. {
  49. DecompilerContext context;
  50. SyntaxTree syntaxTree = new SyntaxTree();
  51. Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
  52. bool transformationsHaveRun;
  53. public AstBuilder(DecompilerContext context)
  54. {
  55. if (context == null)
  56. throw new ArgumentNullException("context");
  57. this.context = context;
  58. this.DecompileMethodBodies = true;
  59. }
  60. public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
  61. {
  62. MethodDefinition method = member as MethodDefinition;
  63. if (method != null) {
  64. if (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn)
  65. return true;
  66. if (settings.AnonymousMethods && method.HasGeneratedName() && method.IsCompilerGenerated())
  67. return true;
  68. }
  69. TypeDefinition type = member as TypeDefinition;
  70. if (type != null) {
  71. if (type.DeclaringType != null) {
  72. if (settings.AnonymousMethods && IsClosureType(type))
  73. return true;
  74. if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(type))
  75. return true;
  76. if (settings.AsyncAwait && AsyncDecompiler.IsCompilerGeneratedStateMachine(type))
  77. return true;
  78. } else if (type.IsCompilerGenerated()) {
  79. if (type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
  80. return true;
  81. if (type.IsAnonymousType())
  82. return true;
  83. }
  84. }
  85. FieldDefinition field = member as FieldDefinition;
  86. if (field != null) {
  87. if (field.IsCompilerGenerated()) {
  88. if (settings.AnonymousMethods && IsAnonymousMethodCacheField(field))
  89. return true;
  90. if (settings.AutomaticProperties && IsAutomaticPropertyBackingField(field))
  91. return true;
  92. if (settings.SwitchStatementOnString && IsSwitchOnStringCache(field))
  93. return true;
  94. }
  95. // event-fields are not [CompilerGenerated]
  96. if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
  97. return true;
  98. }
  99. return false;
  100. }
  101. static bool IsSwitchOnStringCache(FieldDefinition field)
  102. {
  103. return field.Name.StartsWith("<>f__switch", StringComparison.Ordinal);
  104. }
  105. static bool IsAutomaticPropertyBackingField(FieldDefinition field)
  106. {
  107. return field.HasGeneratedName() && field.Name.EndsWith("BackingField", StringComparison.Ordinal);
  108. }
  109. static bool IsAnonymousMethodCacheField(FieldDefinition field)
  110. {
  111. return field.Name.StartsWith("CS$<>", StringComparison.Ordinal) || field.Name.StartsWith("<>f__am", StringComparison.Ordinal);
  112. }
  113. static bool IsClosureType(TypeDefinition type)
  114. {
  115. return type.HasGeneratedName() && type.IsCompilerGenerated() && (type.Name.Contains("DisplayClass") || type.Name.Contains("AnonStorey"));
  116. }
  117. /// <summary>
  118. /// Runs the C# transformations on the compilation unit.
  119. /// </summary>
  120. public void RunTransformations()
  121. {
  122. RunTransformations(null);
  123. }
  124. public void RunTransformations(Predicate<IAstTransform> transformAbortCondition)
  125. {
  126. TransformationPipeline.RunTransformationsUntil(syntaxTree, transformAbortCondition, context);
  127. transformationsHaveRun = true;
  128. }
  129. /// <summary>
  130. /// Gets the abstract source tree.
  131. /// </summary>
  132. public SyntaxTree SyntaxTree {
  133. get { return syntaxTree; }
  134. }
  135. /// <summary>
  136. /// Generates C# code from the abstract source tree.
  137. /// </summary>
  138. /// <remarks>This method adds ParenthesizedExpressions into the AST, and will run transformations if <see cref="RunTransformations"/> was not called explicitly</remarks>
  139. public void GenerateCode(ITextOutput output)
  140. {
  141. if (!transformationsHaveRun)
  142. RunTransformations();
  143. syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
  144. var outputFormatter = new TextTokenWriter(output, context) { FoldBraces = context.Settings.FoldBraces };
  145. var formattingPolicy = context.Settings.CSharpFormattingOptions;
  146. syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy));
  147. }
  148. public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
  149. {
  150. AddAssembly(assemblyDefinition.MainModule, onlyAssemblyLevel);
  151. }
  152. public void AddAssembly(ModuleDefinition moduleDefinition, bool onlyAssemblyLevel = false)
  153. {
  154. if (moduleDefinition.Assembly != null && moduleDefinition.Assembly.Name.Version != null) {
  155. syntaxTree.AddChild(
  156. new AttributeSection {
  157. AttributeTarget = "assembly",
  158. Attributes = {
  159. new NRefactory.CSharp.Attribute {
  160. Type = new SimpleType("AssemblyVersion")
  161. .WithAnnotation(new TypeReference(
  162. "System.Reflection", "AssemblyVersionAttribute",
  163. moduleDefinition, moduleDefinition.TypeSystem.CoreLibrary)),
  164. Arguments = {
  165. new PrimitiveExpression(moduleDefinition.Assembly.Name.Version.ToString())
  166. }
  167. }
  168. }
  169. }, EntityDeclaration.AttributeRole);
  170. }
  171. if (moduleDefinition.Assembly != null) {
  172. ConvertCustomAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
  173. ConvertSecurityAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
  174. }
  175. ConvertCustomAttributes(syntaxTree, moduleDefinition, "module");
  176. AddTypeForwarderAttributes(syntaxTree, moduleDefinition, "assembly");
  177. if (!onlyAssemblyLevel) {
  178. foreach (TypeDefinition typeDef in moduleDefinition.Types) {
  179. // Skip the <Module> class
  180. if (typeDef.Name == "<Module>") continue;
  181. // Skip any hidden types
  182. if (AstBuilder.MemberIsHidden(typeDef, context.Settings))
  183. continue;
  184. AddType(typeDef);
  185. }
  186. }
  187. }
  188. void AddTypeForwarderAttributes(SyntaxTree astCompileUnit, ModuleDefinition module, string target)
  189. {
  190. if (!module.HasExportedTypes)
  191. return;
  192. foreach (ExportedType type in module.ExportedTypes) {
  193. if (type.IsForwarder) {
  194. var forwardedType = CreateTypeOfExpression(new TypeReference(type.Namespace, type.Name, module, type.Scope));
  195. astCompileUnit.AddChild(
  196. new AttributeSection {
  197. AttributeTarget = target,
  198. Attributes = {
  199. new NRefactory.CSharp.Attribute {
  200. Type = new SimpleType("TypeForwardedTo")
  201. .WithAnnotation(new TypeReference(
  202. "System.Runtime.CompilerServices", "TypeForwardedToAttribute",
  203. module, module.TypeSystem.CoreLibrary)),
  204. Arguments = { forwardedType }
  205. }
  206. }
  207. }, EntityDeclaration.AttributeRole);
  208. }
  209. }
  210. }
  211. NamespaceDeclaration GetCodeNamespace(string name)
  212. {
  213. if (string.IsNullOrEmpty(name)) {
  214. return null;
  215. }
  216. if (astNamespaces.ContainsKey(name)) {
  217. return astNamespaces[name];
  218. } else {
  219. // Create the namespace
  220. NamespaceDeclaration astNamespace = new NamespaceDeclaration { Name = name };
  221. syntaxTree.Members.Add(astNamespace);
  222. astNamespaces[name] = astNamespace;
  223. return astNamespace;
  224. }
  225. }
  226. public void AddType(TypeDefinition typeDef)
  227. {
  228. var astType = CreateType(typeDef);
  229. NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
  230. if (astNS != null) {
  231. astNS.Members.Add(astType);
  232. } else {
  233. syntaxTree.Members.Add(astType);
  234. }
  235. }
  236. public void AddMethod(MethodDefinition method)
  237. {
  238. AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
  239. syntaxTree.Members.Add(node);
  240. }
  241. public void AddProperty(PropertyDefinition property)
  242. {
  243. syntaxTree.Members.Add(CreateProperty(property));
  244. }
  245. public void AddField(FieldDefinition field)
  246. {
  247. syntaxTree.Members.Add(CreateField(field));
  248. }
  249. public void AddEvent(EventDefinition ev)
  250. {
  251. syntaxTree.Members.Add(CreateEvent(ev));
  252. }
  253. /// <summary>
  254. /// Creates the AST for a type definition.
  255. /// </summary>
  256. /// <param name="typeDef"></param>
  257. /// <returns>TypeDeclaration or DelegateDeclaration.</returns>
  258. public EntityDeclaration CreateType(TypeDefinition typeDef)
  259. {
  260. // create type
  261. TypeDefinition oldCurrentType = context.CurrentType;
  262. context.CurrentType = typeDef;
  263. TypeDeclaration astType = new TypeDeclaration();
  264. ConvertAttributes(astType, typeDef);
  265. astType.AddAnnotation(typeDef);
  266. astType.Modifiers = ConvertModifiers(typeDef);
  267. astType.Name = CleanName(typeDef.Name);
  268. if (typeDef.IsEnum) { // NB: Enum is value type
  269. astType.ClassType = ClassType.Enum;
  270. astType.Modifiers &= ~Modifiers.Sealed;
  271. } else if (typeDef.IsValueType) {
  272. astType.ClassType = ClassType.Struct;
  273. astType.Modifiers &= ~Modifiers.Sealed;
  274. } else if (typeDef.IsInterface) {
  275. astType.ClassType = ClassType.Interface;
  276. astType.Modifiers &= ~Modifiers.Abstract;
  277. } else {
  278. astType.ClassType = ClassType.Class;
  279. }
  280. IEnumerable<GenericParameter> genericParameters = typeDef.GenericParameters;
  281. if (typeDef.DeclaringType != null && typeDef.DeclaringType.HasGenericParameters)
  282. genericParameters = genericParameters.Skip(typeDef.DeclaringType.GenericParameters.Count);
  283. astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters));
  284. astType.Constraints.AddRange(MakeConstraints(genericParameters));
  285. EntityDeclaration result = astType;
  286. if (typeDef.IsEnum) {
  287. long expectedEnumMemberValue = 0;
  288. bool forcePrintingInitializers = IsFlagsEnum(typeDef);
  289. TypeCode baseType = TypeCode.Int32;
  290. foreach (FieldDefinition field in typeDef.Fields) {
  291. if (!field.IsStatic) {
  292. // the value__ field
  293. if (field.FieldType != typeDef.Module.TypeSystem.Int32) {
  294. astType.AddChild(ConvertType(field.FieldType), Roles.BaseType);
  295. baseType = TypeAnalysis.GetTypeCode(field.FieldType);
  296. }
  297. } else {
  298. EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
  299. ConvertCustomAttributes(enumMember, field);
  300. enumMember.AddAnnotation(field);
  301. enumMember.Name = CleanName(field.Name);
  302. long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
  303. if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) {
  304. enumMember.AddChild(new PrimitiveExpression(CSharpPrimitiveCast.Cast(baseType, field.Constant, false)), EnumMemberDeclaration.InitializerRole);
  305. }
  306. expectedEnumMemberValue = memberValue + 1;
  307. astType.AddChild(enumMember, Roles.TypeMemberRole);
  308. }
  309. }
  310. } else if (typeDef.BaseType != null && typeDef.BaseType.FullName == "System.MulticastDelegate") {
  311. DelegateDeclaration dd = new DelegateDeclaration();
  312. dd.Modifiers = astType.Modifiers & ~Modifiers.Sealed;
  313. dd.Name = astType.Name;
  314. dd.AddAnnotation(typeDef);
  315. astType.Attributes.MoveTo(dd.Attributes);
  316. astType.TypeParameters.MoveTo(dd.TypeParameters);
  317. astType.Constraints.MoveTo(dd.Constraints);
  318. foreach (var m in typeDef.Methods) {
  319. if (m.Name == "Invoke") {
  320. dd.ReturnType = ConvertType(m.ReturnType, m.MethodReturnType);
  321. dd.Parameters.AddRange(MakeParameters(m));
  322. ConvertAttributes(dd, m.MethodReturnType, m.Module);
  323. }
  324. }
  325. result = dd;
  326. } else {
  327. // Base type
  328. if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != "System.Object") {
  329. astType.AddChild(ConvertType(typeDef.BaseType), Roles.BaseType);
  330. }
  331. foreach (var i in typeDef.Interfaces)
  332. astType.AddChild(ConvertType(i), Roles.BaseType);
  333. AddTypeMembers(astType, typeDef);
  334. if (astType.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType.IsNull)) {
  335. // Remove the [DefaultMember] attribute if the class contains indexers
  336. foreach (AttributeSection section in astType.Attributes) {
  337. foreach (Ast.Attribute attr in section.Attributes) {
  338. TypeReference tr = attr.Type.Annotation<TypeReference>();
  339. if (tr != null && tr.Name == "DefaultMemberAttribute" && tr.Namespace == "System.Reflection") {
  340. attr.Remove();
  341. }
  342. }
  343. if (section.Attributes.Count == 0)
  344. section.Remove();
  345. }
  346. }
  347. }
  348. context.CurrentType = oldCurrentType;
  349. return result;
  350. }
  351. internal static string CleanName(string name)
  352. {
  353. int pos = name.LastIndexOf('`');
  354. if (pos >= 0)
  355. name = name.Substring(0, pos);
  356. pos = name.LastIndexOf('.');
  357. if (pos >= 0)
  358. name = name.Substring(pos + 1);
  359. return name;
  360. }
  361. #region Create TypeOf Expression
  362. /// <summary>
  363. /// Creates a typeof-expression for the specified type.
  364. /// </summary>
  365. public static TypeOfExpression CreateTypeOfExpression(TypeReference type)
  366. {
  367. return new TypeOfExpression(AddEmptyTypeArgumentsForUnboundGenerics(ConvertType(type)));
  368. }
  369. static AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type)
  370. {
  371. TypeReference typeRef = type.Annotation<TypeReference>();
  372. if (typeRef == null)
  373. return type;
  374. TypeDefinition typeDef = typeRef.Resolve(); // need to resolve to figure out the number of type parameters
  375. if (typeDef == null || !typeDef.HasGenericParameters)
  376. return type;
  377. SimpleType sType = type as SimpleType;
  378. MemberType mType = type as MemberType;
  379. if (sType != null) {
  380. while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) {
  381. sType.TypeArguments.Add(new SimpleType(""));
  382. }
  383. }
  384. if (mType != null) {
  385. AddEmptyTypeArgumentsForUnboundGenerics(mType.Target);
  386. int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count;
  387. while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) {
  388. mType.TypeArguments.Add(new SimpleType(""));
  389. }
  390. }
  391. return type;
  392. }
  393. #endregion
  394. #region Convert Type Reference
  395. /// <summary>
  396. /// Converts a type reference.
  397. /// </summary>
  398. /// <param name="type">The Cecil type reference that should be converted into
  399. /// a type system type reference.</param>
  400. /// <param name="typeAttributes">Attributes associated with the Cecil type reference.
  401. /// This is used to support the 'dynamic' type.</param>
  402. public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null, ConvertTypeOptions options = ConvertTypeOptions.None)
  403. {
  404. int typeIndex = 0;
  405. return ConvertType(type, typeAttributes, ref typeIndex, options);
  406. }
  407. static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex, ConvertTypeOptions options)
  408. {
  409. while (type is OptionalModifierType || type is RequiredModifierType) {
  410. type = ((TypeSpecification)type).ElementType;
  411. }
  412. if (type == null) {
  413. return AstType.Null;
  414. }
  415. if (type is Mono.Cecil.ByReferenceType) {
  416. typeIndex++;
  417. // by reference type cannot be represented in C#; so we'll represent it as a pointer instead
  418. return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex, options)
  419. .MakePointerType();
  420. } else if (type is Mono.Cecil.PointerType) {
  421. typeIndex++;
  422. return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex, options)
  423. .MakePointerType();
  424. } else if (type is Mono.Cecil.ArrayType) {
  425. typeIndex++;
  426. return ConvertType((type as Mono.Cecil.ArrayType).ElementType, typeAttributes, ref typeIndex, options)
  427. .MakeArrayType((type as Mono.Cecil.ArrayType).Rank);
  428. } else if (type is GenericInstanceType) {
  429. GenericInstanceType gType = (GenericInstanceType)type;
  430. if (gType.ElementType.Namespace == "System" && gType.ElementType.Name == "Nullable`1" && gType.GenericArguments.Count == 1) {
  431. typeIndex++;
  432. return new ComposedType {
  433. BaseType = ConvertType(gType.GenericArguments[0], typeAttributes, ref typeIndex, options),
  434. HasNullableSpecifier = true
  435. };
  436. }
  437. AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
  438. List<AstType> typeArguments = new List<AstType>();
  439. foreach (var typeArgument in gType.GenericArguments) {
  440. typeIndex++;
  441. typeArguments.Add(ConvertType(typeArgument, typeAttributes, ref typeIndex, options));
  442. }
  443. ApplyTypeArgumentsTo(baseType, typeArguments);
  444. return baseType;
  445. } else if (type is GenericParameter) {
  446. return new SimpleType(type.Name);
  447. } else if (type.IsNested) {
  448. AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions);
  449. string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
  450. MemberType memberType = new MemberType { Target = typeRef, MemberName = namepart };
  451. memberType.AddAnnotation(type);
  452. if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
  453. AddTypeParameterDefininitionsTo(type, memberType);
  454. }
  455. return memberType;
  456. } else {
  457. string ns = type.Namespace ?? string.Empty;
  458. string name = type.Name;
  459. if (name == null)
  460. throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString());
  461. if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
  462. return new PrimitiveType("dynamic");
  463. } else {
  464. if (ns == "System") {
  465. if ((options & ConvertTypeOptions.DoNotUsePrimitiveTypeNames)
  466. != ConvertTypeOptions.DoNotUsePrimitiveTypeNames) {
  467. switch (name) {
  468. case "SByte":
  469. return new PrimitiveType("sbyte");
  470. case "Int16":
  471. return new PrimitiveType("short");
  472. case "Int32":
  473. return new PrimitiveType("int");
  474. case "Int64":
  475. return new PrimitiveType("long");
  476. case "Byte":
  477. return new PrimitiveType("byte");
  478. case "UInt16":
  479. return new PrimitiveType("ushort");
  480. case "UInt32":
  481. return new PrimitiveType("uint");
  482. case "UInt64":
  483. return new PrimitiveType("ulong");
  484. case "String":
  485. return new PrimitiveType("string");
  486. case "Single":
  487. return new PrimitiveType("float");
  488. case "Double":
  489. return new PrimitiveType("double");
  490. case "Decimal":
  491. return new PrimitiveType("decimal");
  492. case "Char":
  493. return new PrimitiveType("char");
  494. case "Boolean":
  495. return new PrimitiveType("bool");
  496. case "Void":
  497. return new PrimitiveType("void");
  498. case "Object":
  499. return new PrimitiveType("object");
  500. }
  501. }
  502. }
  503. name = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(name);
  504. AstType astType;
  505. if ((options & ConvertTypeOptions.IncludeNamespace) == ConvertTypeOptions.IncludeNamespace && ns.Length > 0) {
  506. string[] parts = ns.Split('.');
  507. AstType nsType = new SimpleType(parts[0]);
  508. for (int i = 1; i < parts.Length; i++) {
  509. nsType = new MemberType { Target = nsType, MemberName = parts[i] };
  510. }
  511. astType = new MemberType { Target = nsType, MemberName = name };
  512. } else {
  513. astType = new SimpleType(name);
  514. }
  515. astType.AddAnnotation(type);
  516. if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
  517. AddTypeParameterDefininitionsTo(type, astType);
  518. }
  519. return astType;
  520. }
  521. }
  522. }
  523. static void AddTypeParameterDefininitionsTo(TypeReference type, AstType astType)
  524. {
  525. if (type.HasGenericParameters) {
  526. List<AstType> typeArguments = new List<AstType>();
  527. foreach (GenericParameter gp in type.GenericParameters) {
  528. typeArguments.Add(new SimpleType(gp.Name));
  529. }
  530. ApplyTypeArgumentsTo(astType, typeArguments);
  531. }
  532. }
  533. static void ApplyTypeArgumentsTo(AstType baseType, List<AstType> typeArguments)
  534. {
  535. SimpleType st = baseType as SimpleType;
  536. if (st != null) {
  537. st.TypeArguments.AddRange(typeArguments);
  538. }
  539. MemberType mt = baseType as MemberType;
  540. if (mt != null) {
  541. TypeReference type = mt.Annotation<TypeReference>();
  542. if (type != null) {
  543. int typeParameterCount;
  544. ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
  545. if (typeParameterCount > typeArguments.Count)
  546. typeParameterCount = typeArguments.Count;
  547. mt.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount));
  548. typeArguments.RemoveRange(typeArguments.Count - typeParameterCount, typeParameterCount);
  549. if (typeArguments.Count > 0)
  550. ApplyTypeArgumentsTo(mt.Target, typeArguments);
  551. } else {
  552. mt.TypeArguments.AddRange(typeArguments);
  553. }
  554. }
  555. }
  556. const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute";
  557. static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex)
  558. {
  559. if (attributeProvider == null || !attributeProvider.HasCustomAttributes)
  560. return false;
  561. foreach (CustomAttribute a in attributeProvider.CustomAttributes) {
  562. if (a.Constructor.DeclaringType.FullName == DynamicAttributeFullName) {
  563. if (a.ConstructorArguments.Count == 1) {
  564. CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[];
  565. if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool)
  566. return (bool)values[typeIndex].Value;
  567. }
  568. return true;
  569. }
  570. }
  571. return false;
  572. }
  573. #endregion
  574. #region ConvertModifiers
  575. Modifiers ConvertModifiers(TypeDefinition typeDef)
  576. {
  577. Modifiers modifiers = Modifiers.None;
  578. if (typeDef.IsNestedPrivate)
  579. modifiers |= Modifiers.Private;
  580. else if (typeDef.IsNestedAssembly || typeDef.IsNestedFamilyAndAssembly || typeDef.IsNotPublic)
  581. modifiers |= Modifiers.Internal;
  582. else if (typeDef.IsNestedFamily)
  583. modifiers |= Modifiers.Protected;
  584. else if (typeDef.IsNestedFamilyOrAssembly)
  585. modifiers |= Modifiers.Protected | Modifiers.Internal;
  586. else if (typeDef.IsPublic || typeDef.IsNestedPublic)
  587. modifiers |= Modifiers.Public;
  588. if (typeDef.IsAbstract && typeDef.IsSealed)
  589. modifiers |= Modifiers.Static;
  590. else if (typeDef.IsAbstract)
  591. modifiers |= Modifiers.Abstract;
  592. else if (typeDef.IsSealed)
  593. modifiers |= Modifiers.Sealed;
  594. return modifiers;
  595. }
  596. Modifiers ConvertModifiers(FieldDefinition fieldDef)
  597. {
  598. Modifiers modifiers = Modifiers.None;
  599. if (fieldDef.IsPrivate)
  600. modifiers |= Modifiers.Private;
  601. else if (fieldDef.IsAssembly || fieldDef.IsFamilyAndAssembly)
  602. modifiers |= Modifiers.Internal;
  603. else if (fieldDef.IsFamily)
  604. modifiers |= Modifiers.Protected;
  605. else if (fieldDef.IsFamilyOrAssembly)
  606. modifiers |= Modifiers.Protected | Modifiers.Internal;
  607. else if (fieldDef.IsPublic)
  608. modifiers |= Modifiers.Public;
  609. if (fieldDef.IsLiteral) {
  610. modifiers |= Modifiers.Const;
  611. } else {
  612. if (fieldDef.IsStatic)
  613. modifiers |= Modifiers.Static;
  614. if (fieldDef.IsInitOnly)
  615. modifiers |= Modifiers.Readonly;
  616. }
  617. RequiredModifierType modreq = fieldDef.FieldType as RequiredModifierType;
  618. if (modreq != null && modreq.ModifierType.FullName == typeof(IsVolatile).FullName)
  619. modifiers |= Modifiers.Volatile;
  620. return modifiers;
  621. }
  622. Modifiers ConvertModifiers(MethodDefinition methodDef)
  623. {
  624. if (methodDef == null)
  625. return Modifiers.None;
  626. Modifiers modifiers = Modifiers.None;
  627. if (methodDef.IsPrivate)
  628. modifiers |= Modifiers.Private;
  629. else if (methodDef.IsAssembly || methodDef.IsFamilyAndAssembly)
  630. modifiers |= Modifiers.Internal;
  631. else if (methodDef.IsFamily)
  632. modifiers |= Modifiers.Protected;
  633. else if (methodDef.IsFamilyOrAssembly)
  634. modifiers |= Modifiers.Protected | Modifiers.Internal;
  635. else if (methodDef.IsPublic)
  636. modifiers |= Modifiers.Public;
  637. if (methodDef.IsStatic)
  638. modifiers |= Modifiers.Static;
  639. if (methodDef.IsAbstract) {
  640. modifiers |= Modifiers.Abstract;
  641. if (!methodDef.IsNewSlot)
  642. modifiers |= Modifiers.Override;
  643. } else if (methodDef.IsFinal) {
  644. if (!methodDef.IsNewSlot) {
  645. modifiers |= Modifiers.Sealed | Modifiers.Override;
  646. }
  647. } else if (methodDef.IsVirtual) {
  648. if (methodDef.IsNewSlot)
  649. modifiers |= Modifiers.Virtual;
  650. else
  651. modifiers |= Modifiers.Override;
  652. }
  653. if (!methodDef.HasBody && !methodDef.IsAbstract)
  654. modifiers |= Modifiers.Extern;
  655. return modifiers;
  656. }
  657. #endregion
  658. void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
  659. {
  660. // Nested types
  661. foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
  662. if (MemberIsHidden(nestedTypeDef, context.Settings))
  663. continue;
  664. var nestedType = CreateType(nestedTypeDef);
  665. SetNewModifier(nestedType);
  666. astType.AddChild(nestedType, Roles.TypeMemberRole);
  667. }
  668. // Add fields
  669. foreach(FieldDefinition fieldDef in typeDef.Fields) {
  670. if (MemberIsHidden(fieldDef, context.Settings)) continue;
  671. astType.AddChild(CreateField(fieldDef), Roles.TypeMemberRole);
  672. }
  673. // Add events
  674. foreach(EventDefinition eventDef in typeDef.Events) {
  675. astType.AddChild(CreateEvent(eventDef), Roles.TypeMemberRole);
  676. }
  677. // Add properties
  678. foreach(PropertyDefinition propDef in typeDef.Properties) {
  679. astType.Members.Add(CreateProperty(propDef));
  680. }
  681. // Add methods
  682. foreach(MethodDefinition methodDef in typeDef.Methods) {
  683. if (MemberIsHidden(methodDef, context.Settings)) continue;
  684. if (methodDef.IsConstructor)
  685. astType.Members.Add(CreateConstructor(methodDef));
  686. else
  687. astType.Members.Add(CreateMethod(methodDef));
  688. }
  689. }
  690. EntityDeclaration CreateMethod(MethodDefinition methodDef)
  691. {
  692. MethodDeclaration astMethod = new MethodDeclaration();
  693. astMethod.AddAnnotation(methodDef);
  694. astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
  695. astMethod.Name = CleanName(methodDef.Name);
  696. astMethod.TypeParameters.AddRange(MakeTypeParameters(methodDef.GenericParameters));
  697. astMethod.Parameters.AddRange(MakeParameters(methodDef));
  698. bool createMethodBody = false;
  699. // constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly
  700. if (!methodDef.IsVirtual || (methodDef.IsNewSlot && !methodDef.IsPrivate)) astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
  701. if (!methodDef.DeclaringType.IsInterface) {
  702. if (IsExplicitInterfaceImplementation(methodDef)) {
  703. astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
  704. } else {
  705. astMethod.Modifiers = ConvertModifiers(methodDef);
  706. if (methodDef.IsVirtual == methodDef.IsNewSlot)
  707. SetNewModifier(astMethod);
  708. }
  709. createMethodBody = true;
  710. } else if (methodDef.IsStatic) {
  711. // decompile static method in interface
  712. astMethod.Modifiers = ConvertModifiers(methodDef);
  713. createMethodBody = true;
  714. }
  715. if (createMethodBody) {
  716. astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
  717. if (context.CurrentMethodIsAsync) {
  718. astMethod.Modifiers |= Modifiers.Async;
  719. context.CurrentMethodIsAsync = false;
  720. }
  721. }
  722. ConvertAttributes(astMethod, methodDef);
  723. if (methodDef.HasCustomAttributes && astMethod.Parameters.Count > 0) {
  724. foreach (CustomAttribute ca in methodDef.CustomAttributes) {
  725. if (ca.AttributeType.Name == "ExtensionAttribute" && ca.AttributeType.Namespace == "System.Runtime.CompilerServices") {
  726. astMethod.Parameters.First().ParameterModifier = ParameterModifier.This;
  727. }
  728. }
  729. }
  730. // Convert MethodDeclaration to OperatorDeclaration if possible
  731. if (methodDef.IsSpecialName && !methodDef.HasGenericParameters) {
  732. OperatorType? opType = OperatorDeclaration.GetOperatorType(methodDef.Name);
  733. if (opType.HasValue) {
  734. OperatorDeclaration op = new OperatorDeclaration();
  735. op.CopyAnnotationsFrom(astMethod);
  736. op.ReturnType = astMethod.ReturnType.Detach();
  737. op.OperatorType = opType.Value;
  738. op.Modifiers = astMethod.Modifiers;
  739. astMethod.Parameters.MoveTo(op.Parameters);
  740. astMethod.Attributes.MoveTo(op.Attributes);
  741. op.Body = astMethod.Body.Detach();
  742. return op;
  743. }
  744. }
  745. return astMethod;
  746. }
  747. bool IsExplicitInterfaceImplementation(MethodDefinition methodDef)
  748. {
  749. return methodDef.HasOverrides && methodDef.IsPrivate;
  750. }
  751. IEnumerable<TypeParameterDeclaration> MakeTypeParameters(IEnumerable<GenericParameter> genericParameters)
  752. {
  753. foreach (var gp in genericParameters) {
  754. TypeParameterDeclaration tp = new TypeParameterDeclaration();
  755. tp.Name = CleanName(gp.Name);
  756. if (gp.IsContravariant)
  757. tp.Variance = VarianceModifier.Contravariant;
  758. else if (gp.IsCovariant)
  759. tp.Variance = VarianceModifier.Covariant;
  760. ConvertCustomAttributes(tp, gp);
  761. yield return tp;
  762. }
  763. }
  764. IEnumerable<Constraint> MakeConstraints(IEnumerable<GenericParameter> genericParameters)
  765. {
  766. foreach (var gp in genericParameters) {
  767. Constraint c = new Constraint();
  768. c.TypeParameter = new SimpleType(CleanName(gp.Name));
  769. // class/struct must be first
  770. if (gp.HasReferenceTypeConstraint)
  771. c.BaseTypes.Add(new PrimitiveType("class"));
  772. if (gp.HasNotNullableValueTypeConstraint)
  773. c.BaseTypes.Add(new PrimitiveType("struct"));
  774. foreach (var constraintType in gp.Constraints) {
  775. if (gp.HasNotNullableValueTypeConstraint && constraintType.FullName == "System.ValueType")
  776. continue;
  777. c.BaseTypes.Add(ConvertType(constraintType));
  778. }
  779. if (gp.HasDefaultConstructorConstraint && !gp.HasNotNullableValueTypeConstraint)
  780. c.BaseTypes.Add(new PrimitiveType("new")); // new() must be last
  781. if (c.BaseTypes.Any())
  782. yield return c;
  783. }
  784. }
  785. ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
  786. {
  787. ConstructorDeclaration astMethod = new ConstructorDeclaration();
  788. astMethod.AddAnnotation(methodDef);
  789. astMethod.Modifiers = ConvertModifiers(methodDef);
  790. if (methodDef.IsStatic) {
  791. // don't show visibility for static ctors
  792. astMethod.Modifiers &= ~Modifiers.VisibilityMask;
  793. }
  794. astMethod.Name = CleanName(methodDef.DeclaringType.Name);
  795. astMethod.Parameters.AddRange(MakeParameters(methodDef));
  796. astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
  797. ConvertAttributes(astMethod, methodDef);
  798. if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) {
  799. astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), Roles.Comment);
  800. }
  801. return astMethod;
  802. }
  803. Modifiers FixUpVisibility(Modifiers m)
  804. {
  805. Modifiers v = m & Modifiers.VisibilityMask;
  806. // If any of the modifiers is public, use that
  807. if ((v & Modifiers.Public) == Modifiers.Public)
  808. return Modifiers.Public | (m & ~Modifiers.VisibilityMask);
  809. // If both modifiers are private, no need to fix anything
  810. if (v == Modifiers.Private)
  811. return m;
  812. // Otherwise, use the other modifiers (internal and/or protected)
  813. return m & ~Modifiers.Private;
  814. }
  815. EntityDeclaration CreateProperty(PropertyDefinition propDef)
  816. {
  817. PropertyDeclaration astProp = new PropertyDeclaration();
  818. astProp.AddAnnotation(propDef);
  819. var accessor = propDef.GetMethod ?? propDef.SetMethod;
  820. Modifiers getterModifiers = Modifiers.None;
  821. Modifiers setterModifiers = Modifiers.None;
  822. if (IsExplicitInterfaceImplementation(accessor)) {
  823. astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType);
  824. } else if (!propDef.DeclaringType.IsInterface) {
  825. getterModifiers = ConvertModifiers(propDef.GetMethod);
  826. setterModifiers = ConvertModifiers(propDef.SetMethod);
  827. astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers);
  828. try {
  829. if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null)) {
  830. foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef)) {
  831. if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) {
  832. var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
  833. astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
  834. break;
  835. } else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot) {
  836. break;
  837. }
  838. }
  839. }
  840. } catch (ReferenceResolvingException) {
  841. // TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
  842. }
  843. }
  844. astProp.Name = CleanName(propDef.Name);
  845. astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
  846. if (propDef.GetMethod != null) {
  847. astProp.Getter = new Accessor();
  848. astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
  849. astProp.Getter.AddAnnotation(propDef.GetMethod);
  850. ConvertAttributes(astProp.Getter, propDef.GetMethod);
  851. if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
  852. astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask;
  853. }
  854. if (propDef.SetMethod != null) {
  855. astProp.Setter = new Accessor();
  856. astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
  857. astProp.Setter.AddAnnotation(propDef.SetMethod);
  858. ConvertAttributes(astProp.Setter, propDef.SetMethod);
  859. ParameterDefinition lastParam = propDef.SetMethod.Parameters.LastOrDefault();
  860. if (lastParam != null) {
  861. ConvertCustomAttributes(astProp.Setter, lastParam, "param");
  862. if (lastParam.HasMarshalInfo) {
  863. astProp.Setter.Attributes.Add(new AttributeSection(ConvertMarshalInfo(lastParam, propDef.Module)) { AttributeTarget = "param" });
  864. }
  865. }
  866. if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
  867. astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
  868. }
  869. ConvertCustomAttributes(astProp, propDef);
  870. EntityDeclaration member = astProp;
  871. if(propDef.IsIndexer())
  872. member = ConvertPropertyToIndexer(astProp, propDef);
  873. if(!accessor.HasOverrides && !accessor.DeclaringType.IsInterface)
  874. if (accessor.IsVirtual == accessor.IsNewSlot)
  875. SetNewModifier(member);
  876. return member;
  877. }
  878. IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef)
  879. {
  880. var astIndexer = new IndexerDeclaration();
  881. astIndexer.CopyAnnotationsFrom(astProp);
  882. astProp.Attributes.MoveTo(astIndexer.Attributes);
  883. astIndexer.Modifiers = astProp.Modifiers;
  884. astIndexer.PrivateImplementationType = astProp.PrivateImplementationType.Detach();
  885. astIndexer.ReturnType = astProp.ReturnType.Detach();
  886. astIndexer.Getter = astProp.Getter.Detach();
  887. astIndexer.Setter = astProp.Setter.Detach();
  888. astIndexer.Parameters.AddRange(MakeParameters(propDef.Parameters));
  889. return astIndexer;
  890. }
  891. EntityDeclaration CreateEvent(EventDefinition eventDef)
  892. {
  893. if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) {
  894. // An abstract event cannot be custom
  895. EventDeclaration astEvent = new EventDeclaration();
  896. ConvertCustomAttributes(astEvent, eventDef);
  897. astEvent.AddAnnotation(eventDef);
  898. astEvent.Variables.Add(new VariableInitializer(CleanName(eventDef.Name)));
  899. astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
  900. if (!eventDef.DeclaringType.IsInterface)
  901. astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
  902. return astEvent;
  903. } else {
  904. CustomEventDeclaration astEvent = new CustomEventDeclaration();
  905. ConvertCustomAttributes(astEvent, eventDef);
  906. astEvent.AddAnnotation(eventDef);
  907. astEvent.Name = CleanName(eventDef.Name);
  908. astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
  909. if (eventDef.AddMethod == null || !IsExplicitInterfaceImplementation(eventDef.AddMethod))
  910. astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
  911. else
  912. astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
  913. if (eventDef.AddMethod != null) {
  914. astEvent.AddAccessor = new Accessor {
  915. Body = CreateMethodBody(eventDef.AddMethod)
  916. }.WithAnnotation(eventDef.AddMethod);
  917. ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
  918. }
  919. if (eventDef.RemoveMethod != null) {
  920. astEvent.RemoveAccessor = new Accessor {
  921. Body = CreateMethodBody(eventDef.RemoveMethod)
  922. }.WithAnnotation(eventDef.RemoveMethod);
  923. ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
  924. }
  925. MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
  926. if (accessor.IsVirtual == accessor.IsNewSlot) {
  927. SetNewModifier(astEvent);
  928. }
  929. return astEvent;
  930. }
  931. }
  932. public bool DecompileMethodBodies { get; set; }
  933. BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable<ParameterDeclaration> parameters = null)
  934. {
  935. if (DecompileMethodBodies)
  936. return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters);
  937. else
  938. return null;
  939. }
  940. FieldDeclaration CreateField(FieldDefinition fieldDef)
  941. {
  942. FieldDeclaration astField = new FieldDeclaration();
  943. astField.AddAnnotation(fieldDef);
  944. VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
  945. astField.AddChild(initializer, Roles.Variable);
  946. astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);
  947. astField.Modifiers = ConvertModifiers(fieldDef);
  948. if (fieldDef.HasConstant) {
  949. initializer.Initializer = CreateExpressionForConstant(fieldDef.Constant, fieldDef.FieldType, fieldDef.DeclaringType.IsEnum);
  950. }
  951. ConvertAttributes(astField, fieldDef);
  952. SetNewModifier(astField);
  953. return astField;
  954. }
  955. static Expression CreateExpressionForConstant(object constant, TypeReference type, bool isEnumMemberDeclaration = false)
  956. {
  957. if (constant == null) {
  958. if (type.IsValueType && !(type.Namespace == "System" && type.Name == "Nullable`1"))
  959. return new DefaultValueExpression(ConvertType(type));
  960. else
  961. return new NullReferenceExpression();
  962. } else {
  963. TypeCode c = Type.GetTypeCode(constant.GetType());
  964. if (c >= TypeCode.SByte && c <= TypeCode.UInt64 && !isEnumMemberDeclaration) {
  965. return MakePrimitive((long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constant, false), type);
  966. } else {
  967. return new PrimitiveExpression(constant);
  968. }
  969. }
  970. }
  971. public static IEnumerable<ParameterDeclaration> MakeParameters(MethodDefinition method, bool isLambda = false)
  972. {
  973. var parameters = MakeParameters(method.Parameters, isLambda);
  974. if (method.CallingConvention == MethodCallingConvention.VarArg) {
  975. return parameters.Concat(new[] { new ParameterDeclaration { Type = new PrimitiveType("__arglist") } });
  976. } else {
  977. return parameters;
  978. }
  979. }
  980. public static IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol, bool isLambda = false)
  981. {
  982. foreach(ParameterDefinition paramDef in paramCol) {
  983. ParameterDeclaration astParam = new ParameterDeclaration();
  984. astParam.AddAnnotation(paramDef);
  985. if (!(isLambda && paramDef.ParameterType.ContainsAnonymousType()))
  986. astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
  987. astParam.Name = paramDef.Name;
  988. if (paramDef.ParameterType is ByReferenceType) {
  989. astParam.ParameterModifier = (!paramDef.IsIn && paramDef.IsOut) ? ParameterModifier.Out : ParameterModifier.Ref;
  990. ComposedType ct = astParam.Type as ComposedType;
  991. if (ct != null && ct.PointerRank > 0)
  992. ct.PointerRank--;
  993. }
  994. if (paramDef.HasCustomAttributes) {
  995. foreach (CustomAttribute ca in paramDef.CustomAttributes) {
  996. if (ca.AttributeType.Name == "ParamArrayAttribute" && ca.AttributeType.Namespace == "System")
  997. astParam.ParameterModifier = ParameterModifier.Params;
  998. }
  999. }
  1000. if (paramDef.IsOptional) {
  1001. astParam.DefaultExpression = CreateExpressionForConstant(paramDef.Constant, paramDef.ParameterType);
  1002. }
  1003. ConvertCustomAttributes(astParam, paramDef);
  1004. ModuleDefinition module = ((MethodDefinition)paramDef.Method).Module;
  1005. if (paramDef.HasMarshalInfo) {
  1006. astParam.Attributes.Add(new AttributeSection(ConvertMarshalInfo(paramDef, module)));
  1007. }
  1008. if (astParam.ParameterModifier != ParameterModifier.Out) {
  1009. if (paramDef.IsIn)
  1010. astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(InAttribute), module)));
  1011. if (paramDef.IsOut)
  1012. astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(OutAttribute), module)));
  1013. }
  1014. yield return astParam;
  1015. }
  1016. }
  1017. #region ConvertAttributes
  1018. void ConvertAttributes(EntityDeclaration attributedNode, TypeDefinition typeDefinition)
  1019. {
  1020. ConvertCustomAttributes(attributedNode, typeDefinition);
  1021. ConvertSecurityAttributes(attributedNode, typeDefinition);
  1022. // Handle the non-custom attributes:
  1023. #region SerializableAttribute
  1024. if (typeDefinition.IsSerializable)
  1025. attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute))));
  1026. #endregion
  1027. #region ComImportAttribute
  1028. if (typeDefinition.IsImport)
  1029. attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(ComImportAttribute))));
  1030. #endregion
  1031. #region StructLayoutAttribute
  1032. LayoutKind layoutKind = LayoutKind.Auto;
  1033. switch (typeDefinition.Attributes & TypeAttributes.LayoutMask) {
  1034. case TypeAttributes.SequentialLayout:
  1035. layoutKind = LayoutKind.Sequential;
  1036. break;
  1037. case TypeAttributes.ExplicitLayout:
  1038. layoutKind = LayoutKind.Explicit;
  1039. break;
  1040. }
  1041. CharSet charSet = CharSet.None;
  1042. switch (typeDefinition.Attributes & TypeAttributes.StringFormatMask) {
  1043. case TypeAttributes.AnsiClass:
  1044. charSet = CharSet.Ansi;
  1045. break;
  1046. case TypeAttributes.AutoClass:
  1047. charSet = CharSet.Auto;
  1048. break;
  1049. case TypeAttributes.UnicodeClass:
  1050. charSet = CharSet.Unicode;
  1051. break;
  1052. }
  1053. LayoutKind defaultLayoutKind = (typeDefinition.IsValueType && !typeDefinition.IsEnum) ? LayoutKind.Sequential: LayoutKind.Auto;
  1054. if (layoutKind != defaultLayoutKind || charSet != CharSet.Ansi || typeDefinition.PackingSize > 0 || typeDefinition.ClassSize > 0) {
  1055. var structLayout = CreateNonCustomAttribute(typeof(StructLayoutAttribute));
  1056. structLayout.Arguments.Add(new IdentifierExpression("LayoutKind").Member(layoutKind.ToString()));
  1057. if (charSet != CharSet.Ansi) {
  1058. structLayout.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString()));
  1059. }
  1060. if (typeDefinition.PackingSize > 0) {
  1061. structLayout.AddNamedArgument("Pack", new PrimitiveExpression((int)typeDefinition.PackingSize));
  1062. }
  1063. if (typeDefinition.ClassSize > 0) {
  1064. structLayout.AddNamedArgument("Size", new PrimitiveExpression((int)typeDefinition.ClassSize));
  1065. }
  1066. attributedNode.Attributes.Add(new AttributeSection(structLayout));
  1067. }
  1068. #endregion
  1069. }
  1070. void ConvertAttributes(EntityDeclaration attributedNode, MethodDefinition methodDefinition)
  1071. {
  1072. ConvertCustomAttributes(attributedNode, methodDefinition);
  1073. ConvertSecurityAttributes(attributedNode, methodDefinition);
  1074. MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask;
  1075. #region DllImportAttribute
  1076. if (methodDefinition.HasPInvokeInfo && methodDefinition.PInvokeInfo != null) {
  1077. PInvokeInfo info = methodDefinition.PInvokeInfo;
  1078. Ast.Attribute dllImport = CreateNonCustomAttribute(typeof(DllImportAttribute));
  1079. dllImport.Arguments.Add(new PrimitiveExpression(info.Module.Name));
  1080. if (info.IsBestFitDisabled)
  1081. dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(false));
  1082. if (info.IsBestFitEnabled)
  1083. dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(true));
  1084. CallingConvention callingConvention;
  1085. switch (info.Attributes & PInvokeAttributes.CallConvMask) {
  1086. case PInvokeAttributes.CallConvCdecl:
  1087. callingConvention = CallingConvention.Cdecl;
  1088. break;
  1089. case PInvokeAttributes.CallConvFastcall:
  1090. callingConvention = CallingConvention.FastCall;
  1091. break;
  1092. case PInvokeAttributes.CallConvStdCall:
  1093. callingConvention = CallingConvention.StdCall;
  1094. break;
  1095. case PInvokeAttributes.CallConvThiscall:
  1096. callingConvention = CallingConvention.ThisCall;
  1097. break;
  1098. case PInvokeAttributes.CallConvWinapi:
  1099. callingConvention = CallingConvention.Winapi;
  1100. break;
  1101. default:
  1102. throw new NotSupportedException("unknown calling convention");
  1103. }
  1104. if (callingConvention != CallingConvention.Winapi)
  1105. dllImport.AddNamedArgument("CallingConvention", new IdentifierExpression("CallingConvention").Member(callingConvention.ToString()));
  1106. CharSet charSet = CharSet.None;
  1107. switch (info.Attributes & PInvokeAttributes.CharSetMask) {
  1108. case PInvokeAttributes.CharSetAnsi:
  1109. charSet = CharSet.Ansi;
  1110. break;
  1111. case PInvokeAttributes.CharSetAuto:
  1112. charSet = CharSet.Auto;
  1113. break;
  1114. case PInvokeAttributes.CharSetUnicode:
  1115. charSet = CharSet.Unicode;
  1116. break;
  1117. }
  1118. if (charSet != CharSet.None)
  1119. dllImport.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString()));
  1120. if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != methodDefinition.Name)
  1121. dllImport.AddNamedArgument("EntryPoint", new PrimitiveExpression(info.EntryPoint));
  1122. if (info.IsNoMangle)
  1123. dllImport.AddNamedArgument("ExactSpelling", new PrimitiveExpression(true));
  1124. if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig)
  1125. implAttributes &= ~MethodImplAttributes.PreserveSig;
  1126. else
  1127. dllImport.AddNamedArgument("PreserveSig", new PrimitiveExpression(false));
  1128. if (info.SupportsLastError)
  1129. dllImport.AddNamedArgument("SetLastError", new PrimitiveExpression(true));
  1130. if (info.IsThrowOnUnmappableCharDisabled)
  1131. dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(false));
  1132. if (info.IsThrowOnUnmappableCharEnabled)
  1133. dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(true));
  1134. attributedNode.Attributes.Add(new AttributeSection(dllImport));
  1135. }
  1136. #endregion
  1137. #region PreserveSigAttribute
  1138. if (implAttributes == MethodImplAttributes.PreserveSig) {
  1139. attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(PreserveSigAttribute))));
  1140. implAttributes = 0;
  1141. }
  1142. #endregion
  1143. #region MethodImplAttribute
  1144. if (implAttributes != 0) {
  1145. Ast.Attribute methodImpl = CreateNonCustomAttribute(typeof(MethodImplAttribute));
  1146. TypeReference methodImplOptions = new TypeReference(
  1147. "System.Runtime.CompilerServices", "MethodImplOptions",
  1148. methodDefinition.Module, methodDefinition.Module.TypeSystem.CoreLibrary);
  1149. methodImpl.Arguments.Add(MakePrimitive((long)implAttributes, methodImplOptions));
  1150. attributedNode.Attributes.Add(new AttributeSection(methodImpl));
  1151. }
  1152. #endregion
  1153. ConvertAttributes(attributedNode, methodDefinition.MethodReturnType, methodDefinition.Module);
  1154. }
  1155. void ConvertAttributes(EntityDeclaration attributedNode, MethodReturnType methodReturnType, ModuleDefinition module)
  1156. {
  1157. ConvertCustomAttributes(attributedNode, methodReturnType, "return");
  1158. if (methodReturnType.HasMarshalInfo) {
  1159. var marshalInfo = ConvertMarshalInfo(methodReturnType, module);
  1160. attributedNode.Attributes.Add(new AttributeSection(marshalInfo) { AttributeTarget = "return" });
  1161. }
  1162. }
  1163. internal static void ConvertAttributes(EntityDeclaration attributedNode, FieldDefinition fieldDefinition, string attributeTarget = null)
  1164. {
  1165. ConvertCustomAttributes(attributedNode, fieldDefinition);
  1166. #region FieldOffsetAttribute
  1167. if (fieldDefinition.HasLayoutInfo) {
  1168. Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute), fieldDefinition.Module);
  1169. fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset));
  1170. attributedNode.Attributes.Add(new AttributeSection(fieldOffset) { AttributeTarget = attributeTarget });
  1171. }
  1172. #endregion
  1173. #region NonSerializedAttribute
  1174. if (fieldDefinition.IsNotSerialized) {
  1175. Ast.Attribute nonSerialized = CreateNonCustomAttribute(typeof(NonSerializedAttribute), fieldDefinition.Module);
  1176. attributedNode.Attributes.Add(new AttributeSection(nonSerialized) { AttributeTarget = attributeTarget });
  1177. }
  1178. #endregion
  1179. if (fieldDefinition.HasMarshalInfo) {
  1180. attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)) { AttributeTarget = attributeTarget });
  1181. }
  1182. }
  1183. #region MarshalAsAttribute (ConvertMarshalInfo)
  1184. static Ast.Attribute ConvertMarshalInfo(IMarshalInfoProvider marshalInfoProvider, ModuleDefinition module)
  1185. {
  1186. MarshalInfo marshalInfo = marshalInfoProvider.MarshalInfo;
  1187. Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module);
  1188. var unmanagedType = new TypeReference("System.Runtime.InteropServices", "UnmanagedType", module, module.TypeSystem.CoreLibrary);
  1189. attr.Arguments.Add(MakePrimitive((int)marshalInfo.NativeType, unmanagedType));
  1190. FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo;
  1191. if (fami != null) {
  1192. attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fami.Size));
  1193. if (fami.ElementType != NativeType.None)
  1194. attr.AddNamedArgument("ArraySubType", MakePrimitive((int)fami.ElementType, unmanagedType));
  1195. }
  1196. SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo;
  1197. if (sami != null && sami.ElementType != VariantType.None) {
  1198. var varEnum = new TypeReference("System.Runtime.InteropServices", "VarEnum", module, module.TypeSystem.CoreLibrary);
  1199. attr.AddNamedArgument("SafeArraySubType", MakePrimitive((int)sami.ElementType, varEnum));
  1200. }
  1201. ArrayMarshalInfo ami = marshalInfo as ArrayMarshalInfo;
  1202. if (ami != null) {
  1203. if (ami.ElementType != NativeType.Max)
  1204. attr.AddNamedArgument("ArraySubType", MakePrimitive((int)ami.ElementType, unmanagedType));
  1205. if (ami.Size >= 0)
  1206. attr.AddNamedArgument("SizeConst", new PrimitiveExpression(ami.Size));
  1207. if (ami.SizeParameterMultiplier != 0 && ami.SizeParameterIndex >= 0)
  1208. attr.AddNamedArgument("SizeParamIndex", new PrimitiveExpression(ami.SizeParameterIndex));
  1209. }
  1210. CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo;
  1211. if (cmi != null) {
  1212. attr.AddNamedArgument("MarshalType", new PrimitiveExpression(cmi.ManagedType.FullName));
  1213. if (!string.IsNullOrEmpty(cmi.Cookie))
  1214. attr.AddNamedArgument("MarshalCookie", new PrimitiveExpression(cmi.Cookie));
  1215. }
  1216. FixedSysStringMarshalInfo fssmi = marshalInfo as FixedSysStringMarshalInfo;
  1217. if (fssmi != null) {
  1218. attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fssmi.Size));
  1219. }
  1220. return attr;
  1221. }
  1222. #endregion
  1223. Ast.Attribute CreateNonCustomAttribute(Type attributeType)
  1224. {
  1225. return CreateNonCustomAttribute(attributeType, context.CurrentType != null ? context.CurrentType.Module : null);
  1226. }
  1227. static Ast.Attribute CreateNonCustomAttribute(Type attributeType, ModuleDefinition module)
  1228. {
  1229. Debug.Assert(attributeType.Name.EndsWith("Attribute", StringComparison.Ordinal));
  1230. Ast.Attribute attr = new Ast.Attribute();
  1231. attr.Type = new SimpleType(attributeType.Name.Substring(0, attributeType.Name.Length - "Attribute".Length));
  1232. if (module != null) {
  1233. attr.Type.AddAnnotation(new TypeReference(attributeType.Namespace, attributeType.Name, module, module.TypeSystem.CoreLibrary));
  1234. }
  1235. return attr;
  1236. }
  1237. static void ConvertCustomAttributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, string attributeTarget = null)
  1238. {
  1239. EntityDeclaration entityDecl = attributedNode as EntityDeclaration;
  1240. if (customAttributeProvider.HasCustomAttributes) {
  1241. var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
  1242. foreach (var customAttribute in customAttributeProvider.CustomAttributes.OrderBy(a => a.AttributeType.FullName)) {
  1243. if (customAttribute.AttributeType.Name == "ExtensionAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices") {
  1244. // don't show the ExtensionAttribute (it's converted to the 'this' modifier)
  1245. continue;
  1246. }
  1247. if (customAttribute.AttributeType.Name == "ParamArrayAttribute" && customAttribute.AttributeType.Namespace == "System") {
  1248. // don't show the ParamArrayAttribute (it's converted to the 'params' modifier)
  1249. continue;
  1250. }
  1251. // if the method is async, remove [DebuggerStepThrough] and [Async
  1252. if (entityDecl != null && entityDecl.HasModifier(Modifiers.Async)) {
  1253. if (customAttribute.AttributeType.Name == "DebuggerStepThroughAttribute" && customAttribute.AttributeType.Namespace == "System.Diagnostics") {
  1254. continue;
  1255. }
  1256. if (customAttribute.AttributeType.Name == "AsyncStateMachineAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices") {
  1257. continue;
  1258. }
  1259. }
  1260. var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
  1261. attribute.AddAnnotation(customAttribute);
  1262. attribute.Type = ConvertType(customAttribute.AttributeType);
  1263. attributes.Add(attribute);
  1264. SimpleType st = attribute.Type as SimpleType;
  1265. if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) {
  1266. st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length);
  1267. }
  1268. if(customAttribute.HasConstructorArguments) {
  1269. foreach (var parameter in customAttribute.ConstructorArguments) {
  1270. Expression parameterValue = ConvertArgumentValue(parameter);
  1271. attribute.Arguments.Add(parameterValue);
  1272. }
  1273. }
  1274. if (customAttribute.HasProperties) {
  1275. TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve();
  1276. foreach (var propertyNamedArg in customAttribute.Properties) {
  1277. var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null;
  1278. var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference);
  1279. var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument);
  1280. attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue));
  1281. }
  1282. }
  1283. if (customAttribute.HasFields) {
  1284. TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve();
  1285. foreach (var fieldNamedArg in customAttribute.Fields) {
  1286. var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null;
  1287. var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference);
  1288. var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument);
  1289. attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue));
  1290. }
  1291. }
  1292. }
  1293. if (attributeTarget == "module" || attributeTarget == "assembly") {
  1294. // use separate section for each attribute
  1295. foreach (var attribute in attributes) {
  1296. var section = new AttributeSection();
  1297. section.AttributeTarget = attributeTarget;
  1298. section.Attributes.Add(attribute);
  1299. attributedNode.AddChild(section, EntityDeclaration.AttributeRole);
  1300. }
  1301. } else if (attributes.Count > 0) {
  1302. // use single section for all attributes
  1303. var section = new AttributeSection();
  1304. section.AttributeTarget = attributeTarget;
  1305. section.Attributes.AddRange(attributes);
  1306. attributedNode.AddChild(section, EntityDeclaration.AttributeRole);
  1307. }
  1308. }
  1309. }
  1310. static void ConvertSecurityAttributes(AstNode attributedNode, ISecurityDeclarationProvider secDeclProvider, string attributeTarget = null)
  1311. {
  1312. if (!secDeclProvider.HasSecurityDeclarations)
  1313. return;
  1314. var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
  1315. foreach (var secDecl in secDeclProvider.SecurityDeclarations.OrderBy(d => d.Action)) {
  1316. foreach (var secAttribute in secDecl.SecurityAttributes.OrderBy(a => a.AttributeType.FullName)) {
  1317. var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
  1318. attribute.AddAnnotation(secAttribute);
  1319. attribute.Type = ConvertType(secAttribute.AttributeType);
  1320. attributes.Add(attribute);
  1321. SimpleType st = attribute.Type as SimpleType;
  1322. if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) {
  1323. st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length);
  1324. }
  1325. var module = secAttribute.AttributeType.Module;
  1326. var securityActionType = new TypeReference("System.Security.Permissions", "SecurityAction", module, module.TypeSystem.CoreLibrary);
  1327. attribute.Arguments.Add(MakePrimitive((int)secDecl.Action, securityActionType));
  1328. if (secAttribute.HasProperties) {
  1329. TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve();
  1330. foreach (var propertyNamedArg in secAttribute.Properties) {
  1331. var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null;
  1332. var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference);
  1333. var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument);
  1334. attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue));
  1335. }
  1336. }
  1337. if (secAttribute.HasFields) {
  1338. TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve();
  1339. foreach (var fieldNamedArg in secAttribute.Fields) {
  1340. var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null;
  1341. var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference);
  1342. var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument);
  1343. attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue));
  1344. }
  1345. }
  1346. }
  1347. }
  1348. if (attributeTarget == "module" || attributeTarget == "assembly") {
  1349. // use separate section for each attribute
  1350. foreach (var attribute in attributes) {
  1351. var section = new AttributeSection();
  1352. section.AttributeTarget = attributeTarget;
  1353. section.Attributes.Add(attribute);
  1354. attributedNode.AddChild(section, EntityDeclaration.AttributeRole);
  1355. }
  1356. } else if (attributes.Count > 0) {
  1357. // use single section for all attributes
  1358. var section = new AttributeSection();
  1359. section.AttributeTarget = attributeTarget;
  1360. section.Attributes.AddRange(attributes);
  1361. attributedNode.AddChild(section, EntityDeclaration.AttributeRole);
  1362. }
  1363. }
  1364. private static Expression ConvertArgumentValue(CustomAttributeArgument argument)
  1365. {
  1366. if (argument.Value is CustomAttributeArgument[]) {
  1367. ArrayInitializerExpression arrayInit = new ArrayInitializerExpression();
  1368. foreach (CustomAttributeArgument element in (CustomAttributeArgument[])argument.Value) {
  1369. arrayInit.Elements.Add(ConvertArgumentValue(element));
  1370. }
  1371. ArrayType arrayType = argument.Type as ArrayType;
  1372. return new ArrayCreateExpression {
  1373. Type = ConvertType(arrayType != null ? arrayType.ElementType : argument.Type),
  1374. AdditionalArraySpecifiers = { new ArraySpecifier() },
  1375. Initializer = arrayInit
  1376. };
  1377. } else if (argument.Value is CustomAttributeArgument) {
  1378. // occurs with boxed arguments
  1379. return ConvertArgumentValue((CustomAttributeArgument)argument.Value);
  1380. }
  1381. var type = argument.Type.Resolve();
  1382. if (type != null && type.IsEnum) {
  1383. long val = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, argument.Value, false);
  1384. return MakePrimitive(val, type);
  1385. } else if (argument.Value is TypeReference) {
  1386. return CreateTypeOfExpression((TypeReference)argument.Value);
  1387. } else {
  1388. return new PrimitiveExpression(argument.Value);
  1389. }
  1390. }
  1391. #endregion
  1392. internal static Expression MakePrimitive(long val, TypeReference type)
  1393. {
  1394. if (TypeAnalysis.IsBoolean(type) && val == 0)
  1395. return new Ast.PrimitiveExpression(false);
  1396. else if (TypeAnalysis.IsBoolean(type) && val == 1)
  1397. return new Ast.PrimitiveExpression(true);
  1398. else if (val == 0 && type is PointerType)
  1399. return new Ast.NullReferenceExpression();
  1400. if (type != null)
  1401. { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
  1402. TypeDefinition enumDefinition = type.Resolve();
  1403. if (enumDefinition != null && enumDefinition.IsEnum) {
  1404. TypeCode enumBaseTypeCode = TypeCode.Int32;
  1405. foreach (FieldDefinition field in enumDefinition.Fields) {
  1406. if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
  1407. return ConvertType(type).Member(field.Name).WithAnnotation(field);
  1408. else if (!field.IsStatic)
  1409. enumBaseTypeCode = TypeAnalysis.GetTypeCode(field.FieldType); // use primitive type of the enum
  1410. }
  1411. if (IsFlagsEnum(enumDefinition)) {
  1412. long enumValue = val;
  1413. Expression expr = null;
  1414. long negatedEnumValue = ~val;
  1415. // limit negatedEnumValue to the appropriate range
  1416. switch (enumBaseTypeCode) {
  1417. case TypeCode.Byte:
  1418. case TypeCode.SByte:
  1419. negatedEnumValue &= byte.MaxValue;
  1420. break;
  1421. case TypeCode.Int16:
  1422. case TypeCode.UInt16:
  1423. negatedEnumValue &= ushort.MaxValue;
  1424. break;
  1425. case TypeCode.Int32:
  1426. case TypeCode.UInt32:
  1427. negatedEnumValue &= uint.MaxValue;
  1428. break;
  1429. }
  1430. Expression negatedExpr = null;
  1431. foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic)) {
  1432. long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
  1433. if (fieldValue == 0)
  1434. continue; // skip None enum value
  1435. if ((fieldValue & enumValue) == fieldValue) {
  1436. var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field);
  1437. if (expr == null)
  1438. expr = fieldExpression;
  1439. else
  1440. expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
  1441. enumValue &= ~fieldValue;
  1442. }
  1443. if ((fieldValue & negatedEnumValue) == fieldValue) {
  1444. var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field);
  1445. if (negatedExpr == null)
  1446. negatedExpr = fieldExpression;
  1447. else
  1448. negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression);
  1449. negatedEnumValue &= ~fieldValue;
  1450. }
  1451. }
  1452. if (enumValue == 0 && expr != null) {
  1453. if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) {
  1454. return expr;
  1455. }
  1456. }
  1457. if (negatedEnumValue == 0 && negatedExpr != null) {
  1458. return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr);
  1459. }
  1460. }
  1461. return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type));
  1462. }
  1463. }
  1464. TypeCode code = TypeAnalysis.GetTypeCode(type);
  1465. if (code == TypeCode.Object || code == TypeCode.Empty)
  1466. code = TypeCode.Int32;
  1467. return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
  1468. }
  1469. static bool IsFlagsEnum(TypeDefinition type)
  1470. {
  1471. if (!type.HasCustomAttributes)
  1472. return false;
  1473. return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute");
  1474. }
  1475. /// <summary>
  1476. /// Sets new modifier if the member hides some other member from a base type.
  1477. /// </summary>
  1478. /// <param name="member">The node of the member which new modifier state should be determined.</param>
  1479. static void SetNewModifier(EntityDeclaration member)
  1480. {
  1481. try {
  1482. bool addNewModifier = false;
  1483. if (member is IndexerDeclaration) {
  1484. var propertyDef = member.Annotation<PropertyDefinition>();
  1485. var baseProperties =
  1486. TypesHierarchyHelpers.FindBaseProperties(propertyDef);
  1487. addNewModifier = baseProperties.Any();
  1488. } else
  1489. addNewModifier = HidesBaseMember(member);
  1490. if (addNewModifier)
  1491. member.Modifiers |= Modifiers.New;
  1492. }
  1493. catch (ReferenceResolvingException) {
  1494. // TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references.
  1495. }
  1496. }
  1497. private static bool HidesBaseMember(EntityDeclaration member)
  1498. {
  1499. var memberDefinition = member.Annotation<IMemberDefinition>();
  1500. bool addNewModifier = false;
  1501. var methodDefinition = memberDefinition as MethodDefinition;
  1502. if (methodDefinition != null) {
  1503. addNewModifier = HidesByName(memberDefinition, includeBaseMethods: false);
  1504. if (!addNewModifier)
  1505. addNewModifier = TypesHierarchyHelpers.FindBaseMethods(methodDefinition).Any();
  1506. } else
  1507. addNewModifier = HidesByName(memberDefinition, includeBaseMethods: true);
  1508. return addNewModifier;
  1509. }
  1510. /// <summary>
  1511. /// Determines whether any base class member has the same name as the given member.
  1512. /// </summary>
  1513. /// <param name="member">The derived type's member.</param>
  1514. /// <param name="includeBaseMethods">true if names of methods declared in base types should also be checked.</param>
  1515. /// <returns>true if any base member has the same name as given member, otherwise false.</returns>
  1516. static bool HidesByName(IMemberDefinition member, bool includeBaseMethods)
  1517. {
  1518. Debug.Assert(!(member is PropertyDefinition) || !((PropertyDefinition)member).IsIndexer());
  1519. if (member.DeclaringType.BaseType != null) {
  1520. var baseTypeRef = member.DeclaringType.BaseType;
  1521. while (baseTypeRef != null) {
  1522. var baseType = baseTypeRef.ResolveOrThrow();
  1523. if (baseType.HasProperties && AnyIsHiddenBy(baseType.Properties, member, m => !m.IsIndexer()))
  1524. return true;
  1525. if (baseType.HasEvents && AnyIsHiddenBy(baseType.Events, member))
  1526. return true;
  1527. if (baseType.HasFields && AnyIsHiddenBy(baseType.Fields, member))
  1528. return true;
  1529. if (includeBaseMethods && baseType.HasMethods
  1530. && AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName))
  1531. return true;
  1532. if (baseType.HasNestedTypes && AnyIsHiddenBy(baseType.NestedTypes, member))
  1533. return true;
  1534. baseTypeRef = baseType.BaseType;
  1535. }
  1536. }
  1537. return false;
  1538. }
  1539. static bool AnyIsHiddenBy<T>(IEnumerable<T> members, IMemberDefinition derived, Predicate<T> condition = null)
  1540. where T : IMemberDefinition
  1541. {
  1542. return members.Any(m => m.Name == derived.Name
  1543. && (condition == null || condition(m))
  1544. && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
  1545. }
  1546. }
  1547. }