using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Populators; using Semmle.Extraction.Kinds; namespace Semmle.Extraction.CSharp.Entities.Expressions { class ImplicitCast : Expression { public Expression Expr { get; private set; } public ImplicitCast(ExpressionNodeInfo info) : base(new ExpressionInfo(info.Context, Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.CAST, info.Parent, info.Child, true, info.ExprValue)) { Expr = Factory.Create(new ExpressionNodeInfo(cx, info.Node, this, 0)); } public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) : base(new ExpressionInfo(info.Context, Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue) ) { Expr = Factory.Create(info.SetParent(this, 0)); var target = Method.Create(cx, method); if (target != null) cx.Emit(Tuples.expr_call(this, target)); else cx.ModelError(info.Node, "Failed to resolve target for operator invocation"); } /// /// Creates a new expression, adding casts as required. /// /// The extraction context. /// The expression node. /// The parent of the expression. /// The child number. /// A type hint. /// A new expression. public static Expression Create(ExpressionNodeInfo info) { var resolvedType = info.ResolvedType; var convertedType = info.ConvertedType; var conversion = info.Conversion; if (conversion.MethodSymbol != null) { bool convertedToDelegate = Type.IsDelegate(convertedType); if (convertedToDelegate) { var objectCreation = info.Parent as ExplicitObjectCreation; bool isExplicitConversion = objectCreation != null && objectCreation.Kind == ExprKind.EXPLICIT_DELEGATE_CREATION; if (!isExplicitConversion) { info.Kind = ExprKind.IMPLICIT_DELEGATE_CREATION; var parent = new Expression(info); return Factory.Create(new ExpressionNodeInfo(info.Context, info.Node, parent, 0)); } info.Kind = ExprKind.UNKNOWN; return Factory.Create(info); } if (resolvedType != null) return new ImplicitCast(info, conversion.MethodSymbol); } bool implicitUpcast = conversion.IsImplicit && convertedType != null && !conversion.IsBoxing && ( resolvedType == null || conversion.IsReference || convertedType.SpecialType == SpecialType.System_Object) ; if (!conversion.IsIdentity && !implicitUpcast) { return new ImplicitCast(info); } // Default: Just create the expression without a conversion. return Factory.Create(info); } } }