1 // Mono.Util.CorCompare.MissingType
4 // Nick Drochak (ndrochak@gol.com)
6 // (C) 2001-2002 Nick Drochak
10 using System.Reflection;
11 using System.Collections;
13 namespace Mono.Util.CorCompare
17 /// Represents a class method that missing.
21 /// created on - 2/20/2002 10:43:57 PM
23 class MissingType : MissingBase
25 // e.g. <class name="System.Byte" status="missing"/>
26 // e.g. <class name="System.Array" status="todo" missing="5" todo="6" complete="45">
27 Type typeMono, typeMS;
28 // ArrayList rgAttributes = new ArrayList ();
29 ArrayList rgMethods = new ArrayList ();
30 ArrayList rgProperties = new ArrayList ();
31 ArrayList rgEvents = new ArrayList ();
32 ArrayList rgFields = new ArrayList ();
33 ArrayList rgConstructors = new ArrayList ();
34 ArrayList rgNestedTypes = new ArrayList ();
35 ArrayList rgInterfaces = new ArrayList ();
36 // NodeStatus nsAttributes = new NodeStatus ();
37 NodeStatus nsMethods = new NodeStatus ();
38 NodeStatus nsProperties = new NodeStatus ();
39 NodeStatus nsEvents = new NodeStatus ();
40 NodeStatus nsFields = new NodeStatus ();
41 NodeStatus nsConstructors = new NodeStatus ();
42 NodeStatus nsNestedTypes = new NodeStatus ();
43 NodeStatus nsInterfaces = new NodeStatus ();
45 public MissingType (Type _typeMono, Type _typeMS)
49 m_nodeStatus = new NodeStatus (_typeMono, _typeMS);
52 public override string Name
54 get { return TypeInfoBest.Name; }
57 public override string Type
64 else if (type.IsInterface)
66 else if (type.IsValueType)
77 get { return (typeMono != null) ? typeMono : typeMS; }
80 public Type TypeInfoBest
82 get { return (typeMS == null) ? typeMono : typeMS; }
85 public bool IsDelegate
89 Type typeBest = TypeInfoBest;
90 if (typeBest.IsEnum || typeBest.IsInterface || typeBest.IsValueType)
92 Type type = typeBest.BaseType;
95 if (type.FullName == "System.Delegate")
103 public MissingMember CreateMember (MemberInfo infoMono, MemberInfo infoMS)
105 MemberTypes mt = (infoMono != null) ? infoMono.MemberType : infoMS.MemberType;
109 case MemberTypes.Method:
110 mm = new MissingMethod (infoMono, infoMS);
112 case MemberTypes.Property:
113 mm = new MissingProperty (infoMono, infoMS);
115 case MemberTypes.Event:
116 mm = new MissingEvent (infoMono, infoMS);
118 case MemberTypes.Field:
119 mm = new MissingField (infoMono, infoMS);
121 case MemberTypes.Constructor:
122 mm = new MissingConstructor (infoMono, infoMS);
124 case MemberTypes.NestedType:
125 mm = new MissingNestedType (infoMono, infoMS);
128 throw new Exception ("Unexpected MemberType: " + mt.ToString());
135 public void AddMember (MissingMember mm)
137 switch (mm.Info.MemberType)
139 case MemberTypes.Method:
140 nsMethods.AddChildren (mm.Status);
143 case MemberTypes.Property:
144 nsProperties.AddChildren (mm.Status);
145 rgProperties.Add (mm);
147 case MemberTypes.Event:
148 nsEvents.AddChildren (mm.Status);
151 case MemberTypes.Field:
152 nsFields.AddChildren (mm.Status);
155 case MemberTypes.Constructor:
156 nsConstructors.AddChildren (mm.Status);
157 rgConstructors.Add (mm);
159 case MemberTypes.NestedType:
160 nsNestedTypes.AddChildren (mm.Status);
161 rgNestedTypes.Add (mm);
164 throw new Exception ("Unexpected MemberType: " + mm.Info.ToString());
168 public void AddMember (MemberInfo infoMono, MemberInfo infoMS)
170 AddMember (CreateMember (infoMono, infoMS));
173 public override XmlElement CreateXML (XmlDocument doc)
175 XmlElement eltClass = base.CreateXML (doc);
176 XmlElement eltMember;
178 eltMember = MissingBase.CreateMemberCollectionElement ("methods", rgMethods, nsMethods, doc);
179 if (eltMember != null)
180 eltClass.AppendChild (eltMember);
182 eltMember = MissingBase.CreateMemberCollectionElement ("properties", rgProperties, nsProperties, doc);
183 if (eltMember != null)
184 eltClass.AppendChild (eltMember);
186 eltMember = MissingBase.CreateMemberCollectionElement ("events", rgEvents, nsEvents, doc);
187 if (eltMember != null)
188 eltClass.AppendChild (eltMember);
190 eltMember = MissingBase.CreateMemberCollectionElement ("fields", rgFields, nsFields, doc);
191 if (eltMember != null)
192 eltClass.AppendChild (eltMember);
194 eltMember = MissingBase.CreateMemberCollectionElement ("constructors", rgConstructors, nsConstructors, doc);
195 if (eltMember != null)
196 eltClass.AppendChild (eltMember);
198 eltMember = MissingBase.CreateMemberCollectionElement ("nestedTypes", rgNestedTypes, nsNestedTypes, doc);
199 if (eltMember != null)
200 eltClass.AppendChild (eltMember);
202 eltMember = MissingBase.CreateMemberCollectionElement ("interfaces", rgInterfaces, nsInterfaces, doc);
203 if (eltMember != null)
204 eltClass.AppendChild (eltMember);
209 public override NodeStatus Analyze ()
211 Hashtable htMono = new Hashtable ();
212 if (typeMono != null)
214 ArrayList rgIgnoreMono = new ArrayList ();
215 foreach (MemberInfo miMono in typeMono.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
217 if (typeMono == miMono.DeclaringType)
219 string strName = MissingMember.GetUniqueName (miMono);
220 htMono.Add (strName, miMono);
222 // ignore any property/event accessors
223 if (miMono.MemberType == MemberTypes.Property)
225 PropertyInfo pi = (PropertyInfo) miMono;
226 MemberInfo miGet = pi.GetGetMethod ();
228 rgIgnoreMono.Add (miGet);
229 MemberInfo miSet = pi.GetSetMethod ();
231 rgIgnoreMono.Add (miSet);
233 else if (miMono.MemberType == MemberTypes.Event)
235 EventInfo ei = (EventInfo) miMono;
236 MemberInfo miAdd = ei.GetAddMethod ();
238 rgIgnoreMono.Add (miAdd);
239 MemberInfo miRemove = ei.GetRemoveMethod ();
240 if (miRemove != null)
241 rgIgnoreMono.Add (miRemove);
242 MemberInfo miRaise = ei.GetRaiseMethod ();
244 rgIgnoreMono.Add (miRaise);
248 foreach (MemberInfo miIgnore in rgIgnoreMono)
249 htMono.Remove (MissingMember.GetUniqueName (miIgnore));
251 Hashtable htMethodsMS = new Hashtable ();
254 ICollection colMembersMS = typeMS.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
255 Hashtable htIgnoreMS = new Hashtable ();
256 foreach (MemberInfo miMS in colMembersMS)
258 // ignore any property/event accessors
259 if (miMS.MemberType == MemberTypes.Property)
261 PropertyInfo pi = (PropertyInfo) miMS;
262 MemberInfo miGet = pi.GetGetMethod ();
264 htIgnoreMS.Add (miGet, miMS);
265 MemberInfo miSet = pi.GetSetMethod ();
267 htIgnoreMS.Add (miSet, miMS);
269 else if (miMS.MemberType == MemberTypes.Event)
271 EventInfo ei = (EventInfo) miMS;
272 MemberInfo miAdd = ei.GetAddMethod ();
274 htIgnoreMS.Add (miAdd, miMS);
275 MemberInfo miRemove = ei.GetRemoveMethod ();
276 if (miRemove != null)
277 htIgnoreMS.Add (miRemove, miMS);
278 MemberInfo miRaise = ei.GetRaiseMethod ();
280 htIgnoreMS.Add (miRaise, miMS);
283 foreach (MemberInfo miMS in colMembersMS)
285 if (miMS != null && miMS.DeclaringType == typeMS && !htIgnoreMS.Contains (miMS))
287 string strNameUnique = MissingMember.GetUniqueName (miMS);
288 MemberInfo miMono = (MemberInfo) htMono [strNameUnique];
290 MissingMember mm = CreateMember (miMono, miMS);
292 bool fVisibleMS = IsVisible (miMS);
300 bool fVisibleMono = IsVisible (miMono);
303 if (fVisibleMS != fVisibleMono)
306 mm.Status.AddWarning ("Should be visible");
308 mm.Status.AddWarning ("Should be hidden");
312 if (miMono.MemberType != miMS.MemberType)
314 //AddMember (null, miMS);
315 //MissingMember mm2 = CreateMember (miMono, null);
316 //mm2.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']");
318 mm.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']");
321 else if (fVisibleMS || fVisibleMono)
326 htMono.Remove (strNameUnique);
329 switch (miMS.MemberType)
331 case MemberTypes.Method:
333 string strNameMSFull = miMS.ToString ();
334 int ichMS = strNameMSFull.IndexOf (' ');
335 string strNameMS = strNameMSFull.Substring (ichMS + 1);
336 if (!htMethodsMS.Contains (strNameMS))
337 htMethodsMS.Add (strNameMSFull.Substring (ichMS + 1), miMS);
344 foreach (MemberInfo miMono in htMono.Values)
346 if (IsVisible (miMono))
348 MissingMember mm = CreateMember (miMono, null);
349 switch (miMono.MemberType)
351 case MemberTypes.Method:
353 string strNameMonoFull = miMono.ToString ();
354 int ichMono = strNameMonoFull.IndexOf (' ');
355 string strNameMono = strNameMonoFull.Substring (ichMono + 1);
356 MemberInfo miMS = (MemberInfo) htMethodsMS [strNameMono];
359 string strNameMSFull = miMS.ToString ();
360 int ichMS = strNameMSFull.IndexOf (' ');
361 string strReturnTypeMS = strNameMSFull.Substring (0, ichMS);
362 string strReturnTypeMono = strNameMonoFull.Substring (0, ichMono);
363 mm.Status.AddWarning ("Return type mismatch, is: '"+strReturnTypeMono+"' [should be: '"+strReturnTypeMS+"']");
364 //Console.WriteLine ("WARNING: Return type mismatch on "+miMS.DeclaringType.FullName+"."+strNameMono+", is: '"+strReturnTypeMono+"' [should be: '"+strReturnTypeMS+"']");
373 // compare the attributes
374 rgAttributes = new ArrayList ();
375 nsAttributes = MissingAttribute.AnalyzeAttributes (
376 (typeMono == null) ? null : typeMono.GetCustomAttributes (false),
377 ( typeMS == null) ? null : typeMS.GetCustomAttributes (false),
380 rgInterfaces = new ArrayList ();
381 if (typeMono != null && typeMS != null)
383 // compare base types
384 string strBaseMono = (typeMono.BaseType == null) ? null : typeMono.BaseType.FullName;
385 string strBaseMS = ( typeMS.BaseType == null) ? null : typeMS.BaseType.FullName;
386 if (strBaseMono != strBaseMS)
388 m_nodeStatus.AddWarning ("Base class mismatch, is '"+strBaseMono+"' [should be: '"+strBaseMS+"']");
389 //Console.WriteLine ("WARNING: Base class mismatch on "+typeMono.FullName+", is: '"+strBaseMono+"' [should be: '"+strBaseMS+"']");
392 // compare the interfaces
393 Hashtable htInterfacesMono = new Hashtable ();
394 Type [] rgInterfacesMono = typeMono.GetInterfaces ();
395 foreach (Type ifaceMono in rgInterfacesMono)
397 if (ifaceMono != null)
399 string strName = ifaceMono.FullName;
400 htInterfacesMono.Add (strName, ifaceMono);
403 Type [] rgInterfacesMS = typeMS.GetInterfaces ();
404 foreach (Type ifaceMS in rgInterfacesMS)
408 string strName = ifaceMS.FullName;
409 Type ifaceMono = (Type) htInterfacesMono [strName];
410 MissingInterface mi = new MissingInterface (ifaceMono, ifaceMS);
412 rgInterfaces.Add (mi);
413 if (ifaceMono != null)
414 htInterfacesMono.Remove (strName);
415 nsInterfaces.AddChildren (mi.Status);
418 foreach (Type ifaceMono in htInterfacesMono.Values)
420 MissingInterface mi = new MissingInterface (ifaceMono, null);
422 rgInterfaces.Add (mi);
423 //Console.WriteLine ("WARNING: additional interface on "+typeMono.FullName+": '"+ifaceMono.FullName+"'");
424 nsInterfaces.AddChildren (mi.Status);
427 // serializable attribute
428 AddFakeAttribute (typeMono.IsSerializable, typeMS.IsSerializable, "System.SerializableAttribute");
429 AddFakeAttribute (typeMono.IsAutoLayout, typeMS.IsAutoLayout, "System.AutoLayoutAttribute");
430 AddFakeAttribute (typeMono.IsExplicitLayout, typeMS.IsExplicitLayout, "System.ExplicitLayoutAttribute");
431 AddFakeAttribute (typeMono.IsLayoutSequential, typeMS.IsLayoutSequential, "System.SequentialLayoutAttribute");
433 Accessibility accessibilityMono = GetAccessibility (typeMono);
434 Accessibility accessibilityMS = GetAccessibility (typeMS);
435 if (accessibilityMono != accessibilityMS)
436 m_nodeStatus.AddWarning ("Should be "+AccessibilityToString (accessibilityMono));
438 AddFlagWarning (typeMono.IsSealed, typeMS.IsSealed, "sealed");
439 AddFlagWarning (typeMono.IsAbstract, typeMS.IsAbstract, "abstract");
442 // sum up the sub-sections
443 m_nodeStatus.Add (nsAttributes);
444 m_nodeStatus.Add (nsMethods);
445 m_nodeStatus.Add (nsProperties);
446 m_nodeStatus.Add (nsEvents);
447 m_nodeStatus.Add (nsFields);
448 m_nodeStatus.Add (nsConstructors);
449 m_nodeStatus.Add (nsNestedTypes);
450 m_nodeStatus.Add (nsInterfaces);
455 MissingMethod FindMethod (MethodInfo mi)
459 string strName = mi.Name;
460 foreach (MissingMethod method in rgMethods)
462 if (strName == method.BestInfo.Name)
469 static bool IsVisible (MemberInfo mi)
471 // this is just embarrasing, couldn't they have virtualized this?
472 switch (mi.MemberType)
474 case MemberTypes.Constructor:
475 case MemberTypes.Method:
476 return !((MethodBase) mi).IsPrivate && !((MethodBase) mi).IsFamilyAndAssembly && !((MethodBase) mi).IsAssembly;
477 case MemberTypes.Field:
478 return !((FieldInfo) mi).IsPrivate && !((FieldInfo) mi).IsFamilyAndAssembly && !((FieldInfo) mi).IsAssembly;
479 case MemberTypes.NestedType:
480 return !((Type) mi).IsNestedPrivate;
481 case MemberTypes.Property: // great, now we have to look at the methods
482 PropertyInfo pi = (PropertyInfo) mi;
483 MethodInfo miAccessor = pi.GetGetMethod ();
484 if (miAccessor == null)
485 miAccessor = pi.GetSetMethod ();
486 if (miAccessor == null)
488 return IsVisible (miAccessor);
489 case MemberTypes.Event: // ditto
490 EventInfo ei = (EventInfo) mi;
491 MethodInfo eiAccessor = ei.GetAddMethod ();
492 if (eiAccessor == null)
493 eiAccessor = ei.GetRemoveMethod ();
494 if (eiAccessor == null)
495 eiAccessor = ei.GetRaiseMethod ();
496 if (eiAccessor == null)
498 return IsVisible (eiAccessor);
500 throw new Exception ("Missing handler for MemberType: "+mi.MemberType.ToString ());
504 static Accessibility GetAccessibility (Type type)
507 return Accessibility.Public;
508 else if (type.IsNotPublic)
509 return Accessibility.Private;
510 return MissingMember.GetAccessibility (type);