/// <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); }
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)); }
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)); }
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)); }
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++; } }
/// <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)); } }
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); }
/// <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); }
/// <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++; } }