using System.IO; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { internal class Literal : Expression { private Literal(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info))) { } public static Expression Create(ExpressionNodeInfo info) => new Literal(info).TryPopulate(); protected override void PopulateExpression(TextWriter trapFile) { } private static ExprKind GetKind(ExpressionNodeInfo info) { switch (info.Node.Kind()) { case SyntaxKind.DefaultLiteralExpression: return ExprKind.DEFAULT; case SyntaxKind.Utf8StringLiteralExpression: return ExprKind.UTF8_STRING_LITERAL; case SyntaxKind.NullLiteralExpression: info.SetType(null); // Don't use converted type. return ExprKind.NULL_LITERAL; } // short circuit bool literals, because they have no type in `#if A = true` if (info.IsBoolLiteral()) { return ExprKind.BOOL_LITERAL; } var type = info.Type?.Symbol; return GetExprKind(type, info.Node, info.Location, info.Context); } private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Location loc, Context context) { switch (type?.SpecialType) { case SpecialType.System_Boolean: return ExprKind.BOOL_LITERAL; case SpecialType.System_Int16: case SpecialType.System_Int32: case SpecialType.System_Byte: // ?? return ExprKind.INT_LITERAL; case SpecialType.System_Char: return ExprKind.CHAR_LITERAL; case SpecialType.System_Decimal: return ExprKind.DECIMAL_LITERAL; case SpecialType.System_Double: return ExprKind.DOUBLE_LITERAL; case SpecialType.System_Int64: return ExprKind.LONG_LITERAL; case SpecialType.System_Single: return ExprKind.FLOAT_LITERAL; case SpecialType.System_String: return ExprKind.UTF16_STRING_LITERAL; case SpecialType.System_UInt16: case SpecialType.System_UInt32: case SpecialType.System_SByte: // ?? return ExprKind.UINT_LITERAL; case SpecialType.System_UInt64: return ExprKind.ULONG_LITERAL; case null: default: var kind = type?.SpecialType.ToString() ?? "null"; if (expr is not null) context.ModelError(expr, $"Unhandled literal type {kind}"); else context.ModelError(loc, $"Unhandled literal type {kind}"); return ExprKind.UNKNOWN; } } public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value, Location location) { var kind = value is null ? ExprKind.NULL_LITERAL : GetExprKind(type, null, location, cx); var info = new ExpressionInfo( cx, AnnotatedTypeSymbol.CreateNotAnnotated(type), location, kind, parent, childIndex, isCompilerGenerated: true, ValueAsString(value)); return new Expression(info); } public static Expression CreateGeneratedNullLiteral(Context cx, IExpressionParentEntity parent, int childIndex, Location location) { var info = new ExpressionInfo( cx, null, location, ExprKind.NULL_LITERAL, parent, childIndex, isCompilerGenerated: true, ValueAsString(null)); return new Expression(info); } } }