/// <summary> /// Converts CLR type symbol to TypeRef used by flow analysis. /// </summary> public static ITypeRef CreateTypeRef(TypeRefContext ctx, TypeSymbol t) { Contract.ThrowIfNull(t); switch (t.SpecialType) { case SpecialType.System_Void: throw new ArgumentException(); case SpecialType.System_Int32: case SpecialType.System_Int64: return LongTypeRef; case SpecialType.System_String: return StringTypeRef; case SpecialType.System_Double: return DoubleTypeRef; case SpecialType.System_Boolean: return BoolTypeRef; case SpecialType.System_Object: return new ClassTypeRef(NameUtils.SpecialNames.System_Object); case SpecialType.System_DateTime: return new ClassTypeRef(new QualifiedName(new Name("DateTime"), new[] { new Name("System") })); default: if (t is NamedTypeSymbol) { return new ClassTypeRef(((NamedTypeSymbol)t).MakeQualifiedName()); } else if (t is ArrayTypeSymbol) { var arr = (ArrayTypeSymbol)t; if (!arr.IsSZArray) { throw new NotImplementedException(); } return new ArrayTypeRef(null, CreateMask(ctx, arr.ElementType)); } else { throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(t); } } }
/// <summary> /// Gets type mask of the literal within given type context. /// </summary> internal TypeRefMask ResolveTypeMask(TypeRefContext typeCtx) { Debug.Assert(this.ConstantValue.HasValue); var value = this.ConstantValue.Value; if (value == null) { return typeCtx.GetNullTypeMask(); } else { if (value is long || value is int) { return typeCtx.GetLongTypeMask(); } else if (value is string) { return typeCtx.GetStringTypeMask(); } else if (value is bool) { return typeCtx.GetBooleanTypeMask(); } else if (value is double) { return typeCtx.GetDoubleTypeMask(); } else { throw new NotImplementedException(); } } }
/// <summary> /// Resolves list of input arguments. /// Implicit parameters passed by compiler are ignored. /// </summary> /// <param name="routine">Routine.</param> /// <param name="ctx">TYpe context to transmer type masks into.</param> /// <returns>List of input PHP arguments.</returns> public static PhpParam[] GetExpectedArguments(this IPhpRoutineSymbol routine, TypeRefContext ctx) { Contract.ThrowIfNull(routine); var ps = routine.Parameters; var table = (routine as SourceRoutineSymbol)?.LocalsTable; var result = new List<PhpParam>(ps.Length); foreach (ParameterSymbol p in ps) { if (result.Count == 0 && p.IsImplicitlyDeclared) { continue; } // default value (bound expression) ConstantValue cvalue; var psrc = p as SourceParameterSymbol; var defaultexpr = psrc != null ? psrc.Initializer : ((cvalue = p.ExplicitDefaultConstantValue) != null ? new BoundLiteral(cvalue.Value) : null); // var phpparam = new PhpParam( TypeRefFactory.CreateMask(ctx, p.Type), p.RefKind != RefKind.None, p.IsParams, defaultexpr); result.Add(phpparam); } // return result.ToArray(); }
public static TypeRefMask CreateMask(TypeRefContext ctx, TypeSymbol t) { Contract.ThrowIfNull(t); switch (t.SpecialType) { case SpecialType.System_Void: return 0; case SpecialType.System_Int64: return ctx.GetLongTypeMask(); case SpecialType.System_String: return ctx.GetStringTypeMask(); case SpecialType.System_Double: return ctx.GetDoubleTypeMask(); case SpecialType.System_Boolean: return ctx.GetBooleanTypeMask(); case SpecialType.None: var containing = t.ContainingAssembly; if (containing != null && containing.IsPchpCorLibrary) { if (t.Name == "PhpValue") return TypeRefMask.AnyType; if (t.Name == "PhpAlias") return TypeRefMask.AnyType.WithRefFlag; if (t.Name == "PhpNumber") return ctx.GetNumberTypeMask(); if (t.Name == "PhpString") return ctx.GetWritableStringTypeMask(); if (t.Name == "PhpArray") return ctx.GetArrayTypeMask(); if (t.Name == "IPhpCallable") return ctx.GetCallableTypeMask(); } break; } return CreateMask(ctx, CreateTypeRef(ctx, t)); }
internal FlowContext(TypeRefContext/*!*/typeCtx, SourceRoutineSymbol routine) { Contract.ThrowIfNull(typeCtx); _typeCtx = typeCtx; _routine = routine; // _varsIndex = new Dictionary<VariableName, int>(); }
/// <summary> /// Gets type mask representing given type name. /// </summary> public static TypeRefMask GetTypeMask(TypeRefContext/*!*/typeCtx, string tname, NamingContext naming, bool fullyQualified = false) { if (!string.IsNullOrEmpty(tname)) { // handle various array conventions if (tname.LastCharacter() == ']') { // "TName[]" if (tname.EndsWith("[]", StringComparison.Ordinal)) { var elementType = GetTypeMask(typeCtx, tname.Remove(tname.Length - 2), naming, fullyQualified); return typeCtx.GetArrayTypeMask(elementType); } // "array[TName]" var arrayTypeName = QualifiedName.Array.Name.Value; if (tname.Length > arrayTypeName.Length && tname[arrayTypeName.Length] == '[' && tname.StartsWith(arrayTypeName, StringComparison.OrdinalIgnoreCase)) { var elementTypeName = tname.Substring(arrayTypeName.Length + 1, tname.Length - arrayTypeName.Length - 2); var elementType = GetTypeMask(typeCtx, elementTypeName, naming, fullyQualified); return typeCtx.GetArrayTypeMask(elementType); } // unknown something // ... } else { var result = GetKnownTypeMask(typeCtx, tname); if (result.IsUninitialized) { var qname = NameUtils.MakeQualifiedName(tname, false); if (!fullyQualified && naming != null && !qname.IsReservedClassName) qname = QualifiedName.TranslateAlias(qname, AliasKind.Type, naming.Aliases, naming.CurrentNamespace); if (qname.IsPrimitiveTypeName) { result = GetKnownTypeMask(typeCtx, qname.Name.Value); if (!result.IsUninitialized) return result; } result = typeCtx.GetTypeMask(qname, true); } //Contract.Assert(!result.IsUninitialized); return result; } } return 0; }
/// <summary> /// Gets type mask of known PHPDoc type name or <c>0</c> if such type is now known. /// </summary> public static TypeRefMask GetKnownTypeMask(TypeRefContext/*!*/typeCtx, string tname) { Contract.ThrowIfNull(typeCtx); if (!string.IsNullOrEmpty(tname)) { TypeMaskGetter getter; if (_knownTypes.TryGetValue(tname, out getter)) { return getter(typeCtx); } } return 0; // void }
/// <summary> /// Gets expected return type mask of given symbol (field, function, method or property). /// </summary> /// <remarks>Returned type mask corresponds to types that can be returned by invoking given symbol.</remarks> public static TypeRefMask GetResultType(this IPhpValue symbol, TypeRefContext ctx) { Contract.ThrowIfNull(symbol); Contract.ThrowIfNull(ctx); TypeSymbol t; if (symbol is FieldSymbol) { t = ((FieldSymbol)symbol).Type; } else if (symbol is MethodSymbol) { var m = (MethodSymbol)symbol; var r = symbol as SourceRoutineSymbol; if (r != null && r.IsStatic) { // In case of a static function, we can return expected return type mask exactly. // Such function cannot be overriden and we know exactly what the return type will be even the CLR type covers more possibilities. return ctx.AddToContext(r.TypeRefContext, r.ResultTypeMask); } t = m.ReturnType; } else if (symbol is PropertySymbol) { t = ((PropertySymbol)symbol).Type; } else if (symbol is ParameterSymbol) { t = ((ParameterSymbol)symbol).Type; } else { throw Roslyn.Utilities.ExceptionUtilities.UnexpectedValue(symbol); } // create the type mask from the CLR type symbol var mask = TypeRefFactory.CreateMask(ctx, t); // [CastToFalse] if (symbol is IPhpRoutineSymbol && ((IPhpRoutineSymbol)symbol).CastToFalse) { mask |= ctx.GetBooleanTypeMask(); // the function may return FALSE } // return mask; }
public MethodSymbol Resolve(TypeRefContext typeCtx, TypeRefMask[] args, TypeSymbol classCtx) { // see Pchp.Core.Dynamic.OverloadBinder var result = new List<MethodSymbol>(_methods); // RemoveInaccessible(result, classCtx); if (result.Count == 1) return result[0]; // TODO: cost of args convert operation // by params count var result2 = new List<MethodSymbol>(); foreach (var m in result) { var nmandatory = 0; var hasoptional = false; var hasparams = false; var expectedparams = m.GetExpectedArguments(typeCtx); foreach (var p in expectedparams) { hasoptional |= p.DefaultValue != null; hasparams |= p.IsVariadic; if (!hasoptional && !hasparams) nmandatory++; // TODO: check args[i] is convertible to p.Type } if (args.Length >= nmandatory && (hasparams || args.Length <= expectedparams.Length)) { result2.Add(m); } } // return (result2.Count == 1) ? result2[0] : null; }
/// <summary> /// Gets type mask at target type context representing given type names from given routine. /// </summary> public static TypeRefMask GetTypeMask(TypeRefContext/*!*/targetCtx, TypeRefContext/*!*/ctx, string[] tnames, NamingContext naming, bool fullyQualified = false) { Contract.ThrowIfNull(targetCtx); Contract.ThrowIfNull(ctx); var mask = GetTypeMask(ctx, tnames, naming, fullyQualified); return targetCtx.AddToContext(ctx, mask); }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsCount">Amount of parameters used for the call.</param> /// <param name="lateStaticBindType">Type of the <c>self</c> in the caller context.</param> public CallInfo(TypeRefContext ctx, int paramsCount, TypeRefMask lateStaticBindType) : this(ctx, GetParamsTypeArr(paramsCount, TypeRefMask.AnyType), lateStaticBindType) { }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsType">Type of parameters used for the call. Length of the array corresponds to the parameters count.</param> public CallInfo(TypeRefContext ctx, TypeRefMask[] paramsType) : this(ctx, paramsType, 0) { }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsCount">Amount of parameters used for the call.</param> public CallInfo(TypeRefContext ctx, int paramsCount) : this(ctx, paramsCount, 0) { }
/// <summary> /// Initializes <see cref="CallInfo"/>. /// </summary> /// <param name="ctx">Type context of the caller.</param> /// <param name="paramsType">Type of parameters used for the call. Length of the array corresponds to the parameters count.</param> /// <param name="lateStaticBindType">Type of the <c>self</c> in the caller context.</param> public CallInfo(TypeRefContext ctx, TypeRefMask[] paramsType, TypeRefMask lateStaticBindType) { _typeCtx = ctx; _paramsType = paramsType; _lateStaticBindType = (lateStaticBindType.IsSingleType ? lateStaticBindType : 0); }
public virtual ITypeRef /*!*/ Transfer(TypeRefContext /*!*/ source, TypeRefContext /*!*/ target) { return(this); } // there is nothing depending on the context
public ITypeRef /*!*/ Transfer(TypeRefContext /*!*/ source, TypeRefContext /*!*/ target) { return(this); }
/// <summary> /// Enqueues the standalone expression for analysis. /// </summary> void EnqueueExpression(BoundExpression expression, TypeRefContext/*!*/ctx, NamingContext naming) { Contract.ThrowIfNull(expression); Contract.ThrowIfNull(ctx); var dummy = new BoundBlock() { FlowState = new FlowState(new FlowContext(ctx, null)), Naming = naming }; dummy.Add(new BoundExpressionStatement(expression)); _worklist.Enqueue(dummy); }
public static TypeRefMask CreateMask(TypeRefContext ctx, ITypeRef tref) { Contract.ThrowIfNull(tref); TypeRefMask result = 0; result.AddType(ctx.AddToContext(tref)); if (!tref.IsPrimitiveType && !tref.IsArray) { result.IncludesSubclasses = true; } return result; }
/// <summary> /// Gets actual parameter type if provided. Otherwise <c>void</c>. /// </summary> /// <param name="ctx">Target type context.</param> /// <param name="index">Index of parameter.</param> /// <returns>Type mask of the parameter or <c>void</c>.</returns> public TypeRefMask GetParamType(TypeRefContext/*!*/ctx, int index) { if (ctx == null) throw new ArgumentNullException("ctx"); if (_typeCtx != null && index >= 0 && index < _paramsType.Length) return ctx.AddToContext(_typeCtx, _paramsType[index]); return 0; }
/// <summary> /// Adds properly types from another context. /// </summary> /// <param name="other">Another type context which types will be added to this one.</param> internal void AddToContext(TypeRefContext/*!*/other) { Contract.ThrowIfNull(other); foreach (var typeref in other.Types) { AddToContext(typeref.Transfer(other, this)); } }
/// <summary> /// Adds properly types from another context matching given mask. /// </summary> /// <param name="context">Context of <paramref name="mask"/>.</param> /// <param name="mask">Type mask representing types in <paramref name="context"/>.</param> /// <returns>Returns type mask in this context representing <paramref name="mask"/> as <paramref name="context"/>.</returns> public TypeRefMask AddToContext(TypeRefContext/*!*/context, TypeRefMask mask) { Contract.ThrowIfNull(context); if (mask.IsAnyType || mask.IsVoid || object.ReferenceEquals(this, context)) return mask; var result = default(TypeRefMask); var types = context.Types; var count = Math.Min(types.Count, TypeRefMask.IndicesCount); for (int i = 0; i < count; i++) { if (mask.HasType(i)) { var index = AddToContext(types[i].Transfer(context, this)); result.AddType(index); } } // result.IsRef = mask.IsRef; result.IncludesSubclasses = mask.IncludesSubclasses; // return result; }
/// <summary> /// Gets actual lates static bind type (type of <c>static</c>) if provided. /// Otherwise <c>void</c>. /// </summary> /// <param name="ctx">Target type context.</param> /// <returns>TYpe mask of <c>static</c> in given context or <c>void</c>.</returns> public TypeRefMask GetLateStaticBindType(TypeRefContext/*!*/ctx) { if (ctx == null) throw new ArgumentNullException("ctx"); if (_typeCtx != null && !_lateStaticBindType.IsUninitialized) return ctx.AddToContext(_typeCtx, _lateStaticBindType); return 0; }
/// <summary> /// Gets type mask representing given type name. /// </summary> public static TypeRefMask GetTypeMask(TypeRefContext/*!*/typeCtx, string[] tnames, NamingContext naming, bool fullyQualified = false) { TypeRefMask result = 0; foreach (var tname in tnames) result |= GetTypeMask(typeCtx, tname, naming, fullyQualified); return result; }
/// <summary> /// Gets type mask at target ctype context representing given type names from given routine. /// </summary> public static TypeRefMask GetTypeMask(TypeRefContext/*!*/targetCtx, Symbols.SourceRoutineSymbol/*!*/routine, string[] tnames, bool fullyQualified = false) { Contract.ThrowIfNull(targetCtx); Contract.ThrowIfNull(routine); return GetTypeMask(targetCtx, routine.TypeRefContext, tnames, routine.GetNamingContext(), fullyQualified); }