/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs

http://github.com/icsharpcode/ILSpy · C# · 981 lines · 798 code · 79 blank · 104 comment · 267 complexity · f0434825ad05db0a40857671dc7c926d MD5 · raw file

  1. // Copyright (c) 2010-2013 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.Diagnostics;
  21. using System.Linq;
  22. using ICSharpCode.NRefactory.CSharp.Resolver;
  23. using ICSharpCode.NRefactory.CSharp.TypeSystem;
  24. using ICSharpCode.NRefactory.Semantics;
  25. using ICSharpCode.NRefactory.TypeSystem;
  26. using ICSharpCode.NRefactory.TypeSystem.Implementation;
  27. using ICSharpCode.NRefactory.Utils;
  28. namespace ICSharpCode.NRefactory.CSharp.Refactoring
  29. {
  30. /// <summary>
  31. /// Converts from type system to the C# AST.
  32. /// </summary>
  33. public class TypeSystemAstBuilder
  34. {
  35. readonly CSharpResolver resolver;
  36. #region Constructor
  37. /// <summary>
  38. /// Creates a new TypeSystemAstBuilder.
  39. /// </summary>
  40. /// <param name="resolver">
  41. /// A resolver initialized for the position where the type will be inserted.
  42. /// </param>
  43. public TypeSystemAstBuilder(CSharpResolver resolver)
  44. {
  45. if (resolver == null)
  46. throw new ArgumentNullException("resolver");
  47. this.resolver = resolver;
  48. InitProperties();
  49. }
  50. /// <summary>
  51. /// Creates a new TypeSystemAstBuilder.
  52. /// </summary>
  53. public TypeSystemAstBuilder()
  54. {
  55. InitProperties();
  56. }
  57. #endregion
  58. #region Properties
  59. void InitProperties()
  60. {
  61. this.ShowAccessibility = true;
  62. this.ShowModifiers = true;
  63. this.ShowBaseTypes = true;
  64. this.ShowTypeParameters = true;
  65. this.ShowTypeParameterConstraints = true;
  66. this.ShowParameterNames = true;
  67. this.ShowConstantValues = true;
  68. this.UseAliases = true;
  69. }
  70. /// <summary>
  71. /// Specifies whether the ast builder should add annotations to type references.
  72. /// The default value is <c>false</c>.
  73. /// </summary>
  74. public bool AddAnnotations { get; set; }
  75. /// <summary>
  76. /// Controls the accessibility modifiers are shown.
  77. /// The default value is <c>true</c>.
  78. /// </summary>
  79. public bool ShowAccessibility { get; set; }
  80. /// <summary>
  81. /// Controls the non-accessibility modifiers are shown.
  82. /// The default value is <c>true</c>.
  83. /// </summary>
  84. public bool ShowModifiers { get; set; }
  85. /// <summary>
  86. /// Controls whether base type references are shown.
  87. /// The default value is <c>true</c>.
  88. /// </summary>
  89. public bool ShowBaseTypes { get; set; }
  90. /// <summary>
  91. /// Controls whether type parameter declarations are shown.
  92. /// The default value is <c>true</c>.
  93. /// </summary>
  94. public bool ShowTypeParameters { get; set; }
  95. /// <summary>
  96. /// Controls whether constraints on type parameter declarations are shown.
  97. /// Has no effect if ShowTypeParameters is false.
  98. /// The default value is <c>true</c>.
  99. /// </summary>
  100. public bool ShowTypeParameterConstraints { get; set; }
  101. /// <summary>
  102. /// Controls whether the names of parameters are shown.
  103. /// The default value is <c>true</c>.
  104. /// </summary>
  105. public bool ShowParameterNames { get; set; }
  106. /// <summary>
  107. /// Controls whether to show default values of optional parameters, and the values of constant fields.
  108. /// The default value is <c>true</c>.
  109. /// </summary>
  110. public bool ShowConstantValues { get; set; }
  111. /// <summary>
  112. /// Controls whether to use fully-qualified type names or short type names.
  113. /// The default value is <c>false</c>.
  114. /// </summary>
  115. public bool AlwaysUseShortTypeNames { get; set; }
  116. /// <summary>
  117. /// Controls whether to generate a body that throws a <c>System.NotImplementedException</c>.
  118. /// The default value is <c>false</c>.
  119. /// </summary>
  120. public bool GenerateBody { get; set; }
  121. /// <summary>
  122. /// Controls whether to generate custom events.
  123. /// The default value is <c>false</c>.
  124. /// </summary>
  125. public bool UseCustomEvents { get; set; }
  126. /// <summary>
  127. /// Controls if unbound type argument names are inserted in the ast or not.
  128. /// The default value is <c>false</c>.
  129. /// </summary>
  130. public bool ConvertUnboundTypeArguments { get; set;}
  131. /// <summary>
  132. /// Controls if aliases should be used inside the type name or not.
  133. /// The default value is <c>true</c>.
  134. /// </summary>
  135. public bool UseAliases { get; set;}
  136. #endregion
  137. #region Convert Type
  138. public AstType ConvertType(IType type)
  139. {
  140. if (type == null)
  141. throw new ArgumentNullException("type");
  142. AstType astType = ConvertTypeHelper(type);
  143. if (AddAnnotations)
  144. astType.AddAnnotation(type);
  145. return astType;
  146. }
  147. public AstType ConvertType(FullTypeName fullTypeName)
  148. {
  149. if (resolver != null) {
  150. foreach (var asm in resolver.Compilation.Assemblies) {
  151. var def = asm.GetTypeDefinition(fullTypeName);
  152. if (def != null) {
  153. return ConvertType(def);
  154. }
  155. }
  156. }
  157. TopLevelTypeName top = fullTypeName.TopLevelTypeName;
  158. AstType type;
  159. if (string.IsNullOrEmpty(top.Namespace)) {
  160. type = new SimpleType(top.Name);
  161. } else {
  162. type = new SimpleType(top.Namespace).MemberType(top.Name);
  163. }
  164. for (int i = 0; i < fullTypeName.NestingLevel; i++) {
  165. type = type.MemberType(fullTypeName.GetNestedTypeName(i));
  166. }
  167. return type;
  168. }
  169. AstType ConvertTypeHelper(IType type)
  170. {
  171. TypeWithElementType typeWithElementType = type as TypeWithElementType;
  172. if (typeWithElementType != null) {
  173. if (typeWithElementType is PointerType) {
  174. return ConvertType(typeWithElementType.ElementType).MakePointerType();
  175. } else if (typeWithElementType is ArrayType) {
  176. return ConvertType(typeWithElementType.ElementType).MakeArrayType(((ArrayType)type).Dimensions);
  177. } else {
  178. // e.g. ByReferenceType; not supported as type in C#
  179. return ConvertType(typeWithElementType.ElementType);
  180. }
  181. }
  182. ParameterizedType pt = type as ParameterizedType;
  183. if (pt != null) {
  184. if (pt.Name == "Nullable" && pt.Namespace == "System" && pt.TypeParameterCount == 1) {
  185. return ConvertType(pt.TypeArguments[0]).MakeNullableType();
  186. }
  187. return ConvertTypeHelper(pt.GetDefinition(), pt.TypeArguments);
  188. }
  189. ITypeDefinition typeDef = type as ITypeDefinition;
  190. if (typeDef != null) {
  191. if (typeDef.TypeParameterCount > 0) {
  192. // Unbound type
  193. IType[] typeArguments = new IType[typeDef.TypeParameterCount];
  194. for (int i = 0; i < typeArguments.Length; i++) {
  195. typeArguments[i] = SpecialType.UnboundTypeArgument;
  196. }
  197. return ConvertTypeHelper(typeDef, typeArguments);
  198. } else {
  199. return ConvertTypeHelper(typeDef, EmptyList<IType>.Instance);
  200. }
  201. }
  202. return new SimpleType(type.Name);
  203. }
  204. AstType ConvertTypeHelper(ITypeDefinition typeDef, IList<IType> typeArguments)
  205. {
  206. Debug.Assert(typeArguments.Count >= typeDef.TypeParameterCount);
  207. string keyword = KnownTypeReference.GetCSharpNameByTypeCode(typeDef.KnownTypeCode);
  208. if (keyword != null)
  209. return new PrimitiveType(keyword);
  210. // The number of type parameters belonging to outer classes
  211. int outerTypeParameterCount;
  212. if (typeDef.DeclaringType != null)
  213. outerTypeParameterCount = typeDef.DeclaringType.TypeParameterCount;
  214. else
  215. outerTypeParameterCount = 0;
  216. if (resolver != null) {
  217. // Look if there's an alias to the target type
  218. if (UseAliases) {
  219. for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
  220. foreach (var pair in usingScope.UsingAliases) {
  221. if (pair.Value is TypeResolveResult) {
  222. if (TypeMatches(pair.Value.Type, typeDef, typeArguments))
  223. return new SimpleType(pair.Key);
  224. }
  225. }
  226. }
  227. }
  228. IList<IType> localTypeArguments;
  229. if (typeDef.TypeParameterCount > outerTypeParameterCount) {
  230. localTypeArguments = new IType[typeDef.TypeParameterCount - outerTypeParameterCount];
  231. for (int i = 0; i < localTypeArguments.Count; i++) {
  232. localTypeArguments[i] = typeArguments[outerTypeParameterCount + i];
  233. }
  234. } else {
  235. localTypeArguments = EmptyList<IType>.Instance;
  236. }
  237. ResolveResult rr = resolver.ResolveSimpleName(typeDef.Name, localTypeArguments);
  238. TypeResolveResult trr = rr as TypeResolveResult;
  239. if (trr != null || (localTypeArguments.Count == 0 && resolver.IsVariableReferenceWithSameType(rr, typeDef.Name, out trr))) {
  240. if (!trr.IsError && TypeMatches(trr.Type, typeDef, typeArguments)) {
  241. // We can use the short type name
  242. SimpleType shortResult = new SimpleType(typeDef.Name);
  243. AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
  244. return shortResult;
  245. }
  246. }
  247. }
  248. if (AlwaysUseShortTypeNames) {
  249. var shortResult = new SimpleType(typeDef.Name);
  250. AddTypeArguments(shortResult, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
  251. return shortResult;
  252. }
  253. MemberType result = new MemberType();
  254. if (typeDef.DeclaringTypeDefinition != null) {
  255. // Handle nested types
  256. result.Target = ConvertTypeHelper(typeDef.DeclaringTypeDefinition, typeArguments);
  257. } else {
  258. // Handle top-level types
  259. if (string.IsNullOrEmpty(typeDef.Namespace)) {
  260. result.Target = new SimpleType("global");
  261. result.IsDoubleColon = true;
  262. } else {
  263. result.Target = ConvertNamespace(typeDef.Namespace);
  264. }
  265. }
  266. result.MemberName = typeDef.Name;
  267. AddTypeArguments(result, typeDef, typeArguments, outerTypeParameterCount, typeDef.TypeParameterCount);
  268. return result;
  269. }
  270. /// <summary>
  271. /// Gets whether 'type' is the same as 'typeDef' parameterized with the given type arguments.
  272. /// </summary>
  273. bool TypeMatches(IType type, ITypeDefinition typeDef, IList<IType> typeArguments)
  274. {
  275. if (typeDef.TypeParameterCount == 0) {
  276. return typeDef.Equals(type);
  277. } else {
  278. if (!typeDef.Equals(type.GetDefinition()))
  279. return false;
  280. ParameterizedType pt = type as ParameterizedType;
  281. if (pt == null) {
  282. return typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument);
  283. }
  284. var ta = pt.TypeArguments;
  285. for (int i = 0; i < ta.Count; i++) {
  286. if (!ta[i].Equals(typeArguments[i]))
  287. return false;
  288. }
  289. return true;
  290. }
  291. }
  292. /// <summary>
  293. /// Adds type arguments to the result type.
  294. /// </summary>
  295. /// <param name="result">The result AST node (a SimpleType or MemberType)</param>
  296. /// <param name="typeDef">The type definition that owns the type parameters</param>
  297. /// <param name="typeArguments">The list of type arguments</param>
  298. /// <param name="startIndex">Index of first type argument to add</param>
  299. /// <param name="endIndex">Index after last type argument to add</param>
  300. void AddTypeArguments(AstType result, ITypeDefinition typeDef, IList<IType> typeArguments, int startIndex, int endIndex)
  301. {
  302. Debug.Assert(endIndex <= typeDef.TypeParameterCount);
  303. for (int i = startIndex; i < endIndex; i++) {
  304. if (ConvertUnboundTypeArguments && typeArguments[i].Kind == TypeKind.UnboundTypeArgument) {
  305. result.AddChild(new SimpleType(typeDef.TypeParameters[i].Name), Roles.TypeArgument);
  306. } else {
  307. result.AddChild(ConvertType(typeArguments[i]), Roles.TypeArgument);
  308. }
  309. }
  310. }
  311. public AstType ConvertNamespace(string namespaceName)
  312. {
  313. if (resolver != null) {
  314. // Look if there's an alias to the target namespace
  315. if (UseAliases) {
  316. for (ResolvedUsingScope usingScope = resolver.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) {
  317. foreach (var pair in usingScope.UsingAliases) {
  318. NamespaceResolveResult nrr = pair.Value as NamespaceResolveResult;
  319. if (nrr != null && nrr.NamespaceName == namespaceName)
  320. return new SimpleType(pair.Key);
  321. }
  322. }
  323. }
  324. }
  325. int pos = namespaceName.LastIndexOf('.');
  326. if (pos < 0) {
  327. if (IsValidNamespace(namespaceName)) {
  328. return new SimpleType(namespaceName);
  329. } else {
  330. return new MemberType {
  331. Target = new SimpleType("global"),
  332. IsDoubleColon = true,
  333. MemberName = namespaceName
  334. };
  335. }
  336. } else {
  337. string parentNamespace = namespaceName.Substring(0, pos);
  338. string localNamespace = namespaceName.Substring(pos + 1);
  339. return new MemberType {
  340. Target = ConvertNamespace(parentNamespace),
  341. MemberName = localNamespace
  342. };
  343. }
  344. }
  345. bool IsValidNamespace(string firstNamespacePart)
  346. {
  347. if (resolver == null)
  348. return true; // just assume namespaces are valid if we don't have a resolver
  349. NamespaceResolveResult nrr = resolver.ResolveSimpleName(firstNamespacePart, EmptyList<IType>.Instance) as NamespaceResolveResult;
  350. return nrr != null && !nrr.IsError && nrr.NamespaceName == firstNamespacePart;
  351. }
  352. #endregion
  353. #region Convert Attribute
  354. public Attribute ConvertAttribute(IAttribute attribute)
  355. {
  356. Attribute attr = new Attribute();
  357. attr.Type = ConvertType(attribute.AttributeType);
  358. SimpleType st = attr.Type as SimpleType;
  359. MemberType mt = attr.Type as MemberType;
  360. if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) {
  361. st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - 9);
  362. } else if (mt != null && mt.MemberName.EndsWith("Attribute", StringComparison.Ordinal)) {
  363. mt.MemberName = mt.MemberName.Substring(0, mt.MemberName.Length - 9);
  364. }
  365. foreach (ResolveResult arg in attribute.PositionalArguments) {
  366. attr.Arguments.Add(ConvertConstantValue(arg));
  367. }
  368. foreach (var pair in attribute.NamedArguments) {
  369. attr.Arguments.Add(new NamedExpression(pair.Key.Name, ConvertConstantValue(pair.Value)));
  370. }
  371. return attr;
  372. }
  373. #endregion
  374. #region Convert Constant Value
  375. public Expression ConvertConstantValue(ResolveResult rr)
  376. {
  377. if (rr == null)
  378. throw new ArgumentNullException("rr");
  379. if (rr is ConversionResolveResult) {
  380. // unpack ConversionResolveResult if necessary
  381. // (e.g. a boxing conversion or string->object reference conversion)
  382. rr = ((ConversionResolveResult)rr).Input;
  383. }
  384. if (rr is TypeOfResolveResult) {
  385. return new TypeOfExpression(ConvertType(rr.Type));
  386. } else if (rr is ArrayCreateResolveResult) {
  387. ArrayCreateResolveResult acrr = (ArrayCreateResolveResult)rr;
  388. ArrayCreateExpression ace = new ArrayCreateExpression();
  389. ace.Type = ConvertType(acrr.Type);
  390. ComposedType composedType = ace.Type as ComposedType;
  391. if (composedType != null) {
  392. composedType.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
  393. if (!composedType.HasNullableSpecifier && composedType.PointerRank == 0)
  394. ace.Type = composedType.BaseType;
  395. }
  396. if (acrr.SizeArguments != null && acrr.InitializerElements == null) {
  397. ace.AdditionalArraySpecifiers.FirstOrNullObject().Remove();
  398. ace.Arguments.AddRange(acrr.SizeArguments.Select(ConvertConstantValue));
  399. }
  400. if (acrr.InitializerElements != null) {
  401. ArrayInitializerExpression initializer = new ArrayInitializerExpression();
  402. initializer.Elements.AddRange(acrr.InitializerElements.Select(ConvertConstantValue));
  403. ace.Initializer = initializer;
  404. }
  405. return ace;
  406. } else if (rr.IsCompileTimeConstant) {
  407. return ConvertConstantValue(rr.Type, rr.ConstantValue);
  408. } else {
  409. return new ErrorExpression();
  410. }
  411. }
  412. public Expression ConvertConstantValue(IType type, object constantValue)
  413. {
  414. if (type == null)
  415. throw new ArgumentNullException("type");
  416. if (constantValue == null) {
  417. if (type.IsReferenceType == true)
  418. return new NullReferenceExpression();
  419. else
  420. return new DefaultValueExpression(ConvertType(type));
  421. } else if (type.Kind == TypeKind.Enum) {
  422. return ConvertEnumValue(type, (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constantValue, false));
  423. } else {
  424. return new PrimitiveExpression(constantValue);
  425. }
  426. }
  427. bool IsFlagsEnum(ITypeDefinition type)
  428. {
  429. IType flagsAttributeType = type.Compilation.FindType(typeof(System.FlagsAttribute));
  430. return type.GetAttribute(flagsAttributeType) != null;
  431. }
  432. Expression ConvertEnumValue(IType type, long val)
  433. {
  434. ITypeDefinition enumDefinition = type.GetDefinition();
  435. TypeCode enumBaseTypeCode = ReflectionHelper.GetTypeCode(enumDefinition.EnumUnderlyingType);
  436. foreach (IField field in enumDefinition.Fields) {
  437. if (field.IsConst && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.ConstantValue, false), val))
  438. return ConvertType(type).Member(field.Name);
  439. }
  440. if (IsFlagsEnum(enumDefinition)) {
  441. long enumValue = val;
  442. Expression expr = null;
  443. long negatedEnumValue = ~val;
  444. // limit negatedEnumValue to the appropriate range
  445. switch (enumBaseTypeCode) {
  446. case TypeCode.Byte:
  447. case TypeCode.SByte:
  448. negatedEnumValue &= byte.MaxValue;
  449. break;
  450. case TypeCode.Int16:
  451. case TypeCode.UInt16:
  452. negatedEnumValue &= ushort.MaxValue;
  453. break;
  454. case TypeCode.Int32:
  455. case TypeCode.UInt32:
  456. negatedEnumValue &= uint.MaxValue;
  457. break;
  458. }
  459. Expression negatedExpr = null;
  460. foreach (IField field in enumDefinition.Fields.Where(fld => fld.IsConst)) {
  461. long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.ConstantValue, false);
  462. if (fieldValue == 0)
  463. continue; // skip None enum value
  464. if ((fieldValue & enumValue) == fieldValue) {
  465. var fieldExpression = ConvertType(type).Member(field.Name);
  466. if (expr == null)
  467. expr = fieldExpression;
  468. else
  469. expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
  470. enumValue &= ~fieldValue;
  471. }
  472. if ((fieldValue & negatedEnumValue) == fieldValue) {
  473. var fieldExpression = ConvertType(type).Member(field.Name);
  474. if (negatedExpr == null)
  475. negatedExpr = fieldExpression;
  476. else
  477. negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression);
  478. negatedEnumValue &= ~fieldValue;
  479. }
  480. }
  481. if (enumValue == 0 && expr != null) {
  482. if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) {
  483. return expr;
  484. }
  485. }
  486. if (negatedEnumValue == 0 && negatedExpr != null) {
  487. return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr);
  488. }
  489. }
  490. return new PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type));
  491. }
  492. #endregion
  493. #region Convert Parameter
  494. public ParameterDeclaration ConvertParameter(IParameter parameter)
  495. {
  496. if (parameter == null)
  497. throw new ArgumentNullException("parameter");
  498. ParameterDeclaration decl = new ParameterDeclaration();
  499. if (parameter.IsRef) {
  500. decl.ParameterModifier = ParameterModifier.Ref;
  501. } else if (parameter.IsOut) {
  502. decl.ParameterModifier = ParameterModifier.Out;
  503. } else if (parameter.IsParams) {
  504. decl.ParameterModifier = ParameterModifier.Params;
  505. }
  506. decl.Type = ConvertType(parameter.Type);
  507. if (this.ShowParameterNames) {
  508. decl.Name = parameter.Name;
  509. }
  510. if (parameter.IsOptional && this.ShowConstantValues) {
  511. decl.DefaultExpression = ConvertConstantValue(parameter.Type, parameter.ConstantValue);
  512. }
  513. return decl;
  514. }
  515. #endregion
  516. #region Convert Entity
  517. public AstNode ConvertSymbol(ISymbol symbol)
  518. {
  519. if (symbol == null)
  520. throw new ArgumentNullException("symbol");
  521. switch (symbol.SymbolKind) {
  522. case SymbolKind.Namespace:
  523. return ConvertNamespaceDeclaration((INamespace)symbol);
  524. case SymbolKind.Variable:
  525. return ConvertVariable((IVariable)symbol);
  526. case SymbolKind.Parameter:
  527. return ConvertParameter((IParameter)symbol);
  528. case SymbolKind.TypeParameter:
  529. return ConvertTypeParameter((ITypeParameter)symbol);
  530. default:
  531. IEntity entity = symbol as IEntity;
  532. if (entity != null)
  533. return ConvertEntity(entity);
  534. throw new ArgumentException("Invalid value for SymbolKind: " + symbol.SymbolKind);
  535. }
  536. }
  537. public EntityDeclaration ConvertEntity(IEntity entity)
  538. {
  539. if (entity == null)
  540. throw new ArgumentNullException("entity");
  541. switch (entity.SymbolKind) {
  542. case SymbolKind.TypeDefinition:
  543. return ConvertTypeDefinition((ITypeDefinition)entity);
  544. case SymbolKind.Field:
  545. return ConvertField((IField)entity);
  546. case SymbolKind.Property:
  547. return ConvertProperty((IProperty)entity);
  548. case SymbolKind.Indexer:
  549. return ConvertIndexer((IProperty)entity);
  550. case SymbolKind.Event:
  551. return ConvertEvent((IEvent)entity);
  552. case SymbolKind.Method:
  553. return ConvertMethod((IMethod)entity);
  554. case SymbolKind.Operator:
  555. return ConvertOperator((IMethod)entity);
  556. case SymbolKind.Constructor:
  557. return ConvertConstructor((IMethod)entity);
  558. case SymbolKind.Destructor:
  559. return ConvertDestructor((IMethod)entity);
  560. case SymbolKind.Accessor:
  561. IMethod accessor = (IMethod)entity;
  562. return ConvertAccessor(accessor, accessor.AccessorOwner != null ? accessor.AccessorOwner.Accessibility : Accessibility.None);
  563. default:
  564. throw new ArgumentException("Invalid value for SymbolKind: " + entity.SymbolKind);
  565. }
  566. }
  567. EntityDeclaration ConvertTypeDefinition(ITypeDefinition typeDefinition)
  568. {
  569. Modifiers modifiers = Modifiers.None;
  570. if (this.ShowAccessibility) {
  571. modifiers |= ModifierFromAccessibility(typeDefinition.Accessibility);
  572. }
  573. if (this.ShowModifiers) {
  574. if (typeDefinition.IsStatic) {
  575. modifiers |= Modifiers.Static;
  576. } else if (typeDefinition.IsAbstract) {
  577. modifiers |= Modifiers.Abstract;
  578. } else if (typeDefinition.IsSealed) {
  579. modifiers |= Modifiers.Sealed;
  580. }
  581. if (typeDefinition.IsShadowing) {
  582. modifiers |= Modifiers.New;
  583. }
  584. }
  585. ClassType classType;
  586. switch (typeDefinition.Kind) {
  587. case TypeKind.Struct:
  588. classType = ClassType.Struct;
  589. modifiers &= ~Modifiers.Sealed;
  590. break;
  591. case TypeKind.Enum:
  592. classType = ClassType.Enum;
  593. modifiers &= ~Modifiers.Sealed;
  594. break;
  595. case TypeKind.Interface:
  596. classType = ClassType.Interface;
  597. modifiers &= ~Modifiers.Abstract;
  598. break;
  599. case TypeKind.Delegate:
  600. IMethod invoke = typeDefinition.GetDelegateInvokeMethod();
  601. if (invoke != null) {
  602. return ConvertDelegate(invoke, modifiers);
  603. } else {
  604. goto default;
  605. }
  606. default:
  607. classType = ClassType.Class;
  608. break;
  609. }
  610. var decl = new TypeDeclaration();
  611. decl.ClassType = classType;
  612. decl.Modifiers = modifiers;
  613. decl.Name = typeDefinition.Name;
  614. int outerTypeParameterCount = (typeDefinition.DeclaringTypeDefinition == null) ? 0 : typeDefinition.DeclaringTypeDefinition.TypeParameterCount;
  615. if (this.ShowTypeParameters) {
  616. foreach (ITypeParameter tp in typeDefinition.TypeParameters.Skip(outerTypeParameterCount)) {
  617. decl.TypeParameters.Add(ConvertTypeParameter(tp));
  618. }
  619. }
  620. if (this.ShowBaseTypes) {
  621. foreach (IType baseType in typeDefinition.DirectBaseTypes) {
  622. decl.BaseTypes.Add(ConvertType(baseType));
  623. }
  624. }
  625. if (this.ShowTypeParameters && this.ShowTypeParameterConstraints) {
  626. foreach (ITypeParameter tp in typeDefinition.TypeParameters) {
  627. var constraint = ConvertTypeParameterConstraint(tp);
  628. if (constraint != null)
  629. decl.Constraints.Add(constraint);
  630. }
  631. }
  632. return decl;
  633. }
  634. DelegateDeclaration ConvertDelegate(IMethod invokeMethod, Modifiers modifiers)
  635. {
  636. ITypeDefinition d = invokeMethod.DeclaringTypeDefinition;
  637. DelegateDeclaration decl = new DelegateDeclaration();
  638. decl.Modifiers = modifiers & ~Modifiers.Sealed;
  639. decl.ReturnType = ConvertType(invokeMethod.ReturnType);
  640. decl.Name = d.Name;
  641. if (this.ShowTypeParameters) {
  642. foreach (ITypeParameter tp in d.TypeParameters) {
  643. decl.TypeParameters.Add(ConvertTypeParameter(tp));
  644. }
  645. }
  646. foreach (IParameter p in invokeMethod.Parameters) {
  647. decl.Parameters.Add(ConvertParameter(p));
  648. }
  649. if (this.ShowTypeParameters && this.ShowTypeParameterConstraints) {
  650. foreach (ITypeParameter tp in d.TypeParameters) {
  651. var constraint = ConvertTypeParameterConstraint(tp);
  652. if (constraint != null)
  653. decl.Constraints.Add(constraint);
  654. }
  655. }
  656. return decl;
  657. }
  658. FieldDeclaration ConvertField(IField field)
  659. {
  660. FieldDeclaration decl = new FieldDeclaration();
  661. if (ShowModifiers) {
  662. Modifiers m = GetMemberModifiers(field);
  663. if (field.IsConst) {
  664. m &= ~Modifiers.Static;
  665. m |= Modifiers.Const;
  666. } else if (field.IsReadOnly) {
  667. m |= Modifiers.Readonly;
  668. } else if (field.IsVolatile) {
  669. m |= Modifiers.Volatile;
  670. }
  671. decl.Modifiers = m;
  672. }
  673. decl.ReturnType = ConvertType(field.ReturnType);
  674. Expression initializer = null;
  675. if (field.IsConst && this.ShowConstantValues)
  676. initializer = ConvertConstantValue(field.Type, field.ConstantValue);
  677. decl.Variables.Add(new VariableInitializer(field.Name, initializer));
  678. return decl;
  679. }
  680. BlockStatement GenerateBodyBlock()
  681. {
  682. if (GenerateBody) {
  683. return new BlockStatement {
  684. new ThrowStatement(new ObjectCreateExpression(ConvertType(new TopLevelTypeName("System", "NotImplementedException", 0))))
  685. };
  686. } else {
  687. return BlockStatement.Null;
  688. }
  689. }
  690. Accessor ConvertAccessor(IMethod accessor, Accessibility ownerAccessibility)
  691. {
  692. if (accessor == null)
  693. return Accessor.Null;
  694. Accessor decl = new Accessor();
  695. if (this.ShowAccessibility && accessor.Accessibility != ownerAccessibility)
  696. decl.Modifiers = ModifierFromAccessibility(accessor.Accessibility);
  697. decl.Body = GenerateBodyBlock();
  698. return decl;
  699. }
  700. PropertyDeclaration ConvertProperty(IProperty property)
  701. {
  702. PropertyDeclaration decl = new PropertyDeclaration();
  703. decl.Modifiers = GetMemberModifiers(property);
  704. decl.ReturnType = ConvertType(property.ReturnType);
  705. decl.Name = property.Name;
  706. decl.Getter = ConvertAccessor(property.Getter, property.Accessibility);
  707. decl.Setter = ConvertAccessor(property.Setter, property.Accessibility);
  708. return decl;
  709. }
  710. IndexerDeclaration ConvertIndexer(IProperty indexer)
  711. {
  712. IndexerDeclaration decl = new IndexerDeclaration();
  713. decl.Modifiers = GetMemberModifiers(indexer);
  714. decl.ReturnType = ConvertType(indexer.ReturnType);
  715. foreach (IParameter p in indexer.Parameters) {
  716. decl.Parameters.Add(ConvertParameter(p));
  717. }
  718. decl.Getter = ConvertAccessor(indexer.Getter, indexer.Accessibility);
  719. decl.Setter = ConvertAccessor(indexer.Setter, indexer.Accessibility);
  720. return decl;
  721. }
  722. EntityDeclaration ConvertEvent(IEvent ev)
  723. {
  724. if (this.UseCustomEvents) {
  725. CustomEventDeclaration decl = new CustomEventDeclaration();
  726. decl.Modifiers = GetMemberModifiers(ev);
  727. decl.ReturnType = ConvertType(ev.ReturnType);
  728. decl.Name = ev.Name;
  729. decl.AddAccessor = ConvertAccessor(ev.AddAccessor, ev.Accessibility);
  730. decl.RemoveAccessor = ConvertAccessor(ev.RemoveAccessor, ev.Accessibility);
  731. return decl;
  732. } else {
  733. EventDeclaration decl = new EventDeclaration();
  734. decl.Modifiers = GetMemberModifiers(ev);
  735. decl.ReturnType = ConvertType(ev.ReturnType);
  736. decl.Variables.Add(new VariableInitializer(ev.Name));
  737. return decl;
  738. }
  739. }
  740. MethodDeclaration ConvertMethod(IMethod method)
  741. {
  742. MethodDeclaration decl = new MethodDeclaration();
  743. decl.Modifiers = GetMemberModifiers(method);
  744. if (method.IsAsync && ShowModifiers)
  745. decl.Modifiers |= Modifiers.Async;
  746. decl.ReturnType = ConvertType(method.ReturnType);
  747. decl.Name = method.Name;
  748. if (this.ShowTypeParameters) {
  749. foreach (ITypeParameter tp in method.TypeParameters) {
  750. decl.TypeParameters.Add(ConvertTypeParameter(tp));
  751. }
  752. }
  753. foreach (IParameter p in method.Parameters) {
  754. decl.Parameters.Add(ConvertParameter(p));
  755. }
  756. if (method.IsExtensionMethod && method.ReducedFrom == null && decl.Parameters.Any() && decl.Parameters.First().ParameterModifier == ParameterModifier.None)
  757. decl.Parameters.First().ParameterModifier = ParameterModifier.This;
  758. if (this.ShowTypeParameters && this.ShowTypeParameterConstraints && !method.IsOverride && !method.IsExplicitInterfaceImplementation) {
  759. foreach (ITypeParameter tp in method.TypeParameters) {
  760. var constraint = ConvertTypeParameterConstraint(tp);
  761. if (constraint != null)
  762. decl.Constraints.Add(constraint);
  763. }
  764. }
  765. decl.Body = GenerateBodyBlock();
  766. return decl;
  767. }
  768. EntityDeclaration ConvertOperator(IMethod op)
  769. {
  770. OperatorType? opType = OperatorDeclaration.GetOperatorType(op.Name);
  771. if (opType == null)
  772. return ConvertMethod(op);
  773. OperatorDeclaration decl = new OperatorDeclaration();
  774. decl.Modifiers = GetMemberModifiers(op);
  775. decl.OperatorType = opType.Value;
  776. decl.ReturnType = ConvertType(op.ReturnType);
  777. foreach (IParameter p in op.Parameters) {
  778. decl.Parameters.Add(ConvertParameter(p));
  779. }
  780. decl.Body = GenerateBodyBlock();
  781. return decl;
  782. }
  783. ConstructorDeclaration ConvertConstructor(IMethod ctor)
  784. {
  785. ConstructorDeclaration decl = new ConstructorDeclaration();
  786. decl.Modifiers = GetMemberModifiers(ctor);
  787. if (ctor.DeclaringTypeDefinition != null)
  788. decl.Name = ctor.DeclaringTypeDefinition.Name;
  789. foreach (IParameter p in ctor.Parameters) {
  790. decl.Parameters.Add(ConvertParameter(p));
  791. }
  792. decl.Body = GenerateBodyBlock();
  793. return decl;
  794. }
  795. DestructorDeclaration ConvertDestructor(IMethod dtor)
  796. {
  797. DestructorDeclaration decl = new DestructorDeclaration();
  798. if (dtor.DeclaringTypeDefinition != null)
  799. decl.Name = dtor.DeclaringTypeDefinition.Name;
  800. decl.Body = GenerateBodyBlock();
  801. return decl;
  802. }
  803. #endregion
  804. #region Convert Modifiers
  805. public static Modifiers ModifierFromAccessibility(Accessibility accessibility)
  806. {
  807. switch (accessibility) {
  808. case Accessibility.Private:
  809. return Modifiers.Private;
  810. case Accessibility.Public:
  811. return Modifiers.Public;
  812. case Accessibility.Protected:
  813. return Modifiers.Protected;
  814. case Accessibility.Internal:
  815. return Modifiers.Internal;
  816. case Accessibility.ProtectedOrInternal:
  817. case Accessibility.ProtectedAndInternal:
  818. return Modifiers.Protected | Modifiers.Internal;
  819. default:
  820. return Modifiers.None;
  821. }
  822. }
  823. Modifiers GetMemberModifiers(IMember member)
  824. {
  825. bool isInterfaceMember = member.DeclaringType.Kind == TypeKind.Interface;
  826. Modifiers m = Modifiers.None;
  827. if (this.ShowAccessibility && !isInterfaceMember) {
  828. m |= ModifierFromAccessibility(member.Accessibility);
  829. }
  830. if (this.ShowModifiers) {
  831. if (member.IsStatic) {
  832. m |= Modifiers.Static;
  833. } else {
  834. if (member.IsAbstract && !isInterfaceMember)
  835. m |= Modifiers.Abstract;
  836. if (member.IsOverride)
  837. m |= Modifiers.Override;
  838. if (member.IsVirtual && !member.IsAbstract && !member.IsOverride)
  839. m |= Modifiers.Virtual;
  840. if (member.IsSealed)
  841. m |= Modifiers.Sealed;
  842. }
  843. if (member.IsShadowing)
  844. m |= Modifiers.New;
  845. }
  846. return m;
  847. }
  848. #endregion
  849. #region Convert Type Parameter
  850. TypeParameterDeclaration ConvertTypeParameter(ITypeParameter tp)
  851. {
  852. TypeParameterDeclaration decl = new TypeParameterDeclaration();
  853. decl.Variance = tp.Variance;
  854. decl.Name = tp.Name;
  855. return decl;
  856. }
  857. Constraint ConvertTypeParameterConstraint(ITypeParameter tp)
  858. {
  859. if (!tp.HasDefaultConstructorConstraint && !tp.HasReferenceTypeConstraint && !tp.HasValueTypeConstraint && tp.DirectBaseTypes.All(IsObjectOrValueType)) {
  860. return null;
  861. }
  862. Constraint c = new Constraint();
  863. c.TypeParameter = new SimpleType (tp.Name);
  864. if (tp.HasReferenceTypeConstraint) {
  865. c.BaseTypes.Add(new PrimitiveType("class"));
  866. } else if (tp.HasValueTypeConstraint) {
  867. c.BaseTypes.Add(new PrimitiveType("struct"));
  868. }
  869. foreach (IType t in tp.DirectBaseTypes) {
  870. if (!IsObjectOrValueType(t))
  871. c.BaseTypes.Add(ConvertType(t));
  872. }
  873. if (tp.HasDefaultConstructorConstraint) {
  874. c.BaseTypes.Add(new PrimitiveType("new"));
  875. }
  876. return c;
  877. }
  878. static bool IsObjectOrValueType(IType type)
  879. {
  880. ITypeDefinition d = type.GetDefinition();
  881. return d != null && (d.KnownTypeCode == KnownTypeCode.Object || d.KnownTypeCode == KnownTypeCode.ValueType);
  882. }
  883. #endregion
  884. #region Convert Variable
  885. public VariableDeclarationStatement ConvertVariable(IVariable v)
  886. {
  887. VariableDeclarationStatement decl = new VariableDeclarationStatement();
  888. decl.Modifiers = v.IsConst ? Modifiers.Const : Modifiers.None;
  889. decl.Type = ConvertType(v.Type);
  890. Expression initializer = null;
  891. if (v.IsConst)
  892. initializer = ConvertConstantValue(v.Type, v.ConstantValue);
  893. decl.Variables.Add(new VariableInitializer(v.Name, initializer));
  894. return decl;
  895. }
  896. #endregion
  897. NamespaceDeclaration ConvertNamespaceDeclaration(INamespace ns)
  898. {
  899. return new NamespaceDeclaration(ns.FullName);
  900. }
  901. }
  902. }