/// <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);
        }
Пример #2
0
        protected virtual TypeSymbol BuildReturnType(Signature signature, PHPDocBlock phpdocOpt, TypeRefMask return_tmask)
        {
            if (signature.AliasReturn)
            {
                return(DeclaringCompilation.CoreTypes.PhpAlias);
            }

            // TODO: PHP7 return type
            //signature.ReturnTypeHint

            //
            if (phpdocOpt != null)
            {
                var returnTag = phpdocOpt.Returns;
                if (returnTag != null && returnTag.TypeNames.Length != 0)
                {
                    var typeCtx = this.TypeRefContext;
                    var tmask   = PHPDoc.GetTypeMask(typeCtx, returnTag.TypeNamesArray);
                    if (!tmask.IsVoid && !tmask.IsAnyType)
                    {
                        return(DeclaringCompilation.GetTypeFromTypeRef(typeCtx, tmask));
                    }
                }
            }

            //
            return(DeclaringCompilation.GetTypeFromTypeRef(this.TypeRefContext, return_tmask));
        }
Пример #3
0
        public override T VisitAssign(BoundAssignEx x)
        {
            // Template: <x> = <x>
            if (x.Target is BoundVariableRef lvar && lvar.Variable is LocalVariableReference lloc &&
                x.Value is BoundVariableRef rvar && rvar.Variable is LocalVariableReference rloc &&
                lloc.BoundName == rloc.BoundName && x.PhpSyntax != null)
            {
                // Assignment made to same variable
                _diagnostics.Add(_routine, x.PhpSyntax, ErrorCode.WRN_AssigningSameVariable);
            }

            // Check the type of the value assigned to a field against its PHPDoc
            var valMask = x.Value.TypeRefMask;

            if (!valMask.IsAnyType && !valMask.IsRef &&
                x.Target is BoundFieldRef fr && fr.BoundReference.Symbol is SourceFieldSymbol fieldSymbol &&
                fieldSymbol.FindPhpDocVarTag() is PHPDocBlock.TypeVarDescTag fieldDoc &&
                fieldDoc.TypeNamesArray.Length != 0)
            {
                var namingCtx = NameUtils.GetNamingContext(fieldSymbol.PhpDocBlock.ContainingType);
                var fieldMask = PHPDoc.GetTypeMask(TypeCtx, fieldDoc.TypeNamesArray, namingCtx);

                if (!TypeCtx.CanBeSameType(fieldMask, valMask))
                {
                    // The value can't be of the type specified in PHPDoc
                    _diagnostics.Add(_routine, x.PhpSyntax, ErrorCode.WRN_FieldPhpDocAssignIncompatible,
                                     TypeCtx.ToString(valMask), fieldSymbol, fieldDoc.TypeNames);
                }
            }

            //

            return(base.VisitAssign(x));
        }
Пример #4
0
        protected virtual TypeSymbol BuildReturnType(Signature signature, TypeRef tref, PHPDocBlock phpdocOpt, TypeRefMask rtype)
        {
            if (signature.AliasReturn)
            {
                return(DeclaringCompilation.CoreTypes.PhpAlias);
            }

            // PHP7 return type
            if (tref != null)
            {
                return(DeclaringCompilation.GetTypeFromTypeRef(tref));
            }

            //
            var typeCtx = this.TypeRefContext;

            //
            if (phpdocOpt != null && (DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.ReturnTypes) != 0)
            {
                var returnTag = phpdocOpt.Returns;
                if (returnTag != null && returnTag.TypeNames.Length != 0)
                {
                    var tmask = PHPDoc.GetTypeMask(typeCtx, returnTag.TypeNamesArray, this.GetNamingContext());
                    if (!tmask.IsVoid && !tmask.IsAnyType)
                    {
                        return(DeclaringCompilation.GetTypeFromTypeRef(typeCtx, tmask));
                    }
                }
            }

            //
            return(DeclaringCompilation.GetTypeFromTypeRef(typeCtx, rtype));
        }
