/// <summary> /// Creates CLS constructors for a PHP class. /// </summary> /// <param name="type">PHP class.</param> /// <returns>Enumeration of instance constructors for PHP class.</returns> /// <remarks> /// Constructors are created with respect to <c>base..ctor</c> and class PHP constructor function. /// At least a single <c>.ctor</c> is created which initializes fields and calls <c>base..ctor</c>. This is main constructor needed to properly initialize the class. /// In case there is a PHP constructor function: /// - The first ctor is marked as protected and is used only by other ctors and by derived classes to initialize class without calling the PHP constructor function. /// - Another ctor is created in order to call the main constructor and call PHP constructor function. /// - Ghost stubs of the other ctor are created in order to pass default parameter values which cannot be stored in metadata (e.g. array()). /// </remarks> public static IEnumerable <MethodSymbol> CreateCtors(SourceTypeSymbol type) { if (type.IsStatic || type.IsInterface) { yield break; } // resolve php constructor var phpconstruct = type.ResolvePhpCtor(true); // this tells us what parameters are provided so we can select best overload for base..ctor() call // resolve base .ctor that has to be called var btype = type.BaseType; var fieldsonlyctor = (MethodSymbol)(btype as IPhpTypeSymbol)?.InstanceConstructorFieldsOnly; // base..ctor() to be called if provided var basectors = (fieldsonlyctor != null) ? ImmutableArray.Create(fieldsonlyctor) : btype.InstanceConstructors .OrderByDescending(c => c.ParameterCount) // longest ctors first .AsImmutable(); // what parameters are provided var givenparams = (phpconstruct != null) ? phpconstruct.Parameters.Where(p => !p.IsImplicitlyDeclared && !p.IsParams).AsImmutable() : ImmutableArray <ParameterSymbol> .Empty; // first declare .ctor that initializes fields only and calls base .ctor var basector = ResolveBaseCtor(givenparams, basectors); if (basector == null) { // type.BaseType was not resolved, reported by type.BaseType // TODO: Err & ErrorMethodSymbol yield break; } // create .ctor(s) if (phpconstruct == null) { yield return(new SynthesizedPhpCtorSymbol(type, Accessibility.Public, false, basector, null)); } else { var fieldsinitctor = new SynthesizedPhpCtorSymbol(type, Accessibility.ProtectedOrInternal, true, basector, null); yield return(fieldsinitctor); // generate .ctor(s) calling PHP __construct with optional overloads in case there is an optional parameter var ps = phpconstruct.Parameters; for (int i = 0; i < ps.Length; i++) { var p = ps[i] as SourceParameterSymbol; if (p != null && p.Initializer != null && p.ExplicitDefaultConstantValue == null) // => ConstantValue couldn't be resolved for optional parameter { yield return(new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, false, fieldsinitctor, phpconstruct, i)); } } yield return(new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, false, fieldsinitctor, phpconstruct)); } yield break; }
/// <summary> /// Creates CLS constructors for a PHP class. /// </summary> /// <param name="type">PHP class.</param> /// <returns>Enumeration of instance constructors for PHP class.</returns> /// <remarks> /// Constructors are created with respect to <c>base..ctor</c> and class PHP constructor function. /// At least a single <c>.ctor</c> is created which initializes fields and calls <c>base..ctor</c>. This is main constructor needed to properly initialize the class. /// In case there is a PHP constructor function: /// - The first ctor is marked as protected and is used only by other ctors and by derived classes to initialize class without calling the PHP constructor function. /// - Another ctor is created in order to call the main constructor and call PHP constructor function. /// - Ghost stubs of the other ctor are created in order to pass default parameter values which cannot be stored in metadata (e.g. array()). /// </remarks> public static IEnumerable <MethodSymbol> CreateCtors(SourceTypeSymbol type) { if (type.IsStatic || type.IsInterface) { yield break; } // resolve php constructor var phpconstruct = type.ResolvePhpCtor(true); // this tells us what parameters are provided so we can select best overload for base..ctor() call // resolve base .ctor that has to be called var btype = type.BaseType; var fieldsonlyctor = (MethodSymbol)(btype as IPhpTypeSymbol)?.InstanceConstructorFieldsOnly; // base..ctor() to be called if provided var basectors = (fieldsonlyctor != null) ? ImmutableArray.Create(fieldsonlyctor) : btype.InstanceConstructors .Where(c => c.DeclaredAccessibility != Accessibility.Private) // ignore inaccessible .ctors .OrderByDescending(c => c.ParameterCount) // longest ctors first .AsImmutable(); // what parameters are provided var givenparams = (phpconstruct != null) ? phpconstruct.Parameters.Where(p => !p.IsImplicitlyDeclared && !p.IsParams).AsImmutable() : ImmutableArray <ParameterSymbol> .Empty; // first declare .ctor that initializes fields only and calls base .ctor var basector = ResolveBaseCtor(givenparams, basectors); if (basector == null) { // type.BaseType was not resolved, reported by type.BaseType // TODO: Err & ErrorMethodSymbol yield break; } MethodSymbol defaultctor; // .ctor to be used by default // create .ctor(s) if (phpconstruct == null) { yield return(defaultctor = new SynthesizedPhpCtorSymbol(type, Accessibility.Public, basector, null)); } else { var fieldsinitctor = new SynthesizedPhpCtorSymbol(type, Accessibility.ProtectedOrInternal, basector, null) { IsInitFieldsOnly = true, IsEditorBrowsableHidden = true, }; yield return(fieldsinitctor); // generate .ctor(s) calling PHP __construct with optional overloads in case there is an optional parameter var ps = phpconstruct.Parameters; for (int i = 0; i < ps.Length; i++) { var p = ps[i] as SourceParameterSymbol; if (p != null && p.Initializer != null && p.ExplicitDefaultConstantValue == null) // => ConstantValue couldn't be resolved for optional parameter { yield return(new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, fieldsinitctor, phpconstruct, i)); } } yield return(defaultctor = new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, fieldsinitctor, phpconstruct)); } // parameterless .ctor() with shared context if (defaultctor.DeclaredAccessibility == Accessibility.Public && type.DeclaredAccessibility == Accessibility.Public && !type.IsAbstract) { // Template: // void .ctor(...) : this(ContextExtensions.CurrentContext, ...) { } // NOTE: overload resolution will prioritize the overload with Context parameter over this one yield return(new SynthesizedParameterlessPhpCtorSymbol(type, Accessibility.Public, defaultctor)); } yield break; }
/// <summary> /// Creates CLS constructors for a PHP class. /// </summary> /// <param name="type">PHP class.</param> /// <returns>Enumeration of instance constructors for PHP class.</returns> /// <remarks> /// Constructors are created with respect to <c>base..ctor</c> and class PHP constructor function. /// At least a single <c>.ctor</c> is created which initializes fields and calls <c>base..ctor</c>. This is main constructor needed to properly initialize the class. /// In case there is a PHP constructor function: /// - The first ctor is marked as protected and is used only by other ctors and by derived classes to initialize class without calling the PHP constructor function. /// - Another ctor is created in order to call the main constructor and call PHP constructor function. /// - Ghost stubs of the other ctor are created in order to pass default parameter values which cannot be stored in metadata (e.g. array()). /// </remarks> public static ImmutableArray <MethodSymbol> CreateCtors(SourceTypeSymbol type) { if (type.IsStatic || type.IsInterface) { return(ImmutableArray <MethodSymbol> .Empty); } // resolve php constructor var phpconstruct = type.ResolvePhpCtor(true); // this tells us what parameters are provided so we can select best overload for base..ctor() call // resolve base .ctor that has to be called var btype = type.BaseType; var fieldsonlyctor = (MethodSymbol)(btype as IPhpTypeSymbol)?.InstanceConstructorFieldsOnly; // base..ctor() to be called if provided var basectors = (fieldsonlyctor != null) ? ImmutableArray.Create(fieldsonlyctor) : btype.InstanceConstructors .Where(c => c.DeclaredAccessibility != Accessibility.Private) // ignore inaccessible .ctors .OrderByDescending(c => c.ParameterCount) // longest ctors first .AsImmutable(); // what parameters are provided var givenparams = (phpconstruct != null) ? phpconstruct.Parameters.Where(p => !p.IsImplicitlyDeclared && !p.IsParams).AsImmutable() : ImmutableArray <ParameterSymbol> .Empty; // first declare .ctor that initializes fields only and calls base .ctor var basector = ResolveBaseCtor(givenparams, basectors); if (basector == null) { // type.BaseType was not resolved, reported by type.BaseType // TODO: Err & ErrorMethodSymbol return(ImmutableArray <MethodSymbol> .Empty); } MethodSymbol defaultctor = null; // .ctor to be used by default var ctors = ImmutableArray.CreateBuilder <MethodSymbol>(); // create .ctor(s) if (phpconstruct == null) { ctors.Add(defaultctor = new SynthesizedPhpCtorSymbol(type, Accessibility.Public, basector, null)); } else { var fieldsinitctor = new SynthesizedPhpCtorSymbol(type, Accessibility.ProtectedOrInternal, basector, null) { IsInitFieldsOnlyPrivate = true, IsEditorBrowsableHidden = true, }; ctors.Add(fieldsinitctor); if (!type.IsAbstract) { //// generate .ctor(s) calling PHP __construct with optional overloads in case there is an optional parameter //var ps = phpconstruct.Parameters; //for (int i = 0; i < ps.Length; i++) //{ // if (ps[i].HasUnmappedDefaultValue()) // { // yield return new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, fieldsinitctor, phpconstruct, i); // } //} ctors.Add(defaultctor = new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, fieldsinitctor, phpconstruct)); } } // parameterless .ctor() with shared context if (defaultctor != null && defaultctor.DeclaredAccessibility == Accessibility.Public && type.DeclaredAccessibility == Accessibility.Public && !type.IsAbstract) { // Template: // [PhpHidden][CompilerGenerated] // void .ctor(...) : this(ContextExtensions.CurrentContext, ...) { } // NOTE: overload resolution will prioritize the overload with Context parameter over this one // argless ctor must be first! // used for various dependency-injection situations ctors.Insert(0, new SynthesizedParameterlessPhpCtorSymbol(type, Accessibility.Public, defaultctor)); } // return(ctors.ToImmutable()); }