Ejemplo n.º 1
0
        /// <summary>
        /// Get (or try to get) the first and the best protocol that implements the given message.
        /// </summary>
        /// <param name="methodName">Selector of the message to look for.</param>
        /// <param name="methodType">Type of the method (instance / class) to look for.</param>
        /// <param name="cls">Class where to start looking for the method.</param>
        /// <param name="protocolName">Optional protocol that may contain the message.</param>
        /// <returns>Message definition for the given selector or null if one was not found.</returns>
        public static Definitions.Description.Message GetMessageForMethod(string methodName, MethodType methodType, Class cls, string protocolName)
        {
            if (String.IsNullOrWhiteSpace(methodName))
            {
                throw new ArgumentNullException("methodName");
            }
            if (methodType == null)
            {
                throw new ArgumentNullException("methodType");
            }
            if (cls == null)
            {
                throw new ArgumentNullException("cls");
            }

            while (cls != null)
            {
                Definitions.Description.Message msg = null;
                var prot = cls.Parent.SmalltalkSystem.SystemDescription.Protocols.FirstOrDefault(p => p.Name == protocolName);
                if (prot != null)
                {
                    msg = prot.Messages.FirstOrDefault(m => m.Selector == methodName);
                }
                if (msg != null)
                {
                    return(msg);
                }

                List <Class> classesList;
                List <Class> superclassesList;
                Dictionary <string, Class>          classesMap;
                Dictionary <string, List <Class> >  protocolNameClassesMap;
                Dictionary <string, List <Class> >  protocolNameSuperslassesMap;
                Dictionary <string, List <Class> >  methodNameClassesMap;
                Dictionary <string, List <Class> >  methodNameSuperclassesMap;
                Dictionary <string, List <string> > methodNameProtocolNamesMap;
                Dictionary <string, List <string> > allMethodNameProtocolNamesMap;
                Dictionary <string, Definitions.Description.Protocol> protocolMap;
                HashSet <string> subclassResponsibilityMethods;
                Dictionary <string, List <Class> > methodNameLocalImplementorsMap;
                Dictionary <string, List <Class> > methodNameSuperImplementorsMap;
                MethodHelper.BuildLists(cls, cls, methodType, out classesList, out superclassesList, out classesMap,
                                        out protocolNameClassesMap, out protocolNameSuperslassesMap, out methodNameClassesMap,
                                        out methodNameSuperclassesMap, out methodNameProtocolNamesMap, out allMethodNameProtocolNamesMap,
                                        out protocolMap, out subclassResponsibilityMethods, out methodNameLocalImplementorsMap,
                                        out methodNameSuperImplementorsMap);
                List <string> pns;
                methodNameProtocolNamesMap.TryGetValue(methodName, out pns);
                if ((pns != null) && (pns.Count > 0))
                {
                    protocolMap.TryGetValue(pns[0], out prot);
                    if (prot != null)
                    {
                        msg = prot.Messages.FirstOrDefault(m => m.Selector == methodName);
                    }
                }
                if (msg != null)
                {
                    return(msg);
                }

                if (String.IsNullOrWhiteSpace(cls.SuperclassName))
                {
                    cls = null;
                }
                else
                {
                    cls = cls.Parent.Classes.FirstOrDefault(c => c.Name == cls.SuperclassName);
                }
            }

            return(null);
        }
        private void FillView()
        {
            if (this.ListItemChanging)
            {
                return;
            }
            this.Enabled = false;
            this.listMethods.Items.Clear();
            if (this.Class == null)
            {
                return;
            }
            if (String.IsNullOrWhiteSpace(this.ProtocolName))
            {
                return;
            }
            if (this.MethodType == null)
            {
                return;
            }

            this.listMethods.BeginUpdate();
            Font normalFont = this.listMethods.Font;
            Font boldFont   = new Font(normalFont, FontStyle.Bold);

            List <Class> classesList;
            List <Class> superclassesList;
            Dictionary <string, Class>          classesMap;
            Dictionary <string, List <Class> >  protocolNameClassesMap;
            Dictionary <string, List <Class> >  protocolNameSuperslassesMap;
            Dictionary <string, List <Class> >  methodNameClassesMap;
            Dictionary <string, List <Class> >  methodNameSuperclassesMap;
            Dictionary <string, List <string> > methodNameProtocolNamesMap;
            Dictionary <string, List <string> > allMethodNameProtocolNamesMap;
            Dictionary <string, Definitions.Description.Protocol> protocolMap;
            HashSet <string> subclassResponsibilityMethods;
            Dictionary <string, List <Class> > methodNameLocalImplementorsMap;
            Dictionary <string, List <Class> > methodNameSuperImplementorsMap;

            MethodHelper.BuildLists(this.Class, this.IncludeUpToClass, this.MethodType, out classesList, out superclassesList,
                                    out classesMap, out protocolNameClassesMap, out protocolNameSuperslassesMap, out methodNameClassesMap,
                                    out methodNameSuperclassesMap, out methodNameProtocolNamesMap, out allMethodNameProtocolNamesMap,
                                    out protocolMap, out subclassResponsibilityMethods, out methodNameLocalImplementorsMap, out methodNameSuperImplementorsMap);

            /* *** CREATE THE LIST OF METHODS ***
             * The logic is as follows:
             *      1. Consider methods that:
             *          a. Are implemented by the this.Class itself
             *          b. Are implemented by any superclass up to and incl. this.IncludeUpToClass
             *          c. Are defined (actually messages) in any protocol that this.Class wants to implement
             *          d. Are defined (actually messages) in any protocol that any superclass up to and incl. this.IncludeUpToClass wants to implement
             *          * Obviously, depending on this.MethodType we concider only the class methods/protocols or the instance ones
             *      2. Filter methods so:
             *          a. If this.ProtocolName is "ANY", then include everything.
             *          b. If this.ProtocolName is "PRIVATE", then include method found in 1.a. or 1.b. but NOT also in 1.c. and 1.d.
             *          c. Include methods found in 1.c. or 1.d. according to the name of the selected protocol
             *          d. Similar to b., but also method in any protocol that any of the superclasses wants to implements
             *
             *      3. Create list items for each method with following details:
             *          a. Method selector
             *          b. Lists if protocols defining it (similar to 1.c and 1.d but up to the root class)
             *          c. Local implementors of the methods (subclasses of this.Class, but NOT this.Class itself)
             *          d. Super implementors of the methods (superclasses of this.IncludeUpToClass, but NOT this.IncludeUpToClass itself)
             *      4. Decorate (color) each item:
             *          a. Only defined (in protocols) but not implemented: Gray
             *          b. Implementation is empty and super implementor exists that says subclassResponsibility: Red
             *          c. Found in 1.a. or 1.c. (as oposite to 1.b and 1.d): Bold Font
             */


            HashSet <string> methodNames = new HashSet <string>();

            methodNames.UnionWith(methodNameClassesMap.Keys);
            methodNames.UnionWith(methodNameProtocolNamesMap.Keys);

            foreach (string selector in methodNames.OrderBy(s => s))
            {
                bool include;
                if (this.ProtocolName == "ANY")
                {
                    include = true;
                }
                else if (this.ProtocolName == "PRIVATE")
                {
                    include = !methodNameProtocolNamesMap.ContainsKey(selector) || (methodNameProtocolNamesMap[selector].Count == 0);
                }
                else
                {
                    include = allMethodNameProtocolNamesMap.ContainsKey(selector) && allMethodNameProtocolNamesMap[selector].Contains(this.ProtocolName);
                }

                if (include)
                {
                    ListViewItem lvi = this.listMethods.Items.Add(selector, "method");
                    lvi.Tag = selector;
                    lvi.UseItemStyleForSubItems = false;

                    // Is the method implemented by any class (as oposite by only defined by a protocol implemented by the class)
                    if (!methodNameClassesMap.ContainsKey(selector))
                    {
                        lvi.ForeColor = Color.Gray;
                    }

                    // Is this a method that we must override?
                    if (subclassResponsibilityMethods.Contains(selector))
                    {
                        lvi.ForeColor = Color.Red;
                    }


                    IEnumerable <string> definingProtocols = new string[0];
                    if (allMethodNameProtocolNamesMap.ContainsKey(selector))
                    {
                        definingProtocols = allMethodNameProtocolNamesMap[selector];
                    }

                    // This is a method defined in locally implemented protocol
                    if (definingProtocols.Any(pn => protocolNameClassesMap.ContainsKey(pn) && protocolNameClassesMap[pn].Contains(this.Class)))
                    {
                        lvi.Font = boldFont;
                    }

                    // This is a locally implemented method
                    if (methodNameClassesMap.ContainsKey(selector) && methodNameClassesMap[selector].Contains(this.Class))
                    {
                        lvi.Font = boldFont;
                    }

                    IEnumerable <Class> implementingClasses = new Class[0];
                    if (methodNameClassesMap.ContainsKey(selector))
                    {
                        implementingClasses = methodNameClassesMap[selector];
                    }

                    // Protocols: (which protocols defines the method)
                    string protocols = String.Join(", ", definingProtocols.OrderBy(p => p));
                    lvi.SubItems.Add((String.IsNullOrWhiteSpace(protocols) ? "PRIVATE" : protocols));
                    lvi.SubItems[lvi.SubItems.Count - 1].Font      = lvi.Font;
                    lvi.SubItems[lvi.SubItems.Count - 1].ForeColor = lvi.ForeColor;

                    // Local Implementors: (excluding the current class)
                    lvi.SubItems.Add(String.Join(", ", methodNameLocalImplementorsMap[selector].Select(c => c.Name))).Font = normalFont;

                    // Super Implementors: (excluding listed classes)
                    lvi.SubItems.Add(String.Join(", ", methodNameSuperImplementorsMap[selector].Select(c => c.Name))).Font = normalFont;

                    lvi.ToolTipText = String.Format("Defined: {0}\nImplemented: {1}",
                                                    protocols, String.Join(", ", implementingClasses.Select(c => c.Name)));

                    lvi.Selected = (this.MethodName == selector);
                }
            }

            this.listMethods.EndUpdate();

            if (this.listMethods.SelectedItems.Count > 0)
            {
                this.listMethods.SelectedItems[0].EnsureVisible();
            }

            this.Enabled = true;
        }