Пример #5
0
        protected override IEnumerable <ParameterSymbol> BuildParameters(Signature signature, PHPDocBlock phpdocOpt = null)
        {
            int index = 0;

            // Context ctx
            yield return(new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++));

            // System.Object @this
            if (_useThis)
            {
                yield return(new SourceParameterSymbol(this,
                                                       new FormalParam(
                                                           Span.Invalid,
                                                           SpecialParameterSymbol.ThisName,
                                                           Span.Invalid,
                                                           new Devsense.PHP.Syntax.Ast.ClassTypeRef(Span.Invalid, NameUtils.SpecialNames.System_Object),
                                                           FormalParam.Flags.Default,
                                                           null,
                                                           new List <CustomAttribute>()),
                                                       index++, null));
            }

            // @static + parameters
            int pindex = 0;

            foreach (var p in _syntax.UseParams.Concat(signature.FormalParams))
            {
                var ptag = (phpdocOpt != null) ? PHPDoc.GetParamTag(phpdocOpt, pindex - _syntax.UseParams.Count, p.Name.Name.Value) : null;

                yield return(new SourceParameterSymbol(this, p, index++, ptag));

                pindex++;
            }
        }
Пример #6
0
        /// <summary>
        /// Constructs routine source parameters.
        /// </summary>
        protected IEnumerable <SourceParameterSymbol> BuildSrcParams(IEnumerable <FormalParam> formalparams, PHPDocBlock phpdocOpt = null)
        {
            var pindex = 0; // zero-based relative index

            foreach (var p in formalparams)
            {
                var ptag = (phpdocOpt != null) ? PHPDoc.GetParamTag(phpdocOpt, pindex, p.Name.Name.Value) : null;

                yield return(new SourceParameterSymbol(this, p, relindex: pindex++, ptagOpt: ptag));
            }
        }
Пример #7
0
        internal override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound)
        {
            var vartag = _phpdoc?.GetElement <PHPDocBlock.VarTag>();

            if (vartag != null && vartag.TypeNamesArray.Length != 0)
            {
                var typectx = TypeRefFactory.CreateTypeRefContext(_type);
                var tmask   = PHPDoc.GetTypeMask(typectx, vartag.TypeNamesArray);
                var t       = DeclaringCompilation.GetTypeFromTypeRef(typectx, tmask);
                return(t);
            }

            // TODO: analysed PHP type

            return(DeclaringCompilation.CoreTypes.PhpValue);
        }
        internal override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound)
        {
            // TODO: HHVM TypeHint

            //
            if ((IsConst || IsReadOnly) && Initializer != null)
            {
                // resolved type symbol if possible
                if (Initializer.ResultType != null)
                {
                    return(Initializer.ResultType);
                }

                // resolved value type if possible
                var cvalue = Initializer.ConstantValue;
                if (cvalue.HasValue)
                {
                    var specialType = (cvalue.Value != null)
                        ? cvalue.ToConstantValueOrNull()?.SpecialType
                        : SpecialType.System_Object;    // NULL

                    if (specialType.HasValue && specialType != SpecialType.None)
                    {
                        return(DeclaringCompilation.GetSpecialType(specialType.Value));
                    }
                }

                //
                //return DeclaringCompilation.GetTypeFromTypeRef(typectx, Initializer.TypeRefMask);
            }

            // PHPDoc @var type
            if ((DeclaringCompilation.Options.PhpDocTypes & PhpDocTypes.FieldTypes) != 0)
            {
                var vartag = FindPhpDocVarTag();
                if (vartag != null && vartag.TypeNamesArray.Length != 0)
                {
                    var dummyctx = TypeRefFactory.CreateTypeRefContext(_containingType);
                    var tmask    = PHPDoc.GetTypeMask(dummyctx, vartag.TypeNamesArray, NameUtils.GetNamingContext(_containingType.Syntax));
                    return(DeclaringCompilation.GetTypeFromTypeRef(dummyctx, tmask));
                }
            }

            // default
            return(DeclaringCompilation.CoreTypes.PhpValue);
        }
Пример #9
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);
        }
Пример #10
0
        /// <summary>
        /// Builds CLR method parameters.
        /// </summary>
        /// <remarks>(Context, arg1, arg2, ...)</remarks>
        protected virtual IEnumerable <ParameterSymbol> BuildParameters(Signature signature, PHPDocBlock phpdocOpt = null)
        {
            int index = 0;

            if (this.IsStatic)  // instance methods have <ctx> in <this>.<ctx> field, see SourceNamedTypeSymbol._lazyContextField
            {
                yield return(new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++));
            }

            int pindex = 0;

            foreach (var p in signature.FormalParams)
            {
                var ptag = (phpdocOpt != null) ? PHPDoc.GetParamTag(phpdocOpt, pindex, p.Name.Value) : null;

                yield return(new SourceParameterSymbol(this, p, index++, ptag));

                pindex++;
            }
        }