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

            // 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;
        }
Пример #2
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
                                 .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());
        }