Пример #1
0
        /// <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);
        }
Пример #2
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>));
        }
Пример #3
0
 /// <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());
     }
 }
Пример #4
0
 /// <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));
     }
 }
Пример #5
0
        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);
        }
Пример #6
0
 public override NamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName)
 {
     return(SourceModule.SymbolCollection.GetType(NameUtils.MakeQualifiedName(fullyQualifiedMetadataName.Replace('.', Devsense.PHP.Syntax.QualifiedName.Separator), true)));
 }
Пример #7
0
        /// <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;
                }
            }
        }
Пример #8
0
        /// <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;
            }
        }
Пример #9
0
 /// <summary>
 /// Gets type full qualified name.
 /// </summary>
 public static QualifiedName MakeQualifiedName(this NamedTypeSymbol type)
 {
     return(NameUtils.MakeQualifiedName(type.Name, type.NamespaceName, true));
 }
Пример #10
0
 public override NamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName)
 {
     return(SourceModule.SymbolTables.GetType(NameUtils.MakeQualifiedName(fullyQualifiedMetadataName, true)));
 }
Пример #11
0
        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);
        }
Пример #12
0
        /// <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;
                }
            }
        }