Ejemplo n.º 1
0
        /// <summary>
        /// Enqueues routine's start block for analysis.
        /// </summary>
        void EnqueueRoutine(SourceRoutineSymbol routine)
        {
            Contract.ThrowIfNull(routine);

            // lazily binds CFG and
            // adds their entry block to the worklist

            // TODO: reset LocalsTable, FlowContext and CFG

            _worklist.Enqueue(routine.ControlFlowGraph?.Start);

            // enqueue routine parameter default values
            routine.Parameters.OfType<SourceParameterSymbol>().Foreach(p =>
            {
                if (p.Initializer != null)
                {
                    EnqueueExpression(p.Initializer, routine.TypeRefContext, routine.GetNamingContext());
                }
            });
        }
Ejemplo n.º 2
0
        TypeSymbol ResolveType()
        {
            if (IsThis)
            {
                // <this> parameter
                if (_routine is SourceGlobalMethodSymbol)
                {
                    // "AnyType" in case of $this in global scope
                    return(DeclaringCompilation.CoreTypes.PhpValue);
                }

                return(ContainingType);
            }

            //return DeclaringCompilation.GetTypeFromTypeRef(_routine, _routine.ControlFlowGraph.GetParamTypeMask(this));

            // determine parameter type from the signature:

            // aliased parameter:
            if (_syntax.IsOut || _syntax.PassedByRef)
            {
                if (_syntax.IsVariadic)
                {
                    // PhpAlias[]
                    return(ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, DeclaringCompilation.CoreTypes.PhpAlias));
                }
                else
                {
                    // PhpAlias
                    return(DeclaringCompilation.CoreTypes.PhpAlias);
                }
            }

            // 1. specified type hint
            var result = DeclaringCompilation.GetTypeFromTypeRef(_syntax.TypeHint);

            // 2. optionally type specified in PHPDoc
            if (result == null && _ptagOpt != null && _ptagOpt.TypeNamesArray.Length != 0 &&
                (DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.ParameterTypes) != 0)
            {
                var typectx = _routine.TypeRefContext;
                var tmask   = FlowAnalysis.PHPDoc.GetTypeMask(typectx, _ptagOpt.TypeNamesArray, _routine.GetNamingContext());
                if (!tmask.IsVoid && !tmask.IsAnyType)
                {
                    result = DeclaringCompilation.GetTypeFromTypeRef(typectx, tmask);
                }
            }

            // 3 default:
            if (result == null)
            {
                // TODO: use type from overriden method

                result = DeclaringCompilation.CoreTypes.PhpValue;
            }

            // variadic (result[])
            if (_syntax.IsVariadic)
            {
                result = ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, result);
            }

            //
            return(result);
        }
        /// <summary>
        /// Constructs most appropriate CLR return type of given routine.
        /// The method handles returning by alias, PHP7 return type, PHPDoc @return tag and result of flow analysis.
        /// In case the routine is an override or can be overriden, the CLR type is a value.
        /// </summary>
        internal static TypeSymbol ConstructClrReturnType(SourceRoutineSymbol routine)
        {
            var compilation = routine.DeclaringCompilation;

            // if the method is generator and can't be overriden then the return type must be generator
            // TODO: would not be necessary if GN_SGS got fixed (the routine could report the return type correctly itself)
            if (routine.IsGeneratorMethod())
            {
                // if non-virtual -> return Generator directly
                if (IsNotOverriding(routine))
                {
                    return(compilation.CoreTypes.Generator);
                }
                else //can't be sure -> play safe with PhpValue
                {
                    return(compilation.CoreTypes.PhpValue);
                }
            }

            // &
            if (routine.SyntaxSignature.AliasReturn)
            {
                return(compilation.CoreTypes.PhpAlias);
            }

            // : return type
            if (routine.SyntaxReturnType != null)
            {
                return(compilation.GetTypeFromTypeRef(routine.SyntaxReturnType));
            }

            // for non virtual methods:
            if (IsNotOverriding(routine))
            {
                // /** @return */
                var typeCtx = routine.TypeRefContext;
                if (routine.PHPDocBlock != null && (compilation.Options.PhpDocTypes & PhpDocTypes.ReturnTypes) != 0)
                {
                    var returnTag = routine.PHPDocBlock.Returns;
                    if (returnTag != null && returnTag.TypeNames.Length != 0)
                    {
                        var tmask = PHPDoc.GetTypeMask(typeCtx, returnTag.TypeNamesArray, routine.GetNamingContext());
                        if (!tmask.IsVoid && !tmask.IsAnyType)
                        {
                            return(compilation.GetTypeFromTypeRef(typeCtx, tmask));
                        }
                    }
                }

                // determine from code flow
                return(compilation.GetTypeFromTypeRef(typeCtx, routine.ResultTypeMask));
            }
            else
            {
                // TODO: an override that respects the base? check routine.ResultTypeMask (flow analysis) and base implementation is it matches
            }

            // any value by default
            return(compilation.CoreTypes.PhpValue);
        }
