PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs

https://gitlab.com/sharadag/Roslyn
C# | 242 lines | 200 code | 37 blank | 5 comment | 26 complexity | 626c1a6c68852e53e8bf8b18892631a5 MD5 | raw file
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.CodeAnalysis.CodeGeneration;
  5. using Microsoft.CodeAnalysis.CSharp.Extensions;
  6. using Microsoft.CodeAnalysis.CSharp.Symbols;
  7. using Microsoft.CodeAnalysis.CSharp.Syntax;
  8. using Roslyn.Utilities;
  9. using static Microsoft.CodeAnalysis.CodeGeneration.CodeGenerationHelpers;
  10. using static Microsoft.CodeAnalysis.CSharp.CodeGeneration.CSharpCodeGenerationHelpers;
  11. namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration
  12. {
  13. internal static class PropertyGenerator
  14. {
  15. public static bool CanBeGenerated(IPropertySymbol property)
  16. {
  17. return property.IsIndexer || property.Parameters.Length == 0;
  18. }
  19. private static MemberDeclarationSyntax LastPropertyOrField(
  20. SyntaxList<MemberDeclarationSyntax> members)
  21. {
  22. var lastProperty = members.LastOrDefault(m => m is PropertyDeclarationSyntax);
  23. return lastProperty ?? LastField(members);
  24. }
  25. internal static CompilationUnitSyntax AddPropertyTo(
  26. CompilationUnitSyntax destination,
  27. IPropertySymbol property,
  28. CodeGenerationOptions options,
  29. IList<bool> availableIndices)
  30. {
  31. var declaration = GeneratePropertyOrIndexer(property, CodeGenerationDestination.CompilationUnit, options);
  32. var members = Insert(destination.Members, declaration, options,
  33. availableIndices, after: LastPropertyOrField, before: FirstMember);
  34. return destination.WithMembers(members);
  35. }
  36. internal static TypeDeclarationSyntax AddPropertyTo(
  37. TypeDeclarationSyntax destination,
  38. IPropertySymbol property,
  39. CodeGenerationOptions options,
  40. IList<bool> availableIndices)
  41. {
  42. var declaration = GeneratePropertyOrIndexer(property, GetDestination(destination), options);
  43. // Create a clone of the original type with the new method inserted.
  44. var members = Insert(destination.Members, declaration, options,
  45. availableIndices, after: LastPropertyOrField, before: FirstMember);
  46. // Find the best place to put the field. It should go after the last field if we already
  47. // have fields, or at the beginning of the file if we don't.
  48. return AddMembersTo(destination, members);
  49. }
  50. public static MemberDeclarationSyntax GeneratePropertyOrIndexer(
  51. IPropertySymbol property,
  52. CodeGenerationDestination destination,
  53. CodeGenerationOptions options)
  54. {
  55. var reusableSyntax = GetReuseableSyntaxNodeForSymbol<MemberDeclarationSyntax>(property, options);
  56. if (reusableSyntax != null)
  57. {
  58. return reusableSyntax;
  59. }
  60. var declaration = property.IsIndexer
  61. ? GenerateIndexerDeclaration(property, destination, options)
  62. : GeneratePropertyDeclaration(property, destination, options);
  63. return ConditionallyAddDocumentationCommentTo(declaration, property, options);
  64. }
  65. private static MemberDeclarationSyntax GenerateIndexerDeclaration(
  66. IPropertySymbol property,
  67. CodeGenerationDestination destination,
  68. CodeGenerationOptions options)
  69. {
  70. var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(property.ExplicitInterfaceImplementations);
  71. return AddCleanupAnnotationsTo(
  72. AddAnnotationsTo(property, SyntaxFactory.IndexerDeclaration(
  73. attributeLists: AttributeGenerator.GenerateAttributeLists(property.GetAttributes(), options),
  74. modifiers: GenerateModifiers(property, destination, options),
  75. type: property.Type.GenerateTypeSyntax(),
  76. explicitInterfaceSpecifier: explicitInterfaceSpecifier,
  77. parameterList: ParameterGenerator.GenerateBracketedParameterList(property.Parameters, explicitInterfaceSpecifier != null, options),
  78. accessorList: GenerateAccessorList(property, destination, options))));
  79. }
  80. private static MemberDeclarationSyntax GeneratePropertyDeclaration(
  81. IPropertySymbol property, CodeGenerationDestination destination, CodeGenerationOptions options)
  82. {
  83. var initializerNode = CodeGenerationPropertyInfo.GetInitializer(property) as ExpressionSyntax;
  84. var initializer = initializerNode != null
  85. ? SyntaxFactory.EqualsValueClause(initializerNode)
  86. : default(EqualsValueClauseSyntax);
  87. var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(property.ExplicitInterfaceImplementations);
  88. var accessorList = GenerateAccessorList(property, destination, options);
  89. return AddCleanupAnnotationsTo(
  90. AddAnnotationsTo(property, SyntaxFactory.PropertyDeclaration(
  91. attributeLists: AttributeGenerator.GenerateAttributeLists(property.GetAttributes(), options),
  92. modifiers: GenerateModifiers(property, destination, options),
  93. type: property.Type.GenerateTypeSyntax(),
  94. explicitInterfaceSpecifier: explicitInterfaceSpecifier,
  95. identifier: property.Name.ToIdentifierToken(),
  96. accessorList: accessorList,
  97. expressionBody: default(ArrowExpressionClauseSyntax),
  98. initializer: initializer)));
  99. }
  100. private static AccessorListSyntax GenerateAccessorList(
  101. IPropertySymbol property, CodeGenerationDestination destination, CodeGenerationOptions options)
  102. {
  103. var accessors = new List<AccessorDeclarationSyntax>
  104. {
  105. GenerateAccessorDeclaration(property, property.GetMethod, SyntaxKind.GetAccessorDeclaration, destination, options),
  106. GenerateAccessorDeclaration(property, property.SetMethod, SyntaxKind.SetAccessorDeclaration, destination, options),
  107. };
  108. return accessors[0] == null && accessors[1] == null
  109. ? null
  110. : SyntaxFactory.AccessorList(accessors.WhereNotNull().ToSyntaxList());
  111. }
  112. private static AccessorDeclarationSyntax GenerateAccessorDeclaration(
  113. IPropertySymbol property,
  114. IMethodSymbol accessor,
  115. SyntaxKind kind,
  116. CodeGenerationDestination destination,
  117. CodeGenerationOptions options)
  118. {
  119. var hasBody = options.GenerateMethodBodies && HasAccessorBodies(property, destination, accessor);
  120. return accessor == null
  121. ? null
  122. : GenerateAccessorDeclaration(property, accessor, kind, hasBody, options);
  123. }
  124. private static AccessorDeclarationSyntax GenerateAccessorDeclaration(
  125. IPropertySymbol property,
  126. IMethodSymbol accessor,
  127. SyntaxKind kind,
  128. bool hasBody,
  129. CodeGenerationOptions options)
  130. {
  131. return AddAnnotationsTo(accessor, SyntaxFactory.AccessorDeclaration(kind)
  132. .WithModifiers(GenerateAccessorModifiers(property, accessor, options))
  133. .WithBody(hasBody ? GenerateBlock(accessor) : null)
  134. .WithSemicolonToken(hasBody ? default(SyntaxToken) : SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
  135. }
  136. private static BlockSyntax GenerateBlock(IMethodSymbol accessor)
  137. {
  138. return SyntaxFactory.Block(
  139. StatementGenerator.GenerateStatements(CodeGenerationMethodInfo.GetStatements(accessor)));
  140. }
  141. private static bool HasAccessorBodies(
  142. IPropertySymbol property,
  143. CodeGenerationDestination destination,
  144. IMethodSymbol accessor)
  145. {
  146. return destination != CodeGenerationDestination.InterfaceType &&
  147. !property.IsAbstract &&
  148. accessor != null &&
  149. !accessor.IsAbstract;
  150. }
  151. private static SyntaxTokenList GenerateAccessorModifiers(
  152. IPropertySymbol property,
  153. IMethodSymbol accessor,
  154. CodeGenerationOptions options)
  155. {
  156. if (accessor.DeclaredAccessibility == Accessibility.NotApplicable ||
  157. accessor.DeclaredAccessibility == property.DeclaredAccessibility)
  158. {
  159. return new SyntaxTokenList();
  160. }
  161. var modifiers = new List<SyntaxToken>();
  162. AddAccessibilityModifiers(accessor.DeclaredAccessibility, modifiers, options, property.DeclaredAccessibility);
  163. return modifiers.ToSyntaxTokenList();
  164. }
  165. private static SyntaxTokenList GenerateModifiers(
  166. IPropertySymbol property, CodeGenerationDestination destination, CodeGenerationOptions options)
  167. {
  168. var tokens = new List<SyntaxToken>();
  169. // Most modifiers not allowed if we're an explicit impl.
  170. if (!property.ExplicitInterfaceImplementations.Any())
  171. {
  172. if (destination != CodeGenerationDestination.CompilationUnit &&
  173. destination != CodeGenerationDestination.InterfaceType)
  174. {
  175. AddAccessibilityModifiers(property.DeclaredAccessibility, tokens, options, Accessibility.Private);
  176. if (property.IsStatic)
  177. {
  178. tokens.Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword));
  179. }
  180. if (property.IsSealed)
  181. {
  182. tokens.Add(SyntaxFactory.Token(SyntaxKind.SealedKeyword));
  183. }
  184. if (property.IsOverride)
  185. {
  186. tokens.Add(SyntaxFactory.Token(SyntaxKind.OverrideKeyword));
  187. }
  188. if (property.IsVirtual)
  189. {
  190. tokens.Add(SyntaxFactory.Token(SyntaxKind.VirtualKeyword));
  191. }
  192. if (property.IsAbstract)
  193. {
  194. tokens.Add(SyntaxFactory.Token(SyntaxKind.AbstractKeyword));
  195. }
  196. }
  197. }
  198. if (CodeGenerationPropertyInfo.GetIsUnsafe(property))
  199. {
  200. tokens.Add(SyntaxFactory.Token(SyntaxKind.UnsafeKeyword));
  201. }
  202. return tokens.ToSyntaxTokenList();
  203. }
  204. }
  205. }