PageRenderTime 63ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/sharadag/Roslyn
C# | 321 lines | 285 code | 32 blank | 4 comment | 81 complexity | a4df1f3b24321e9c0c8d9ba97a3222d5 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;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.Linq;
  6. using Microsoft.CodeAnalysis.CodeGeneration;
  7. using Microsoft.CodeAnalysis.CSharp.Extensions;
  8. using Microsoft.CodeAnalysis.CSharp.Symbols;
  9. using Microsoft.CodeAnalysis.CSharp.Syntax;
  10. using Microsoft.CodeAnalysis.Shared.Extensions;
  11. using Microsoft.CodeAnalysis.Shared.Utilities;
  12. using Microsoft.CodeAnalysis.Simplification;
  13. using Roslyn.Utilities;
  14. using static Microsoft.CodeAnalysis.CodeGeneration.CodeGenerationHelpers;
  15. namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration
  16. {
  17. internal static class ExpressionGenerator
  18. {
  19. internal static ExpressionSyntax GenerateExpression(
  20. TypedConstant typedConstant)
  21. {
  22. switch (typedConstant.Kind)
  23. {
  24. case TypedConstantKind.Primitive:
  25. case TypedConstantKind.Enum:
  26. return GenerateExpression(typedConstant.Type, typedConstant.Value, canUseFieldReference: true);
  27. case TypedConstantKind.Type:
  28. return typedConstant.Value is ITypeSymbol
  29. ? SyntaxFactory.TypeOfExpression(((ITypeSymbol)typedConstant.Value).GenerateTypeSyntax())
  30. : GenerateNullLiteral();
  31. case TypedConstantKind.Array:
  32. return typedConstant.IsNull ?
  33. GenerateNullLiteral() :
  34. SyntaxFactory.ImplicitArrayCreationExpression(
  35. SyntaxFactory.InitializerExpression(SyntaxKind.ArrayInitializerExpression,
  36. SyntaxFactory.SeparatedList(typedConstant.Values.Select(GenerateExpression))));
  37. default:
  38. return GenerateNullLiteral();
  39. }
  40. }
  41. private static ExpressionSyntax GenerateNullLiteral()
  42. {
  43. return SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression);
  44. }
  45. internal static ExpressionSyntax GenerateExpression(
  46. ITypeSymbol type,
  47. object value,
  48. bool canUseFieldReference)
  49. {
  50. if (value != null)
  51. {
  52. if (type.TypeKind == TypeKind.Enum)
  53. {
  54. var enumType = (INamedTypeSymbol)type;
  55. return (ExpressionSyntax)CSharpFlagsEnumGenerator.Instance.CreateEnumConstantValue(enumType, value);
  56. }
  57. else if (type.IsNullable())
  58. {
  59. // If the type of the argument is T?, then the type of the supplied default value can either be T
  60. // (e.g. int? x = 5) or it can be T? (e.g. SomeStruct? x = null). The below statement handles the case
  61. // where the type of the supplied default value is T.
  62. return GenerateExpression(((INamedTypeSymbol)type).TypeArguments[0], value, canUseFieldReference);
  63. }
  64. }
  65. return GenerateNonEnumValueExpression(type, value, canUseFieldReference);
  66. }
  67. internal static ExpressionSyntax GenerateNonEnumValueExpression(
  68. ITypeSymbol type, object value, bool canUseFieldReference)
  69. {
  70. if (value is bool)
  71. {
  72. return SyntaxFactory.LiteralExpression((bool)value
  73. ? SyntaxKind.TrueLiteralExpression
  74. : SyntaxKind.FalseLiteralExpression);
  75. }
  76. else if (value is string)
  77. {
  78. var valueString = SymbolDisplay.FormatLiteral((string)value, quote: true);
  79. return SyntaxFactory.LiteralExpression(
  80. SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(valueString, (string)value));
  81. }
  82. else if (value is char)
  83. {
  84. var charValue = (char)value;
  85. var literal = SymbolDisplay.FormatLiteral(charValue, quote: true);
  86. return SyntaxFactory.LiteralExpression(
  87. SyntaxKind.CharacterLiteralExpression, SyntaxFactory.Literal(literal, charValue));
  88. }
  89. else if (value is sbyte)
  90. {
  91. return GenerateLiteralExpression(type, (sbyte)value, LiteralSpecialValues.SByteSpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v));
  92. }
  93. else if (value is short)
  94. {
  95. return GenerateLiteralExpression(type, (short)value, LiteralSpecialValues.Int16SpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v));
  96. }
  97. else if (value is int)
  98. {
  99. return GenerateLiteralExpression(type, (int)value, LiteralSpecialValues.Int32SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
  100. }
  101. else if (value is long)
  102. {
  103. return GenerateLiteralExpression(type, (long)value, LiteralSpecialValues.Int64SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
  104. }
  105. else if (value is byte)
  106. {
  107. return GenerateLiteralExpression(type, (byte)value, LiteralSpecialValues.ByteSpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v));
  108. }
  109. else if (value is ushort)
  110. {
  111. return GenerateLiteralExpression(type, (ushort)value, LiteralSpecialValues.UInt16SpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, (uint)v));
  112. }
  113. else if (value is uint)
  114. {
  115. return GenerateLiteralExpression(type, (uint)value, LiteralSpecialValues.UInt32SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
  116. }
  117. else if (value is ulong)
  118. {
  119. return GenerateLiteralExpression(type, (ulong)value, LiteralSpecialValues.UInt64SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
  120. }
  121. else if (value is float)
  122. {
  123. return GenerateSingleLiteralExpression(type, (float)value, canUseFieldReference);
  124. }
  125. else if (value is double)
  126. {
  127. return GenerateDoubleLiteralExpression(type, (double)value, canUseFieldReference);
  128. }
  129. else if (value is decimal)
  130. {
  131. return GenerateLiteralExpression(type, (decimal)value, LiteralSpecialValues.DecimalSpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
  132. }
  133. else if (type == null || type.IsReferenceType || type.IsPointerType())
  134. {
  135. return GenerateNullLiteral();
  136. }
  137. else
  138. {
  139. return SyntaxFactory.DefaultExpression(type.GenerateTypeSyntax());
  140. }
  141. }
  142. private static string DetermineSuffix(ITypeSymbol type, object value)
  143. {
  144. if (value is float)
  145. {
  146. var f = (float)value;
  147. var stringValue = ((IFormattable)value).ToString("R", CultureInfo.InvariantCulture);
  148. var isNotSingle = !IsSpecialType(type, SpecialType.System_Single);
  149. var containsDoubleCharacter =
  150. stringValue.Contains("E") || stringValue.Contains("e") || stringValue.Contains(".") ||
  151. stringValue.Contains("+") || stringValue.Contains("-");
  152. if (isNotSingle || containsDoubleCharacter)
  153. {
  154. return "F";
  155. }
  156. }
  157. if (value is double && !IsSpecialType(type, SpecialType.System_Double))
  158. {
  159. return "D";
  160. }
  161. if (value is uint && !IsSpecialType(type, SpecialType.System_UInt32))
  162. {
  163. return "U";
  164. }
  165. if (value is long && !IsSpecialType(type, SpecialType.System_Int64))
  166. {
  167. return "L";
  168. }
  169. if (value is ulong && !IsSpecialType(type, SpecialType.System_UInt64))
  170. {
  171. return "UL";
  172. }
  173. if (value is decimal)
  174. {
  175. var d = (decimal)value;
  176. var scale = d.GetScale();
  177. var isNotDecimal = !IsSpecialType(type, SpecialType.System_Decimal);
  178. var isOutOfRange = d < long.MinValue || d > long.MaxValue;
  179. var scaleIsNotZero = scale != 0;
  180. if (isNotDecimal || isOutOfRange || scaleIsNotZero)
  181. {
  182. return "M";
  183. }
  184. }
  185. return string.Empty;
  186. }
  187. private static ExpressionSyntax GenerateDoubleLiteralExpression(ITypeSymbol type, double value, bool canUseFieldReference)
  188. {
  189. if (!canUseFieldReference)
  190. {
  191. if (double.IsNaN(value))
  192. {
  193. return SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression,
  194. GenerateDoubleLiteralExpression(null, 0.0, false),
  195. GenerateDoubleLiteralExpression(null, 0.0, false));
  196. }
  197. else if (double.IsPositiveInfinity(value))
  198. {
  199. return SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression,
  200. GenerateDoubleLiteralExpression(null, 1.0, false),
  201. GenerateDoubleLiteralExpression(null, 0.0, false));
  202. }
  203. else if (double.IsNegativeInfinity(value))
  204. {
  205. return SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression,
  206. SyntaxFactory.PrefixUnaryExpression(SyntaxKind.UnaryMinusExpression, GenerateDoubleLiteralExpression(null, 1.0, false)),
  207. GenerateDoubleLiteralExpression(null, 0.0, false));
  208. }
  209. }
  210. return GenerateLiteralExpression(type, value, LiteralSpecialValues.DoubleSpecialValues, "R", canUseFieldReference, SyntaxFactory.Literal);
  211. }
  212. private static ExpressionSyntax GenerateSingleLiteralExpression(ITypeSymbol type, float value, bool canUseFieldReference)
  213. {
  214. if (!canUseFieldReference)
  215. {
  216. if (float.IsNaN(value))
  217. {
  218. return SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression,
  219. GenerateSingleLiteralExpression(null, 0.0F, false),
  220. GenerateSingleLiteralExpression(null, 0.0F, false));
  221. }
  222. else if (float.IsPositiveInfinity(value))
  223. {
  224. return SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression,
  225. GenerateSingleLiteralExpression(null, 1.0F, false),
  226. GenerateSingleLiteralExpression(null, 0.0F, false));
  227. }
  228. else if (float.IsNegativeInfinity(value))
  229. {
  230. return SyntaxFactory.BinaryExpression(SyntaxKind.DivideExpression,
  231. SyntaxFactory.PrefixUnaryExpression(SyntaxKind.UnaryMinusExpression, GenerateSingleLiteralExpression(null, 1.0F, false)),
  232. GenerateSingleLiteralExpression(null, 0.0F, false));
  233. }
  234. }
  235. return GenerateLiteralExpression(type, value, LiteralSpecialValues.SingleSpecialValues, "R", canUseFieldReference, SyntaxFactory.Literal);
  236. }
  237. private static ExpressionSyntax GenerateLiteralExpression<T>(
  238. ITypeSymbol type, T value, IEnumerable<KeyValuePair<T, string>> constants, string formatString, bool canUseFieldReference, Func<string, T, SyntaxToken> tokenFactory)
  239. {
  240. if (canUseFieldReference)
  241. {
  242. var result = GenerateFieldReference(type, value, constants);
  243. if (result != null)
  244. {
  245. return result;
  246. }
  247. }
  248. var suffix = DetermineSuffix(type, value);
  249. var stringValue = ((IFormattable)value).ToString(formatString, CultureInfo.InvariantCulture) + suffix;
  250. return SyntaxFactory.LiteralExpression(
  251. SyntaxKind.NumericLiteralExpression, tokenFactory(stringValue, value));
  252. }
  253. private static ExpressionSyntax GenerateFieldReference<T>(ITypeSymbol type, T value, IEnumerable<KeyValuePair<T, string>> constants)
  254. {
  255. foreach (var constant in constants)
  256. {
  257. if (constant.Key.Equals(value))
  258. {
  259. var memberAccess = GenerateMemberAccess("System", typeof(T).Name);
  260. if (type != null && !(type is IErrorTypeSymbol))
  261. {
  262. memberAccess = memberAccess.WithAdditionalAnnotations(SpecialTypeAnnotation.Create(type.SpecialType));
  263. }
  264. var result = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, memberAccess, SyntaxFactory.IdentifierName(constant.Value));
  265. return result.WithAdditionalAnnotations(Simplifier.Annotation);
  266. }
  267. }
  268. return null;
  269. }
  270. private static ExpressionSyntax GenerateMemberAccess(params string[] names)
  271. {
  272. ExpressionSyntax result = SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.GlobalKeyword));
  273. for (int i = 0; i < names.Length; i++)
  274. {
  275. var name = SyntaxFactory.IdentifierName(names[i]);
  276. if (i == 0)
  277. {
  278. result = SyntaxFactory.AliasQualifiedName((IdentifierNameSyntax)result, name);
  279. }
  280. else
  281. {
  282. result = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, result, name);
  283. }
  284. }
  285. result = result.WithAdditionalAnnotations(Simplifier.Annotation);
  286. return result;
  287. }
  288. }
  289. }