/// <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 if (tname[0] == '&') { return(GetTypeMask(typeCtx, tname.Substring(1), naming, fullyQualified).WithRefFlag); } 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 = BoundTypeRefFactory.Create(qname, typeCtx.SelfType as SourceTypeSymbol).GetTypeRefMask(typeCtx); } //Contract.Assert(!result.IsUninitialized); return(result); } } return(0); }
/// <summary> /// Resolves value of the function call in compile time if possible. /// </summary> public static Optional <object> TryResolve(BoundGlobalFunctionCall x, ISymbolProvider model) { if (x.Name.IsDirect && x.ArgumentsInSourceOrder.All(arg => arg.Value.ConstantValue.HasValue)) { // direct func name with all arguments resolved: // take the function name ignoring current namespace resolution, simple names only: var name = x.NameOpt.HasValue ? x.NameOpt.Value : x.Name.NameValue; if (name.IsSimpleName) { var args = x.ArgumentsInSourceOrder; switch (name.Name.Value) { case "function_exists": if (args.Length == 1) { // TRUE <=> function name is defined unconditionally in a reference library (PE assembly) var str = args[0].Value.ConstantValue.Value as string; if (str != null) { var tmp = model.ResolveFunction(NameUtils.MakeQualifiedName(str, true)); if (tmp is PEMethodSymbol || (tmp is AmbiguousMethodSymbol && ((AmbiguousMethodSymbol)tmp).Ambiguities.All(f => f is PEMethodSymbol))) { return(new Optional <object>(true)); } } } break; } } } // return(default(Optional <object>)); }
/// <summary> /// Gets type mask corresponding to <c>self</c> with <c>includesSubclasses</c> flag set whether type is not final. /// </summary> private TypeRefMask GetTypeCtxMask(AST.TypeDecl typeCtx) { if (typeCtx != null) { var typeIsFinal = (typeCtx.MemberAttributes & PhpMemberAttributes.Final) != 0; return(GetTypeMask(new ClassTypeRef(NameUtils.MakeQualifiedName(typeCtx)), !typeIsFinal)); } else { return(GetSystemObjectTypeMask()); } }
/// <summary> /// Gets type full qualified name. /// </summary> public static QualifiedName MakeQualifiedName(this NamedTypeSymbol type) { if (string.IsNullOrEmpty(type.NamespaceName)) { return(new QualifiedName(new Name(type.Name))); } else { var ns = type.NamespaceName.Replace('.', QualifiedName.Separator); return(NameUtils.MakeQualifiedName(ns + QualifiedName.Separator + type.Name, true)); } }
public override ImmutableArray <NamedTypeSymbol> GetTypeMembers(string name) { var x = _sourceModule.SymbolCollection.GetType(NameUtils.MakeQualifiedName(name, true)); if (x != null) { if (x.IsErrorType()) { var candidates = ((ErrorTypeSymbol)x).CandidateSymbols; if (candidates.Length != 0) { return(candidates.OfType <NamedTypeSymbol>().AsImmutable()); } } else { return(ImmutableArray.Create(x)); } } return(ImmutableArray <NamedTypeSymbol> .Empty); }
public override NamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName) { return(SourceModule.SymbolCollection.GetType(NameUtils.MakeQualifiedName(fullyQualifiedMetadataName.Replace('.', Devsense.PHP.Syntax.QualifiedName.Separator), true))); }
/// <summary> /// Resolves value of the function call in compile time if possible and updates the variable type if necessary /// </summary> public static void HandleSpecialFunctionCall(BoundGlobalFunctionCall call, ExpressionAnalysis analysis, ConditionBranch branch) { // Only direct function names if (!HasSimpleName(call, out string name)) { return; } // Type checking functions if (branch != ConditionBranch.AnyResult && CanBeTypeCheckingFunction(call, name, out var arg)) { if (HandleTypeCheckingFunctions(call, name, arg, analysis, branch)) { return; } } // Functions with all arguments resolved if (call.ArgumentsInSourceOrder.All(a => a.Value.ConstantValue.HasValue)) { // Clear out the constant value result from the previous run of this method (if it was valid, it will be reassigned below) call.ConstantValue = default(Optional <object>); string str; var args = call.ArgumentsInSourceOrder; switch (name) { case "is_callable": // bool is_callable( string $function_name ) case "function_exists": // bool function_exists ( string $function_name ) if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str)) { // TRUE <=> function is defined unconditionally in a reference library (PE assembly) var tmp = analysis.Model.ResolveFunction(NameUtils.MakeQualifiedName(str, true)); if (tmp is PEMethodSymbol || (tmp is AmbiguousMethodSymbol && ((AmbiguousMethodSymbol)tmp).Ambiguities.All(f => f is PEMethodSymbol))) // TODO: unconditional declaration ? { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } break; // bool class_exists ( string $class_name [, bool $autoload = true ] ) case "class_exists": if (args.Length >= 1) { // TRUE <=> class is defined unconditionally in a reference library (PE assembly) var class_name = args[0].Value.ConstantValue.Value as string; if (class_name != null) { var tmp = analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true)); if (tmp is PENamedTypeSymbol) // TODO: unconditional declaration ? { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } } break; // bool method_exists ( string $class_name , string $method_name ) case "method_exists": if (args.Length == 2) { var class_name = args[0].Value.ConstantValue.Value as string; if (class_name != null && args[1].Value.ConstantValue.TryConvertToString(out str)) { var tmp = (NamedTypeSymbol)analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true)); if (tmp is PENamedTypeSymbol) { if (tmp.LookupMethods(str).Any()) { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } } } break; case "extension_loaded": // bool extension_loaded(name) if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str)) { if (analysis.Model.Extensions.Contains(str, StringComparer.OrdinalIgnoreCase)) { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } break; case "defined": case "constant": if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str)) { // TODO: const_name in form of "{CLASS}::{NAME}" var tmp = analysis.Model.ResolveConstant(str); if (tmp is PEFieldSymbol symbol) // TODO: also user constants defined in the same scope { if (name == "defined") { call.ConstantValue = ConstantValueExtensions.AsOptional(true); } else // name == "constant" { var cvalue = symbol.GetConstantValue(false); call.ConstantValue = (cvalue != null) ? new Optional <object>(cvalue.Value) : null; call.TypeRefMask = TypeRefFactory.CreateMask(analysis.TypeCtx, symbol.Type); } return; } } break; case "strlen": if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out string value)) { call.ConstantValue = new Optional <object>(value.Length); } return; } } }
/// <summary> /// Resolves value of the function call in compile time if possible and updates the variable type if necessary /// </summary> public static void HandleSpecialFunctionCall <T>(BoundGlobalFunctionCall call, ExpressionAnalysis <T> analysis, ConditionBranch branch) { // Only direct function names if (!HasSimpleName(call, out string name)) { return; } // Type checking functions if (branch != ConditionBranch.AnyResult && CanBeTypeCheckingFunction(call, name, out var arg)) { if (HandleTypeCheckingFunctions(call, name, arg, analysis, branch)) { return; } } var args = call.ArgumentsInSourceOrder; // Clear out the constant value result from the previous run of this method (if it was valid, it will be reassigned below) call.ConstantValue = default; string str; switch (name) // TODO: case insensitive { case "is_callable": // bool is_callable( string $function_name ) case "function_exists": // bool function_exists ( string $function_name ) if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str)) { // TRUE <=> function is defined unconditionally in a reference library (PE assembly) if (IsUnconditionalDeclaration(analysis.Model.ResolveFunction(NameUtils.MakeQualifiedName(str, true)))) { call.ConstantValue = ConstantValueExtensions.AsOptional(true); } } break; // bool class_exists ( string $class_name [, bool $autoload = true ] ) case "class_exists": case "interface_exists": if (args.Length >= 1) { // TRUE <=> class is defined unconditionally in a reference library (PE assembly) var class_name = args[0].Value.ConstantValue.Value as string; if (!string.IsNullOrEmpty(class_name)) { var tmp = (TypeSymbol)analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true)); if (tmp is PENamedTypeSymbol && !tmp.IsPhpUserType()) // TODO: + SourceTypeSymbol when reachable unconditional declaration { bool @interface = (name == "interface_exists"); if (tmp.TypeKind == (@interface ? TypeKind.Interface : TypeKind.Class)) { call.ConstantValue = ConstantValueExtensions.AsOptional(true); } } } } break; // bool method_exists ( string $class_name , string $method_name ) case "method_exists": if (args.Length == 2) { var class_name = args[0].Value.ConstantValue.Value as string; if (class_name != null && args[1].Value.ConstantValue.TryConvertToString(out str)) { var tmp = (NamedTypeSymbol)analysis.Model.ResolveType(NameUtils.MakeQualifiedName(class_name, true)); if (tmp is PENamedTypeSymbol && !tmp.IsPhpUserType()) { if (tmp.LookupMethods(str).Count != 0) // TODO: why not User Types // TODO: why not resolve FALSE as well below? { call.ConstantValue = ConstantValueExtensions.AsOptional(true); } } } } break; case "defined": // defined(CONST_NAME) case "constant": // constant(CONST_NAME) if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out str)) { // TODO: const_name in form of "{CLASS}::{NAME}" // TODO: also user constants defined in the same scope? // quick evaluation of PE constants that can't be changed at run time var tmp = analysis.Model.ResolveConstant(str); if (tmp is PEFieldSymbol fld) { if (name == "defined") { call.ConstantValue = ConstantValueExtensions.AsOptional(true); } else // name == "constant" { if (fld.Type.Is_Func_Context_TResult(out var tresult)) { call.TypeRefMask = TypeRefFactory.CreateMask(analysis.TypeCtx, tresult); } else { var cvalue = fld.GetConstantValue(false); call.ConstantValue = (cvalue != null) ? new Optional <object>(cvalue.Value) : null; call.TypeRefMask = TypeRefFactory.CreateMask(analysis.TypeCtx, fld.Type, notNull: fld.IsNotNull()); } } } else if (tmp is PEPropertySymbol prop) { if (name == "defined") { call.ConstantValue = ConstantValueExtensions.AsOptional(true); } else // name == "constant" { call.TypeRefMask = TypeRefFactory.CreateMask(analysis.TypeCtx, prop.Type, notNull: prop.IsNotNull()); } } } break; case "strlen": if (args.Length == 1 && args[0].Value.ConstantValue.TryConvertToString(out string value)) { call.ConstantValue = new Optional <object>(value.Length); } break; case "file_exists": if (args.Length == 1) { if (TryResolveFile(analysis.Model, analysis.Routine, args[0].Value, out var script)) { // there is compiled script at this path, // the expression will be always true call.ConstantValue = true.AsOptional(); } } break; } }
/// <summary> /// Gets type full qualified name. /// </summary> public static QualifiedName MakeQualifiedName(this NamedTypeSymbol type) { return(NameUtils.MakeQualifiedName(type.Name, type.NamespaceName, true)); }
public override NamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName) { return(SourceModule.SymbolTables.GetType(NameUtils.MakeQualifiedName(fullyQualifiedMetadataName, true))); }
public override ImmutableArray <NamedTypeSymbol> GetTypeMembers(string name) { var x = _sourceModule.SymbolCollection.GetType(NameUtils.MakeQualifiedName(name, true)); return((x != null) ? ImmutableArray.Create(x) : ImmutableArray <NamedTypeSymbol> .Empty); }
/// <summary> /// Resolves value of the function call in compile time if possible and updates the variable type if necessary /// </summary> public static void HandleFunctionCall(BoundGlobalFunctionCall call, ExpressionAnalysis analysis, ConditionBranch branch) { // Only direct function names if (!HasSimpleName(call, out string name)) { return; } // Type checking functions if (branch != ConditionBranch.AnyResult && CanBeTypeCheckingFunction(call, name, out var arg)) { if (HandleTypeCheckingFunctions(call, name, arg, analysis, branch)) { return; } } // Functions with all arguments resolved if (call.ArgumentsInSourceOrder.All(a => a.Value.ConstantValue.HasValue)) { // Clear out the constant value result from the previous run of this method (if it was valid, it will be reassigned below) call.ConstantValue = default(Optional <object>); var args = call.ArgumentsInSourceOrder; switch (name) { // bool function_exists ( string $function_name ) case "function_exists": if (args.Length == 1) { // TRUE <=> function is defined unconditionally in a reference library (PE assembly) var function_name = args[0].Value.ConstantValue.Value as string; if (function_name != null) { var tmp = analysis.Model.ResolveFunction(NameUtils.MakeQualifiedName(function_name, true)); if (tmp is PEMethodSymbol || (tmp is AmbiguousMethodSymbol && ((AmbiguousMethodSymbol)tmp).Ambiguities.All(f => f is PEMethodSymbol))) // TODO: unconditional declaration ? { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } } break; // bool class_exists ( string $class_name [, bool $autoload = true ] ) case "class_exists": if (args.Length >= 1) { // TRUE <=> class is defined unconditionally in a reference library (PE assembly) var class_name = args[0].Value.ConstantValue.Value as string; if (class_name != null) { var tmp = analysis.Model.GetType(NameUtils.MakeQualifiedName(class_name, true)); if (tmp is PENamedTypeSymbol) // TODO: unconditional declaration ? { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } } break; // bool method_exists ( string $class_name , string $method_name ) case "method_exists": if (args.Length == 2) { var class_name = args[0].Value.ConstantValue.Value as string; var function_name = args[1].Value.ConstantValue.Value as string; if (class_name != null && function_name != null) { var tmp = (NamedTypeSymbol)analysis.Model.GetType(NameUtils.MakeQualifiedName(class_name, true)); if (tmp is PENamedTypeSymbol) { if (tmp.LookupMethods(function_name).Any()) { call.ConstantValue = ConstantValueExtensions.AsOptional(true); return; } } } } break; } } }