Пример #1
0
        /// <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;
            }

            MethodSymbol defaultctor; // .ctor to be used by default

            // create .ctor(s)
            if (phpconstruct == null)
            {
                yield return(defaultctor = 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(defaultctor = new SynthesizedPhpCtorSymbol(type, phpconstruct.DeclaredAccessibility, false, fieldsinitctor, phpconstruct));
            }

            // parameterless .ctor() for shared context
            if (type.GetAttributes().FirstOrDefault(IsSharedContextAttribute) != null)
            {
                // Template:
                // void .ctor() : this(Context.Default) { }
                yield return(new SynthesizedParameterlessPhpCtorSymbol(type, Accessibility.Public, defaultctor));
            }

            yield break;
        }