Ejemplo n.º 4
0
        TypeSymbol ResolveType()
        {
            if (IsThis)
            {
                // <this> parameter
                if (_routine is SourceGlobalMethodSymbol)
                {
                    // "AnyType" in case of $this in global scope
                    return(DeclaringCompilation.CoreTypes.PhpValue);
                }

                return(ContainingType);
            }

            //return DeclaringCompilation.GetTypeFromTypeRef(_routine, _routine.ControlFlowGraph.GetParamTypeMask(this));

            // determine parameter type from the signature:

            // aliased parameter:
            if (_syntax.IsOut || _syntax.PassedByRef)
            {
                if (_syntax.IsVariadic)
                {
                    // PhpAlias[]
                    return(ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, DeclaringCompilation.CoreTypes.PhpAlias));
                }
                else
                {
                    // PhpAlias
                    return(DeclaringCompilation.CoreTypes.PhpAlias);
                }
            }

            // 1. specified type hint
            var typeHint = _syntax.TypeHint;

            if (typeHint is ReservedTypeRef rtref)
            {
                // workaround for https://github.com/peachpiecompiler/peachpie/issues/281
                // remove once it gets updated in parser
                if (rtref.Type == ReservedTypeRef.ReservedType.self)
                {
                    return(_routine.ContainingType);                                                 // self
                }
            }
            var result = DeclaringCompilation.GetTypeFromTypeRef(typeHint, _routine.ContainingType as SourceTypeSymbol, nullable: DefaultsToNull, phpLang: true);

            // 2. optionally type specified in PHPDoc
            if (result == null && PHPDoc != null && PHPDoc.TypeNamesArray.Length != 0 &&
                (DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.ParameterTypes) != 0)
            {
                var typectx = _routine.TypeRefContext;
                var tmask   = FlowAnalysis.PHPDoc.GetTypeMask(typectx, PHPDoc.TypeNamesArray, _routine.GetNamingContext());
                if (!tmask.IsVoid && !tmask.IsAnyType)
                {
                    result = DeclaringCompilation.GetTypeFromTypeRef(typectx, tmask);
                }
            }

            // 3 default:
            if (result == null)
            {
                // TODO: use type from overriden method

                result = DeclaringCompilation.CoreTypes.PhpValue;
            }

            // variadic (result[])
            if (_syntax.IsVariadic)
            {
                result = ArrayTypeSymbol.CreateSZArray(this.ContainingAssembly, result);
            }

            //
            return(result);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Constructs most appropriate CLR return type of given routine.
        /// The method handles returning by alias, PHP7 return type, PHPDoc @return tag and result of flow analysis.
        /// In case the routine is an override or can be overriden, the CLR type is a value.
        /// </summary>
        public static TypeSymbol ConstructClrReturnType(SourceRoutineSymbol routine)
        {
            var compilation = routine.DeclaringCompilation;

            // &
            if (routine.SyntaxSignature.AliasReturn)
            {
                return(compilation.CoreTypes.PhpAlias);
            }

            // : return type
            if (routine.SyntaxReturnType != null)
            {
                return(compilation.GetTypeFromTypeRef(routine.SyntaxReturnType));
            }

            // for non virtual methods:
            if (routine.IsStatic || routine.DeclaredAccessibility == Accessibility.Private || (routine.IsSealed && !routine.IsOverride))
            {
                // /** @return */
                var typeCtx = routine.TypeRefContext;
                if (routine.PHPDocBlock != null && (compilation.Options.PhpDocTypes & PhpDocTypes.ReturnTypes) != 0)
                {
                    var returnTag = routine.PHPDocBlock.Returns;
                    if (returnTag != null && returnTag.TypeNames.Length != 0)
                    {
                        var tmask = PHPDoc.GetTypeMask(typeCtx, returnTag.TypeNamesArray, routine.GetNamingContext());
                        if (!tmask.IsVoid && !tmask.IsAnyType)
                        {
                            return(compilation.GetTypeFromTypeRef(typeCtx, tmask));
                        }
                    }
                }

                // determine from code flow
                return(compilation.GetTypeFromTypeRef(typeCtx, routine.ResultTypeMask));
            }
            else
            {
                // TODO: an override that respects the base? check routine.ResultTypeMask (flow analysis) and base implementation is it matches
            }

            // any value by default
            return(compilation.CoreTypes.PhpValue);
        }