// 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 { return TypeInfoBest.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);
//m_nodeStatus.SetAttributes (eltClass);
XmlElement eltMember;
// eltMember = MissingBase.CreateMemberCollectionElement ("attributes", rgAttributes, nsAttributes, doc);
// if (eltMember != null)
// eltClass.AppendChild (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)
{
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);
}
}
}
Hashtable htMethodsMS = new Hashtable ();
if (typeMS != null)
{
foreach (MemberInfo miMS in typeMS.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
if (miMS != null && miMS.DeclaringType == typeMS)
{
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
{
bool fVisibleMono = IsVisible (miMono);
if (fVisibleMS != fVisibleMono)
{
if (fVisibleMS)
mm.Status.AddWarning ("Should be visible");
else
mm.Status.AddWarning ("Should be hidden");
}
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 || fVisibleMono)
{
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);
}
}
// sort out the properties
foreach (MissingProperty property in rgProperties)
{
MemberInfo infoBest = property.BestInfo;
if (infoBest is PropertyInfo)
{
PropertyInfo pi = (PropertyInfo) property.BestInfo;
MethodInfo miGet = pi.GetGetMethod (true);
MethodInfo miSet = pi.GetSetMethod (true);
if (miGet == null)
miGet = ((PropertyInfo) property.Info).GetGetMethod (true);
if (miSet == null)
miSet = ((PropertyInfo) property.Info).GetSetMethod (true);
MissingMethod mmGet = FindMethod (miGet);
MissingMethod mmSet = FindMethod (miSet);
if (mmGet != null)
{
nsMethods.SubChildren (mmGet.Status);
rgMethods.Remove (mmGet);
property.GetMethod = mmGet;
}
if (mmSet != null)
{
nsMethods.SubChildren (mmSet.Status);
rgMethods.Remove (mmSet);
property.SetMethod = mmSet;
}
}
else
{
// TODO: handle the mistmatch case.
Console.WriteLine ("FIXME: unhandled property mismatch.");
}
}
// sort out the events
foreach (MissingEvent evt in rgEvents)
{
MemberInfo infoBest = evt.BestInfo;
if (infoBest is EventInfo)
{
EventInfo ei = (EventInfo) evt.BestInfo;
MethodInfo miGet = ei.GetAddMethod ();
MethodInfo miSet = ei.GetRemoveMethod ();
MethodInfo miRaise = ei.GetRaiseMethod ();
MissingMethod mmGet = FindMethod (miGet);
MissingMethod mmSet = FindMethod (miSet);
MissingMethod mmRaise = FindMethod (miRaise);
if (mmGet != null)
{
nsMethods.SubChildren (mmGet.Status);
rgMethods.Remove (mmGet);
evt.GetMethod = mmGet;
}
if (mmSet != null)
{
nsMethods.SubChildren (mmSet.Status);
rgMethods.Remove (mmSet);
evt.SetMethod = mmSet;
}
if (mmRaise != null)
{
nsMethods.SubChildren (mmRaise.Status);
rgMethods.Remove (mmRaise);
evt.RaiseMethod = mmRaise;
}
}
else
{
// TODO: handle the mistmatch case.
Console.WriteLine ("FIXME: unhandled event mismatch.");
}
}
// 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");
}
// 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;
}
MissingMethod FindMethod (MethodInfo mi)
{
if (mi != null)
{
string strName = mi.Name;
foreach (MissingMethod method in rgMethods)
{
if (strName == method.BestInfo.Name)
return method;
}
}
return null;
}
static bool IsVisible (MemberInfo mi)
{
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;
case MemberTypes.Event:
case MemberTypes.Property:
return true;
default:
throw new Exception ("Missing handler for MemberType: "+mi.MemberType.ToString ());
}
}
}
}