// Mono.Util.CorCompare.MissingType // // Author(s): // Nick Drochak (ndrochak@gol.com) // // (C) 2001-2002 Nick Drochak using System; using System.Xml; using System.Reflection; using System.Collections; namespace Mono.Util.CorCompare { /// /// Represents a class method that missing. /// /// /// created by - Nick /// created on - 2/20/2002 10:43:57 PM /// class MissingType : MissingBase { // e.g. // e.g. Type typeMono, typeMS; // ArrayList rgAttributes = new ArrayList (); ArrayList rgMethods = new ArrayList (); ArrayList rgProperties = new ArrayList (); ArrayList rgEvents = new ArrayList (); ArrayList rgFields = new ArrayList (); ArrayList rgConstructors = new ArrayList (); ArrayList rgNestedTypes = new ArrayList (); ArrayList rgInterfaces = new ArrayList (); // NodeStatus nsAttributes = new NodeStatus (); NodeStatus nsMethods = new NodeStatus (); NodeStatus nsProperties = new NodeStatus (); NodeStatus nsEvents = new NodeStatus (); NodeStatus nsFields = new NodeStatus (); NodeStatus nsConstructors = new NodeStatus (); NodeStatus nsNestedTypes = new NodeStatus (); NodeStatus nsInterfaces = new NodeStatus (); public MissingType (Type _typeMono, Type _typeMS) { typeMono = _typeMono; typeMS = _typeMS; m_nodeStatus = new NodeStatus (_typeMono, _typeMS); } public override string Name { get { Type type = TypeInfoBest; if (type.DeclaringType != null) return type.DeclaringType.Name + "+" + type.Name; return type.Name; } } public override string Type { get { Type type = TypeInfo; if (type.IsEnum) return "enum"; else if (type.IsInterface) return "interface"; else if (type.IsValueType) return "struct"; else if (IsDelegate) return "delegate"; else return "class"; } } public Type TypeInfo { get { return (typeMono != null) ? typeMono : typeMS; } } public Type TypeInfoBest { get { return (typeMS == null) ? typeMono : typeMS; } } public bool IsDelegate { get { Type typeBest = TypeInfoBest; if (typeBest.IsEnum || typeBest.IsInterface || typeBest.IsValueType) return false; Type type = typeBest.BaseType; while (type != null) { if (type.FullName == "System.Delegate") return true; type = type.BaseType; } return false; } } public MissingMember CreateMember (MemberInfo infoMono, MemberInfo infoMS) { MemberTypes mt = (infoMono != null) ? infoMono.MemberType : infoMS.MemberType; MissingMember mm; switch (mt) { case MemberTypes.Method: mm = new MissingMethod (infoMono, infoMS); break; case MemberTypes.Property: mm = new MissingProperty (infoMono, infoMS); break; case MemberTypes.Event: mm = new MissingEvent (infoMono, infoMS); break; case MemberTypes.Field: mm = new MissingField (infoMono, infoMS); break; case MemberTypes.Constructor: mm = new MissingConstructor (infoMono, infoMS); break; case MemberTypes.NestedType: mm = new MissingNestedType (infoMono, infoMS); break; default: throw new Exception ("Unexpected MemberType: " + mt.ToString()); } mm.Analyze (); return mm; } public void AddMember (MissingMember mm) { switch (mm.Info.MemberType) { case MemberTypes.Method: nsMethods.AddChildren (mm.Status); rgMethods.Add (mm); break; case MemberTypes.Property: nsProperties.AddChildren (mm.Status); rgProperties.Add (mm); break; case MemberTypes.Event: nsEvents.AddChildren (mm.Status); rgEvents.Add (mm); break; case MemberTypes.Field: nsFields.AddChildren (mm.Status); rgFields.Add (mm); break; case MemberTypes.Constructor: nsConstructors.AddChildren (mm.Status); rgConstructors.Add (mm); break; case MemberTypes.NestedType: nsNestedTypes.AddChildren (mm.Status); rgNestedTypes.Add (mm); break; default: throw new Exception ("Unexpected MemberType: " + mm.Info.ToString()); } } public void AddMember (MemberInfo infoMono, MemberInfo infoMS) { AddMember (CreateMember (infoMono, infoMS)); } public override XmlElement CreateXML (XmlDocument doc) { XmlElement eltClass = base.CreateXML (doc); XmlElement eltMember; eltMember = MissingBase.CreateMemberCollectionElement ("methods", rgMethods, nsMethods, doc); if (eltMember != null) eltClass.AppendChild (eltMember); eltMember = MissingBase.CreateMemberCollectionElement ("properties", rgProperties, nsProperties, doc); if (eltMember != null) eltClass.AppendChild (eltMember); eltMember = MissingBase.CreateMemberCollectionElement ("events", rgEvents, nsEvents, doc); if (eltMember != null) eltClass.AppendChild (eltMember); eltMember = MissingBase.CreateMemberCollectionElement ("fields", rgFields, nsFields, doc); if (eltMember != null) eltClass.AppendChild (eltMember); eltMember = MissingBase.CreateMemberCollectionElement ("constructors", rgConstructors, nsConstructors, doc); if (eltMember != null) eltClass.AppendChild (eltMember); eltMember = MissingBase.CreateMemberCollectionElement ("nestedTypes", rgNestedTypes, nsNestedTypes, doc); if (eltMember != null) eltClass.AppendChild (eltMember); eltMember = MissingBase.CreateMemberCollectionElement ("interfaces", rgInterfaces, nsInterfaces, doc); if (eltMember != null) eltClass.AppendChild (eltMember); return eltClass; } public override NodeStatus Analyze () { Hashtable htMono = new Hashtable (); if (typeMono != null) { ArrayList rgIgnoreMono = new ArrayList (); foreach (MemberInfo miMono in typeMono.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (typeMono == miMono.DeclaringType) { string strName = MissingMember.GetUniqueName (miMono); htMono.Add (strName, miMono); // ignore any property/event accessors if (miMono.MemberType == MemberTypes.Property) { PropertyInfo pi = (PropertyInfo) miMono; MemberInfo miGet = pi.GetGetMethod (); if (miGet != null) rgIgnoreMono.Add (miGet); MemberInfo miSet = pi.GetSetMethod (); if (miSet != null) rgIgnoreMono.Add (miSet); } else if (miMono.MemberType == MemberTypes.Event) { EventInfo ei = (EventInfo) miMono; MemberInfo miAdd = ei.GetAddMethod (); if (miAdd != null) rgIgnoreMono.Add (miAdd); MemberInfo miRemove = ei.GetRemoveMethod (); if (miRemove != null) rgIgnoreMono.Add (miRemove); MemberInfo miRaise = ei.GetRaiseMethod (); if (miRaise != null) rgIgnoreMono.Add (miRaise); } } } foreach (MemberInfo miIgnore in rgIgnoreMono) htMono.Remove (MissingMember.GetUniqueName (miIgnore)); } Hashtable htMethodsMS = new Hashtable (); if (typeMS != null) { ICollection colMembersMS = typeMS.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Hashtable htIgnoreMS = new Hashtable (); foreach (MemberInfo miMS in colMembersMS) { // ignore any property/event accessors if (miMS.MemberType == MemberTypes.Property) { PropertyInfo pi = (PropertyInfo) miMS; MemberInfo miGet = pi.GetGetMethod (); if (miGet != null) htIgnoreMS.Add (miGet, miMS); MemberInfo miSet = pi.GetSetMethod (); if (miSet != null) htIgnoreMS.Add (miSet, miMS); } else if (miMS.MemberType == MemberTypes.Event) { EventInfo ei = (EventInfo) miMS; MemberInfo miAdd = ei.GetAddMethod (); if (miAdd != null) htIgnoreMS.Add (miAdd, miMS); MemberInfo miRemove = ei.GetRemoveMethod (); if (miRemove != null) htIgnoreMS.Add (miRemove, miMS); MemberInfo miRaise = ei.GetRaiseMethod (); if (miRaise != null) htIgnoreMS.Add (miRaise, miMS); } } foreach (MemberInfo miMS in colMembersMS) { if (miMS != null && miMS.DeclaringType == typeMS && !htIgnoreMS.Contains (miMS)) { string strNameUnique = MissingMember.GetUniqueName (miMS); MemberInfo miMono = (MemberInfo) htMono [strNameUnique]; MissingMember mm = CreateMember (miMono, miMS); bool fVisibleMS = IsVisible (miMS); if (miMono == null) { if (fVisibleMS) AddMember (mm); } else { if (miMono.MemberType != miMS.MemberType) { //AddMember (null, miMS); //MissingMember mm2 = CreateMember (miMono, null); //mm2.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']"); //AddMember (mm2); mm.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']"); AddMember (mm); } else if (fVisibleMS || IsVisible (miMono)) { AddMember (mm); } htMono.Remove (strNameUnique); } switch (miMS.MemberType) { case MemberTypes.Method: { string strNameMSFull = miMS.ToString (); int ichMS = strNameMSFull.IndexOf (' '); string strNameMS = strNameMSFull.Substring (ichMS + 1); if (!htMethodsMS.Contains (strNameMS)) htMethodsMS.Add (strNameMSFull.Substring (ichMS + 1), miMS); break; } } } } } foreach (MemberInfo miMono in htMono.Values) { if (IsVisible (miMono)) { MissingMember mm = CreateMember (miMono, null); switch (miMono.MemberType) { case MemberTypes.Method: { string strNameMonoFull = miMono.ToString (); int ichMono = strNameMonoFull.IndexOf (' '); string strNameMono = strNameMonoFull.Substring (ichMono + 1); MemberInfo miMS = (MemberInfo) htMethodsMS [strNameMono]; if (miMS != null) { string strNameMSFull = miMS.ToString (); int ichMS = strNameMSFull.IndexOf (' '); string strReturnTypeMS = strNameMSFull.Substring (0, ichMS); string strReturnTypeMono = strNameMonoFull.Substring (0, ichMono); mm.Status.AddWarning ("Return type mismatch, is: '"+strReturnTypeMono+"' [should be: '"+strReturnTypeMS+"']"); //Console.WriteLine ("WARNING: Return type mismatch on "+miMS.DeclaringType.FullName+"."+strNameMono+", is: '"+strReturnTypeMono+"' [should be: '"+strReturnTypeMS+"']"); } break; } } AddMember (mm); } } // compare the attributes rgAttributes = new ArrayList (); nsAttributes = MissingAttribute.AnalyzeAttributes ( (typeMono == null) ? null : typeMono.GetCustomAttributes (false), ( typeMS == null) ? null : typeMS.GetCustomAttributes (false), rgAttributes); rgInterfaces = new ArrayList (); if (typeMono != null && typeMS != null) { // compare base types string strBaseMono = (typeMono.BaseType == null) ? null : typeMono.BaseType.FullName; string strBaseMS = ( typeMS.BaseType == null) ? null : typeMS.BaseType.FullName; if (strBaseMono != strBaseMS) { m_nodeStatus.AddWarning ("Base class mismatch, is '"+strBaseMono+"' [should be: '"+strBaseMS+"']"); //Console.WriteLine ("WARNING: Base class mismatch on "+typeMono.FullName+", is: '"+strBaseMono+"' [should be: '"+strBaseMS+"']"); } // compare the interfaces Hashtable htInterfacesMono = new Hashtable (); Type [] rgInterfacesMono = typeMono.GetInterfaces (); foreach (Type ifaceMono in rgInterfacesMono) { if (ifaceMono != null) { string strName = ifaceMono.FullName; htInterfacesMono.Add (strName, ifaceMono); } } Type [] rgInterfacesMS = typeMS.GetInterfaces (); foreach (Type ifaceMS in rgInterfacesMS) { if (ifaceMS != null) { string strName = ifaceMS.FullName; Type ifaceMono = (Type) htInterfacesMono [strName]; MissingInterface mi = new MissingInterface (ifaceMono, ifaceMS); mi.Analyze (); rgInterfaces.Add (mi); if (ifaceMono != null) htInterfacesMono.Remove (strName); nsInterfaces.AddChildren (mi.Status); } } foreach (Type ifaceMono in htInterfacesMono.Values) { MissingInterface mi = new MissingInterface (ifaceMono, null); mi.Analyze (); rgInterfaces.Add (mi); //Console.WriteLine ("WARNING: additional interface on "+typeMono.FullName+": '"+ifaceMono.FullName+"'"); nsInterfaces.AddChildren (mi.Status); } // serializable attribute // AddFakeAttribute (typeMono.IsSerializable, typeMS.IsSerializable, "System.SerializableAttribute"); AddFakeAttribute (typeMono.IsAutoLayout, typeMS.IsAutoLayout, "System.AutoLayoutAttribute"); AddFakeAttribute (typeMono.IsExplicitLayout, typeMS.IsExplicitLayout, "System.ExplicitLayoutAttribute"); AddFakeAttribute (typeMono.IsLayoutSequential, typeMS.IsLayoutSequential, "System.SequentialLayoutAttribute"); Accessibility accessibilityMono = GetAccessibility (typeMono); Accessibility accessibilityMS = GetAccessibility (typeMS); if (accessibilityMono != accessibilityMS) m_nodeStatus.AddWarning ("Should be "+AccessibilityToString (accessibilityMono)); AddFlagWarning (typeMono.IsSealed, typeMS.IsSealed, "sealed"); AddFlagWarning (typeMono.IsAbstract, typeMS.IsAbstract, "abstract"); } // sum up the sub-sections m_nodeStatus.Add (nsAttributes); m_nodeStatus.Add (nsMethods); m_nodeStatus.Add (nsProperties); m_nodeStatus.Add (nsEvents); m_nodeStatus.Add (nsFields); m_nodeStatus.Add (nsConstructors); m_nodeStatus.Add (nsNestedTypes); m_nodeStatus.Add (nsInterfaces); return m_nodeStatus; } static bool IsVisible (MemberInfo mi) { // this is just embarrasing, couldn't they have virtualized this? switch (mi.MemberType) { case MemberTypes.Constructor: case MemberTypes.Method: return !((MethodBase) mi).IsPrivate && !((MethodBase) mi).IsFamilyAndAssembly && !((MethodBase) mi).IsAssembly; case MemberTypes.Field: return !((FieldInfo) mi).IsPrivate && !((FieldInfo) mi).IsFamilyAndAssembly && !((FieldInfo) mi).IsAssembly; case MemberTypes.NestedType: return !((Type) mi).IsNestedPrivate && !((Type) mi).IsNestedAssembly && !((Type) mi).IsNestedFamANDAssem; case MemberTypes.Property: // great, now we have to look at the methods PropertyInfo pi = (PropertyInfo) mi; MethodInfo miAccessor = pi.GetGetMethod (); if (miAccessor == null) miAccessor = pi.GetSetMethod (); if (miAccessor == null) return false; return IsVisible (miAccessor); case MemberTypes.Event: // ditto EventInfo ei = (EventInfo) mi; MethodInfo eiAccessor = ei.GetAddMethod (); if (eiAccessor == null) eiAccessor = ei.GetRemoveMethod (); if (eiAccessor == null) eiAccessor = ei.GetRaiseMethod (); if (eiAccessor == null) return false; return IsVisible (eiAccessor); default: throw new Exception ("Missing handler for MemberType: "+mi.MemberType.ToString ()); } } static Accessibility GetAccessibility (Type type) { if (type.IsPublic) return Accessibility.Public; else if (type.IsNotPublic) return Accessibility.Private; return MissingMember.GetAccessibility (type); } } }