//
        // Factory method: if there are pending implementation methods, we return a PendingImplementation
        // object, otherwise we return null.
        //
        // Register method implementations are either abstract methods
        // flagged as such on the base class or interface methods
        //
        static public PendingImplementation GetPendingImplementations(TypeContainer container)
        {
            TypeSpec b = container.BaseType;

            var missing_interfaces = GetMissingInterfaces(container);

            //
            // If we are implementing an abstract class, and we are not
            // ourselves abstract, and there are abstract methods (C# allows
            // abstract classes that have no abstract methods), then allocate
            // one slot.
            //
            // We also pre-compute the methods.
            //
            bool implementing_abstract = ((b != null) && b.IsAbstract && (container.ModFlags & Modifiers.ABSTRACT) == 0);

            MethodSpec[] abstract_methods = null;

            if (implementing_abstract)
            {
                var am = MemberCache.GetNotImplementedAbstractMethods(b);

                if (am == null)
                {
                    implementing_abstract = false;
                }
                else
                {
                    abstract_methods = new MethodSpec[am.Count];
                    am.CopyTo(abstract_methods, 0);
                }
            }

            int total = missing_interfaces.Length + (implementing_abstract ? 1 : 0);

            if (total == 0)
            {
                return(null);
            }

            return(new PendingImplementation(container, missing_interfaces, abstract_methods, total));
        }
Esempio n. 2
0
        //
        // Factory method: if there are pending implementation methods, we return a PendingImplementation
        // object, otherwise we return null.
        //
        // Register method implementations are either abstract methods
        // flagged as such on the base class or interface methods
        //
        static public PendingImplementation GetPendingImplementations(TypeDefinition container)
        {
            TypeSpec b = container.BaseType;

            var missing_interfaces = GetMissingInterfaces(container);

            //
            // If we are implementing an abstract class, and we are not
            // ourselves abstract, and there are abstract methods (C# allows
            // abstract classes that have no abstract methods), then allocate
            // one slot.
            //
            // We also pre-compute the methods.
            //
            bool implementing_abstract = ((b != null) && b.IsAbstract && (container.ModFlags & Modifiers.ABSTRACT) == 0);

            MethodSpec[] abstract_methods = null;

            if (implementing_abstract)
            {
                var am = MemberCache.GetNotImplementedAbstractMethods(b);

                if (am == null)
                {
                    implementing_abstract = false;
                }
                else
                {
                    abstract_methods = new MethodSpec[am.Count];
                    am.CopyTo(abstract_methods, 0);
                }
            }

            int total = missing_interfaces.Length + (implementing_abstract ? 1 : 0);

            if (total == 0)
            {
                return(null);
            }

            var pending = new PendingImplementation(container, missing_interfaces, abstract_methods, total);

            //
            // check for inherited conflicting methods
            //
            foreach (var p in pending.pending_implementations)
            {
                //
                // It can happen for generic interfaces only
                //
                if (!p.type.IsGeneric)
                {
                    continue;
                }

                //
                // CLR does not distinguishes between ref and out
                //
                for (int i = 0; i < p.methods.Count; ++i)
                {
                    MethodSpec compared_method = p.methods[i];
                    if (compared_method.Parameters.IsEmpty)
                    {
                        continue;
                    }

                    for (int ii = i + 1; ii < p.methods.Count; ++ii)
                    {
                        MethodSpec tested_method = p.methods[ii];
                        if (compared_method.Name != tested_method.Name)
                        {
                            continue;
                        }

                        if (p.type != tested_method.DeclaringType)
                        {
                            continue;
                        }

                        if (!TypeSpecComparer.Override.IsSame(compared_method.Parameters.Types, tested_method.Parameters.Types))
                        {
                            continue;
                        }

                        bool exact_match         = true;
                        bool ref_only_difference = false;
                        var  cp = compared_method.Parameters.FixedParameters;
                        var  tp = tested_method.Parameters.FixedParameters;

                        for (int pi = 0; pi < cp.Length; ++pi)
                        {
                            //
                            // First check exact modifiers match
                            //
                            if ((cp[pi].ModFlags & Parameter.Modifier.RefOutMask) == (tp[pi].ModFlags & Parameter.Modifier.RefOutMask))
                            {
                                continue;
                            }

                            if (((cp[pi].ModFlags | tp[pi].ModFlags) & Parameter.Modifier.RefOutMask) == Parameter.Modifier.RefOutMask)
                            {
                                ref_only_difference = true;
                                continue;
                            }

                            exact_match = false;
                            break;
                        }

                        if (!exact_match || !ref_only_difference)
                        {
                            continue;
                        }

                        pending.Report.SymbolRelatedToPreviousError(compared_method);
                        pending.Report.SymbolRelatedToPreviousError(tested_method);
                        pending.Report.Error(767, container.Location,
                                             "Cannot implement interface `{0}' with the specified type parameters because it causes method `{1}' to differ on parameter modifiers only",
                                             p.type.GetDefinition().GetSignatureForError(), compared_method.GetSignatureForError());

                        break;
                    }
                }
            }

            return(pending);
        }