public SourceParameterSymbol(SourceRoutineSymbol routine, FormalParam syntax, int relindex, PHPDocBlock.ParamTag ptagOpt) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(syntax); Debug.Assert(relindex >= 0); _routine = routine; _syntax = syntax; _relindex = relindex; _initializer = (syntax.InitValue != null) ? new SemanticsBinder(DeclaringCompilation, routine.ContainingFile.SyntaxTree, locals: null, routine: null, self: routine.ContainingType as SourceTypeSymbol) .BindWholeExpression(syntax.InitValue, BoundAccess.Read) .SingleBoundElement() : null; var phpattrs = _syntax.GetAttributes(); _attributes = phpattrs.Count != 0 ? new SemanticsBinder(DeclaringCompilation, routine.ContainingFile.SyntaxTree, locals: null, routine: routine, self: routine.ContainingType as SourceTypeSymbol) .BindAttributes(phpattrs) : ImmutableArray <AttributeData> .Empty; PHPDoc = ptagOpt; }
/// <summary> /// Gets value indicating the routine does not override any other routine. /// (static methods, private methods or sealed virtual methods not overriding anything) /// </summary> static bool IsNotOverriding(SourceRoutineSymbol routine) { return (routine.IsStatic || routine.DeclaredAccessibility == Accessibility.Private || ((routine.IsSealed || routine.ContainingType.IsSealed) && routine.OverriddenMethod == null)); }
/// <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); }
/// <summary> /// Creates new type context, flow context and flow state for the routine. /// </summary> public static FlowState CreateInitialState(SourceRoutineSymbol/*!*/routine) { Contract.ThrowIfNull(routine); // create typeCtx var typeCtx = routine.TypeRefContext; // create FlowContext var flowCtx = new FlowContext(typeCtx, routine); // create FlowState var state = new FlowState(flowCtx); // handle input parameters type var parameters = routine.Parameters.OfType<SourceParameterSymbol>().ToImmutableArray(); foreach (var p in parameters) { state.SetVar(p.Name, p.GetResultType(typeCtx)); if (p.Syntax.PassedByRef) { state.SetVarRef(p.Name); } } // $this if (routine.HasThis) { InitThisVar(flowCtx, state); } // return state; }
/// <summary> /// Gets file symbol containing given symbol. /// </summary> public static SourceFileSymbol GetContainingFileSymbol(this Symbol s) { return(s?.OriginalDefinition switch { SourceRoutineSymbol routine => routine.ContainingFile, SourceTypeSymbol type => type.ContainingFile, _ => s != null?GetContainingFileSymbol(s.ContainingSymbol) : null, });
public SynthesizedStaticLocHolder(SourceRoutineSymbol routine, string locName, TypeSymbol locType = null) { Contract.ThrowIfNull(routine); _routine = routine; _locName = locName ?? "?"; _locType = locType; }
/// <summary> /// Builds the visibility scope. /// </summary> public static VisibilityScope Create(NamedTypeSymbol self, SourceRoutineSymbol routine) { return(new VisibilityScope() { Scope = self, ScopeIsDynamic = self.IsTraitType() || routine is SourceLambdaSymbol || (routine?.IsGlobalScope == true), }); }
public SourceLocalSymbol(SourceRoutineSymbol routine, string name, TextSpan span) { Debug.Assert(routine != null); Debug.Assert(!string.IsNullOrWhiteSpace(name)); _routine = routine; _name = name; }
public SourceLocalSymbol(SourceRoutineSymbol routine, string name, VariableKind kind) { Debug.Assert(routine != null); Debug.Assert(!string.IsNullOrWhiteSpace(name)); _routine = routine; _name = name; _kind = kind; }
/// <summary> /// Initializes table of locals of given routine. /// </summary> public LocalsTable(SourceRoutineSymbol routine) { Contract.ThrowIfNull(routine); _routine = routine; // PopuplateParameters(); }
public SourceGeneratorSymbol(SourceRoutineSymbol originalRoutine) : base(originalRoutine.ContainingType, string.Format(WellKnownPchpNames.GeneratorStateMachineNameFormatString, originalRoutine.RoutineName), isstatic: true, isvirtual: false, returnType: originalRoutine.DeclaringCompilation.CoreTypes.Void, ps: null) { Debug.Assert(originalRoutine.IsGeneratorMethod()); // Need to postpone settings the params because I can't access 'this' in base constructor call base.SetParameters(CreateParameters(originalRoutine)); }
internal FlowContext(TypeRefContext/*!*/typeCtx, SourceRoutineSymbol routine) { Contract.ThrowIfNull(typeCtx); _typeCtx = typeCtx; _routine = routine; // _varsIndex = new Dictionary<VariableName, int>(); }
public SourceParameterSymbol(SourceRoutineSymbol routine, FormalParam syntax, int index, PHPDocBlock.ParamTag ptagOpt) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(syntax); Debug.Assert(index >= 0); _routine = routine; _syntax = syntax; _index = index; _ptagOpt = ptagOpt; }
/// <summary> /// Gets PHPDoc assoviated with given source symbol. /// </summary> internal static bool TryGetPHPDocBlock(this Symbol symbol, out PHPDocBlock phpdoc) { phpdoc = symbol?.OriginalDefinition switch { SourceRoutineSymbol routine => routine.PHPDocBlock, SourceFieldSymbol field => field.PHPDocBlock, SourceTypeSymbol type => type.Syntax.PHPDoc, _ => null }; return(phpdoc != null); }
public SourceParameterSymbol(SourceRoutineSymbol routine, FormalParam syntax, int index, PHPDocBlock.ParamTag ptagOpt) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(syntax); Debug.Assert(index >= 0); _routine = routine; _syntax = syntax; _index = index; _ptagOpt = ptagOpt; _initializer = (syntax.InitValue != null) ? new SemanticsBinder(null).BindExpression(syntax.InitValue, BoundAccess.Read) : null; }
internal static MethodBody GenerateMethodBody( PEModuleBuilder moduleBuilder, SourceRoutineSymbol routine, int methodOrdinal, //ImmutableArray<LambdaDebugInfo> lambdaDebugInfo, //ImmutableArray<ClosureDebugInfo> closureDebugInfo, //StateMachineTypeSymbol stateMachineTypeOpt, VariableSlotAllocator variableSlotAllocatorOpt, DiagnosticBag diagnostics, //ImportChain importChainOpt, bool emittingPdb) { return GenerateMethodBody(moduleBuilder, routine, (builder) => { DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance(); var optimization = moduleBuilder.Compilation.Options.OptimizationLevel; var codeGen = new CodeGenerator(routine, builder, moduleBuilder, diagnosticsForThisMethod, optimization, emittingPdb); //if (diagnosticsForThisMethod.HasAnyErrors()) //{ // // we are done here. Since there were errors we should not emit anything. // return null; //} // We need to save additional debugging information for MoveNext of an async state machine. //var stateMachineMethod = method as SynthesizedStateMachineMethod; //bool isStateMachineMoveNextMethod = stateMachineMethod != null && method.Name == WellKnownMemberNames.MoveNextMethodName; //if (isStateMachineMoveNextMethod && stateMachineMethod.StateMachineType.KickoffMethod.IsAsync) //{ // int asyncCatchHandlerOffset; // ImmutableArray<int> asyncYieldPoints; // ImmutableArray<int> asyncResumePoints; // codeGen.Generate(out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints); // var kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod; // // The exception handler IL offset is used by the debugger to treat exceptions caught by the marked catch block as "user unhandled". // // This is important for async void because async void exceptions generally result in the process being terminated, // // but without anything useful on the call stack. Async Task methods on the other hand return exceptions as the result of the Task. // // So it is undesirable to consider these exceptions "user unhandled" since there may well be user code that is awaiting the task. // // This is a heuristic since it's possible that there is no user code awaiting the task. // asyncDebugInfo = new Cci.AsyncMethodBodyDebugInfo(kickoffMethod, kickoffMethod.ReturnsVoid ? asyncCatchHandlerOffset : -1, asyncYieldPoints, asyncResumePoints); //} //else { codeGen.Generate(); } }, variableSlotAllocatorOpt, diagnostics, emittingPdb); }
public SourceParameterSymbol(SourceRoutineSymbol routine, FormalParam syntax, int relindex, PHPDocBlock.ParamTag ptagOpt) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(syntax); Debug.Assert(relindex >= 0); _routine = routine; _syntax = syntax; _relindex = relindex; _ptagOpt = ptagOpt; _initializer = (syntax.InitValue != null) ? new SemanticsBinder(locals: null, diagnostics: DeclaringCompilation.DeclarationDiagnostics).BindWholeExpression(syntax.InitValue, BoundAccess.Read).GetOnlyBoundElement() : null; }
public SourceParameterSymbol(SourceRoutineSymbol routine, FormalParam syntax, int relindex, PHPDocBlock.ParamTag ptagOpt) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(syntax); Debug.Assert(relindex >= 0); _routine = routine; _syntax = syntax; _relindex = relindex; _ptagOpt = ptagOpt; _initializer = (syntax.InitValue != null) ? new SemanticsBinder(DeclaringCompilation, locals: null, routine: routine, self: routine.ContainingType as SourceTypeSymbol) .BindWholeExpression(syntax.InitValue, BoundAccess.Read) .SingleBoundElement() : null; }
/// <summary> /// Parameters for <see cref="SourceGeneratorSymbol"/> method are defined by <c>GeneratorStateMachineDelegate</c>. /// </summary> ParameterSymbol[] CreateParameters(SourceRoutineSymbol originalRoutine) { // resolve type of $this var thisType = originalRoutine.GetPhpThisVariablePlaceWithoutGenerator()?.Type ?? (TypeSymbol)originalRoutine.DeclaringCompilation.ObjectType; // yield sm method signature var index = 0; return(new[] { ContextParameter = new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++), ThisParameter = new SpecialParameterSymbol(this, thisType, SpecialParameterSymbol.ThisName, index++), LocalsParameter = new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.PhpArray, SpecialParameterSymbol.LocalsName, index++), TmpLocalsParameter = new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.PhpArray, SpecialParameterSymbol.TemporaryLocalsName, index++), GeneratorParameter = new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Generator, "generator", index++), }); }
/// <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> /// Parameters for <see cref="SourceGeneratorSymbol"/> method are defined by <c>GeneratorStateMachineDelegate</c>. /// </summary> ParameterSymbol[] getParams(SourceRoutineSymbol originalRoutine) { // resolve type of $this TypeSymbol thisType = originalRoutine.ThisParameter?.Type ?? (TypeSymbol)originalRoutine.DeclaringCompilation.ObjectType; Debug.Assert(thisType != null); // yield sm method signature var index = 0; return(new[] { new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++), new SpecialParameterSymbol(this, thisType, SpecialParameterSymbol.ThisName, index++), new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.PhpArray, SpecialParameterSymbol.LocalsName, index++), new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Generator, "generator", index++), }); }
/// <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()); } }); }
public SynthesizedLocalSymbol(SourceRoutineSymbol routine, string name, TypeSymbol type) : base(routine, name + "'", default(TextSpan)) { Contract.ThrowIfNull(type); _type = type; }
/// <summary> /// Gets value indicating the routine was found containing <c>yield</c> /// hence it is considered as a generator state machine method. /// </summary> /// <param name="routine">The analysed routine.</param> /// <returns>Value indicating the routine gets a generator.</returns> internal static bool IsGeneratorMethod(this SourceRoutineSymbol routine) => (routine.Flags & RoutineFlags.IsGenerator) != 0;
public SourceReturnSymbol(SourceRoutineSymbol routine) : base(routine, SpecialName, VariableKind.ReturnVariable) { }
public SynthesizedLocalSymbol(SourceRoutineSymbol routine, string name, TypeSymbol type) : base(routine, name + "#", VariableKind.LocalVariable) { Contract.ThrowIfNull(type); _type = type; }
public SynthesizedStaticLocHolder(SourceRoutineSymbol routine, string locName, TypeSymbol locType) { Contract.ThrowIfNull(routine); Contract.ThrowIfNull(locType); _routine = routine; _locName = locName ?? "?"; _locType = locType; }
/// <summary> /// Builds the visibility scope. /// </summary> public VisibilityScope(NamedTypeSymbol self, SourceRoutineSymbol routine) { Scope = self; ScopeIsDynamic = self.IsTraitType() || routine is SourceLambdaSymbol || (routine?.IsGlobalScope == true); }
/// <summary> /// Generates analyzed method. /// </summary> void EmitMethodBody(SourceRoutineSymbol routine) { Contract.ThrowIfNull(routine); Debug.Assert(routine.ControlFlowGraph != null); Debug.Assert(routine.ControlFlowGraph.Start.FlowState != null); var body = MethodGenerator.GenerateMethodBody(_moduleBuilder, routine, 0, null, _diagnostics, _emittingPdb); _moduleBuilder.SetMethodBody(routine, body); }