2005-11-08 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / tools / corcompare / MissingType.cs
1 // Mono.Util.CorCompare.MissingType
2 //
3 // Author(s):
4 //   Nick Drochak (ndrochak@gol.com)
5 //
6 // (C) 2001-2002 Nick Drochak
7
8 using System;
9 using System.Xml;
10 using System.Reflection;
11 using System.Collections;
12
13 namespace Mono.Util.CorCompare 
14 {
15
16         /// <summary>
17         ///     Represents a class method that missing.
18         /// </summary>
19         /// <remarks>
20         ///     created by - Nick
21         ///     created on - 2/20/2002 10:43:57 PM
22         /// </remarks>
23         class MissingType : MissingBase
24         {
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 ();
44
45                 public MissingType (Type _typeMono, Type _typeMS)
46                 {
47                         typeMono = _typeMono;
48                         typeMS = _typeMS;
49                         m_nodeStatus = new NodeStatus (_typeMono, _typeMS);
50                 }
51
52                 public override string Name 
53                 {
54                         get
55                         {
56                                 Type type = TypeInfoBest;
57                                 if (type.DeclaringType != null)
58                                         return type.DeclaringType.Name + "+" + type.Name;
59                                 return type.Name;
60                         }
61                 }
62
63                 public override string Type
64                 {
65                         get
66                         {
67                                 Type type = TypeInfo;
68                                 if (type.IsEnum)
69                                         return "enum";
70                                 else if (type.IsInterface)
71                                         return "interface";
72                                 else if (type.IsValueType)
73                                         return "struct";
74                                 else if (IsDelegate)
75                                         return "delegate";
76                                 else
77                                         return "class";
78                         }
79                 }
80
81                 public Type TypeInfo
82                 {
83                         get { return (typeMono != null) ? typeMono : typeMS; }
84                 }
85
86                 public Type TypeInfoBest
87                 {
88                         get { return (typeMS == null) ? typeMono : typeMS; }
89                 }
90
91                 public bool IsDelegate
92                 {
93                         get
94                         {
95                                 Type typeBest = TypeInfoBest;
96                                 if (typeBest.IsEnum || typeBest.IsInterface || typeBest.IsValueType)
97                                         return false;
98                                 Type type = typeBest.BaseType;
99                                 while (type != null)
100                                 {
101                                         if (type.FullName == "System.Delegate")
102                                                 return true;
103                                         type = type.BaseType;
104                                 }
105                                 return false;
106                         }
107                 }
108
109                 public MissingMember CreateMember (MemberInfo infoMono, MemberInfo infoMS)
110                 {
111                         MemberTypes mt = (infoMono != null) ? infoMono.MemberType : infoMS.MemberType;
112                         MissingMember mm;
113                         switch (mt)
114                         {
115                                 case MemberTypes.Method:
116                                         mm = new MissingMethod (infoMono, infoMS);
117                                         break;
118                                 case MemberTypes.Property:
119                                         mm = new MissingProperty (infoMono, infoMS);
120                                         break;
121                                 case MemberTypes.Event:
122                                         mm = new MissingEvent (infoMono, infoMS);
123                                         break;
124                                 case MemberTypes.Field:
125                                         mm = new MissingField (infoMono, infoMS);
126                                         break;
127                                 case MemberTypes.Constructor:
128                                         mm = new MissingConstructor (infoMono, infoMS);
129                                         break;
130                                 case MemberTypes.NestedType:
131                                         mm = new MissingNestedType (infoMono, infoMS);
132                                         break;
133                                 default:
134                                         throw new Exception ("Unexpected MemberType: " + mt.ToString());
135                         }
136                         mm.Analyze ();
137                         return mm;
138                 }
139
140
141                 public void AddMember (MissingMember mm)
142                 {
143                         switch (mm.Info.MemberType)
144                         {
145                                 case MemberTypes.Method:
146                                         nsMethods.AddChildren (mm.Status);
147                                         rgMethods.Add (mm);
148                                         break;
149                                 case MemberTypes.Property:
150                                         nsProperties.AddChildren (mm.Status);
151                                         rgProperties.Add (mm);
152                                         break;
153                                 case MemberTypes.Event:
154                                         nsEvents.AddChildren (mm.Status);
155                                         rgEvents.Add (mm);
156                                         break;
157                                 case MemberTypes.Field:
158                                         nsFields.AddChildren (mm.Status);
159                                         rgFields.Add (mm);
160                                         break;
161                                 case MemberTypes.Constructor:
162                                         nsConstructors.AddChildren (mm.Status);
163                                         rgConstructors.Add (mm);
164                                         break;
165                                 case MemberTypes.NestedType:
166                                         nsNestedTypes.AddChildren (mm.Status);
167                                         rgNestedTypes.Add (mm);
168                                         break;
169                                 default:
170                                         throw new Exception ("Unexpected MemberType: " + mm.Info.ToString());
171                         }
172                 }
173
174                 public void AddMember (MemberInfo infoMono, MemberInfo infoMS)
175                 {
176                         AddMember (CreateMember (infoMono, infoMS));
177                 }
178
179                 public override XmlElement CreateXML (XmlDocument doc)
180                 {
181                         XmlElement eltClass = base.CreateXML (doc);
182                         XmlElement eltMember;
183
184                         eltMember = MissingBase.CreateMemberCollectionElement ("methods", rgMethods, nsMethods, doc);
185                         if (eltMember != null) 
186                                 eltClass.AppendChild (eltMember);
187
188                         eltMember = MissingBase.CreateMemberCollectionElement ("properties", rgProperties, nsProperties, doc);
189                         if (eltMember != null) 
190                                 eltClass.AppendChild (eltMember);
191
192                         eltMember = MissingBase.CreateMemberCollectionElement ("events", rgEvents, nsEvents, doc);
193                         if (eltMember != null) 
194                                 eltClass.AppendChild (eltMember);
195
196                         eltMember = MissingBase.CreateMemberCollectionElement ("fields", rgFields, nsFields, doc);
197                         if (eltMember != null) 
198                                 eltClass.AppendChild (eltMember);
199
200                         eltMember = MissingBase.CreateMemberCollectionElement ("constructors", rgConstructors, nsConstructors, doc);
201                         if (eltMember != null) 
202                                 eltClass.AppendChild (eltMember);
203
204                         eltMember = MissingBase.CreateMemberCollectionElement ("nestedTypes", rgNestedTypes, nsNestedTypes, doc);
205                         if (eltMember != null) 
206                                 eltClass.AppendChild (eltMember);
207
208                         eltMember = MissingBase.CreateMemberCollectionElement ("interfaces", rgInterfaces, nsInterfaces, doc);
209                         if (eltMember != null) 
210                                 eltClass.AppendChild (eltMember);
211
212                         return eltClass;
213                 }
214
215                 public override NodeStatus Analyze ()
216                 {
217                         Hashtable htMono = new Hashtable ();
218                         if (typeMono != null)
219                         {
220                                 ArrayList rgIgnoreMono = new ArrayList ();
221                                 foreach (MemberInfo miMono in typeMono.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
222                                 {
223                                         if (typeMono == miMono.DeclaringType)
224                                         {
225                                                 string strName = MissingMember.GetUniqueName (miMono);
226                                                 htMono.Add (strName, miMono);
227
228                                                 // ignore any property/event accessors
229                                                 if (miMono.MemberType == MemberTypes.Property)
230                                                 {
231                                                         PropertyInfo pi = (PropertyInfo) miMono;
232                                                         MemberInfo miGet = pi.GetGetMethod ();
233                                                         if (miGet != null)
234                                                                 rgIgnoreMono.Add (miGet);
235                                                         MemberInfo miSet = pi.GetSetMethod ();
236                                                         if (miSet != null)
237                                                                 rgIgnoreMono.Add (miSet);
238                                                 }
239                                                 else if (miMono.MemberType == MemberTypes.Event)
240                                                 {
241                                                         EventInfo ei = (EventInfo) miMono;
242                                                         MemberInfo miAdd = ei.GetAddMethod ();
243                                                         if (miAdd != null)
244                                                                 rgIgnoreMono.Add (miAdd);
245                                                         MemberInfo miRemove = ei.GetRemoveMethod ();
246                                                         if (miRemove != null)
247                                                                 rgIgnoreMono.Add (miRemove);
248                                                         MemberInfo miRaise = ei.GetRaiseMethod ();
249                                                         if (miRaise != null)
250                                                                 rgIgnoreMono.Add (miRaise);
251                                                 }
252                                         }
253                                 }
254                                 foreach (MemberInfo miIgnore in rgIgnoreMono)
255                                         htMono.Remove (MissingMember.GetUniqueName (miIgnore));
256                         }
257                         Hashtable htMethodsMS = new Hashtable ();
258                         if (typeMS != null)
259                         {
260                                 ICollection colMembersMS = typeMS.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
261                                 Hashtable htIgnoreMS = new Hashtable ();
262                                 foreach (MemberInfo miMS in colMembersMS)
263                                 {
264                                         // ignore any property/event accessors
265                                         if (miMS.MemberType == MemberTypes.Property)
266                                         {
267                                                 PropertyInfo pi = (PropertyInfo) miMS;
268                                                 MemberInfo miGet = pi.GetGetMethod ();
269                                                 if (miGet != null)
270                                                         htIgnoreMS.Add (miGet, miMS);
271                                                 MemberInfo miSet = pi.GetSetMethod ();
272                                                 if (miSet != null)
273                                                         htIgnoreMS.Add (miSet, miMS);
274                                         }
275                                         else if (miMS.MemberType == MemberTypes.Event)
276                                         {
277                                                 EventInfo ei = (EventInfo) miMS;
278                                                 MemberInfo miAdd = ei.GetAddMethod ();
279                                                 if (miAdd != null)
280                                                         htIgnoreMS.Add (miAdd, miMS);
281                                                 MemberInfo miRemove = ei.GetRemoveMethod ();
282                                                 if (miRemove != null)
283                                                         htIgnoreMS.Add (miRemove, miMS);
284                                                 MemberInfo miRaise = ei.GetRaiseMethod ();
285                                                 if (miRaise != null)
286                                                         htIgnoreMS.Add (miRaise, miMS);
287                                         }
288                                 }
289                                 foreach (MemberInfo miMS in colMembersMS)
290                                 {
291                                         if (miMS != null && miMS.DeclaringType == typeMS && !htIgnoreMS.Contains (miMS))
292                                         {
293                                                 string strNameUnique = MissingMember.GetUniqueName (miMS);
294                                                 MemberInfo miMono = (MemberInfo) htMono [strNameUnique];
295
296                                                 MissingMember mm = CreateMember (miMono, miMS);
297
298                                                 bool fVisibleMS = IsVisible (miMS);
299                                                 if (miMono == null)
300                                                 {
301                                                         if (fVisibleMS)
302                                                                 AddMember (mm);
303                                                 }
304                                                 else
305                                                 {
306                                                         if (miMono.MemberType != miMS.MemberType)
307                                                         {
308                                                                 //AddMember (null, miMS);
309                                                                 //MissingMember mm2 = CreateMember (miMono, null);
310                                                                 //mm2.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']");
311                                                                 //AddMember (mm2);
312                                                                 mm.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']");
313                                                                 AddMember (mm);
314                                                         }
315                                                         else if (fVisibleMS || IsVisible (miMono))
316                                                         {
317                                                                 AddMember (mm);
318                                                         }
319
320                                                         htMono.Remove (strNameUnique);
321                                                 }
322
323                                                 switch (miMS.MemberType)
324                                                 {
325                                                         case MemberTypes.Method:
326                                                         {
327                                                                 string strNameMSFull = miMS.ToString ();
328                                                                 int ichMS = strNameMSFull.IndexOf (' ');
329                                                                 string strNameMS = strNameMSFull.Substring (ichMS + 1);
330                                                                 if (!htMethodsMS.Contains (strNameMS))
331                                                                         htMethodsMS.Add (strNameMSFull.Substring (ichMS + 1), miMS);
332                                                                 break;
333                                                         }
334                                                 }
335                                         }
336                                 }
337                         }
338                         foreach (MemberInfo miMono in htMono.Values)
339                         {
340                                 if (IsVisible (miMono))
341                                 {
342                                         MissingMember mm = CreateMember (miMono, null);
343                                         switch (miMono.MemberType)
344                                         {
345                                                 case MemberTypes.Method:
346                                                 {
347                                                         string strNameMonoFull = miMono.ToString ();
348                                                         int ichMono = strNameMonoFull.IndexOf (' ');
349                                                         string strNameMono = strNameMonoFull.Substring (ichMono + 1);
350                                                         MemberInfo miMS = (MemberInfo) htMethodsMS [strNameMono];
351                                                         if (miMS != null)
352                                                         {
353                                                                 string strNameMSFull = miMS.ToString ();
354                                                                 int ichMS = strNameMSFull.IndexOf (' ');
355                                                                 string strReturnTypeMS = strNameMSFull.Substring (0, ichMS);
356                                                                 string strReturnTypeMono = strNameMonoFull.Substring (0, ichMono);
357                                                                 mm.Status.AddWarning ("Return type mismatch, is: '"+strReturnTypeMono+"' [should be: '"+strReturnTypeMS+"']");
358                                                                 //Console.WriteLine ("WARNING: Return type mismatch on "+miMS.DeclaringType.FullName+"."+strNameMono+", is: '"+strReturnTypeMono+"' [should be: '"+strReturnTypeMS+"']");
359                                                         }
360                                                         break;
361                                                 }
362                                         }
363                                         AddMember (mm);
364                                 }
365                         }
366
367                         // compare the attributes
368                         rgAttributes = new ArrayList ();
369                         nsAttributes = MissingAttribute.AnalyzeAttributes (
370                                 (typeMono == null) ? null : typeMono.GetCustomAttributes (false),
371                                 (  typeMS == null) ? null :   typeMS.GetCustomAttributes (false),
372                                 rgAttributes);
373
374                         rgInterfaces = new ArrayList ();
375                         if (typeMono != null && typeMS != null)
376                         {
377                                 // compare base types
378                                 string strBaseMono = (typeMono.BaseType == null) ? null : typeMono.BaseType.FullName;
379                                 string strBaseMS   = (  typeMS.BaseType == null) ? null :   typeMS.BaseType.FullName;
380                                 if (strBaseMono != strBaseMS)
381                                 {
382                                         m_nodeStatus.AddWarning ("Base class mismatch, is '"+strBaseMono+"' [should be: '"+strBaseMS+"']");
383                                         //Console.WriteLine ("WARNING: Base class mismatch on "+typeMono.FullName+", is: '"+strBaseMono+"' [should be: '"+strBaseMS+"']");
384                                 }
385
386                                 // compare the interfaces
387                                 Hashtable htInterfacesMono = new Hashtable ();
388                                 Type [] rgInterfacesMono = typeMono.GetInterfaces ();
389                                 foreach (Type ifaceMono in rgInterfacesMono)
390                                 {
391                                         if (ifaceMono != null)
392                                         {
393                                                 string strName = ifaceMono.FullName;
394                                                 htInterfacesMono.Add (strName, ifaceMono);
395                                         }
396                                 }
397                                 Type [] rgInterfacesMS = typeMS.GetInterfaces ();
398                                 foreach (Type ifaceMS in rgInterfacesMS)
399                                 {
400                                         if (ifaceMS != null)
401                                         {
402                                                 string strName = ifaceMS.FullName;
403                                                 Type ifaceMono = (Type) htInterfacesMono [strName];
404                                                 MissingInterface mi = new MissingInterface (ifaceMono, ifaceMS);
405                                                 mi.Analyze ();
406                                                 rgInterfaces.Add (mi);
407                                                 if (ifaceMono != null)
408                                                         htInterfacesMono.Remove (strName);
409                                                 nsInterfaces.AddChildren (mi.Status);
410                                         }
411                                 }
412                                 foreach (Type ifaceMono in htInterfacesMono.Values)
413                                 {
414                                         MissingInterface mi = new MissingInterface (ifaceMono, null);
415                                         mi.Analyze ();
416                                         rgInterfaces.Add (mi);
417                                         //Console.WriteLine ("WARNING: additional interface on "+typeMono.FullName+": '"+ifaceMono.FullName+"'");
418                                         nsInterfaces.AddChildren (mi.Status);
419                                 }
420
421                                 // serializable attribute
422                                 // AddFakeAttribute (typeMono.IsSerializable, typeMS.IsSerializable, "System.SerializableAttribute");
423                                 AddFakeAttribute (typeMono.IsAutoLayout, typeMS.IsAutoLayout, "System.AutoLayoutAttribute");
424                                 AddFakeAttribute (typeMono.IsExplicitLayout, typeMS.IsExplicitLayout, "System.ExplicitLayoutAttribute");
425                                 AddFakeAttribute (typeMono.IsLayoutSequential, typeMS.IsLayoutSequential, "System.SequentialLayoutAttribute");
426
427                                 Accessibility accessibilityMono = GetAccessibility (typeMono);
428                                 Accessibility accessibilityMS   = GetAccessibility (typeMS);
429                                 if (accessibilityMono != accessibilityMS)
430                                         m_nodeStatus.AddWarning ("Should be "+AccessibilityToString (accessibilityMono));
431
432                                 AddFlagWarning (typeMono.IsSealed, typeMS.IsSealed, "sealed");
433                                 AddFlagWarning (typeMono.IsAbstract, typeMS.IsAbstract, "abstract");
434                         }
435
436                         // sum up the sub-sections
437                         m_nodeStatus.Add (nsAttributes);
438                         m_nodeStatus.Add (nsMethods);
439                         m_nodeStatus.Add (nsProperties);
440                         m_nodeStatus.Add (nsEvents);
441                         m_nodeStatus.Add (nsFields);
442                         m_nodeStatus.Add (nsConstructors);
443                         m_nodeStatus.Add (nsNestedTypes);
444                         m_nodeStatus.Add (nsInterfaces);
445
446                         return m_nodeStatus;
447                 }
448
449                 static bool IsVisible (MemberInfo mi)
450                 {
451                         // this is just embarrasing, couldn't they have virtualized this?
452                         switch (mi.MemberType)
453                         {
454                                 case MemberTypes.Constructor:
455                                 case MemberTypes.Method:
456                                         return !((MethodBase) mi).IsPrivate && !((MethodBase) mi).IsFamilyAndAssembly && !((MethodBase) mi).IsAssembly;
457                                 case MemberTypes.Field:
458                                         return !((FieldInfo) mi).IsPrivate && !((FieldInfo) mi).IsFamilyAndAssembly && !((FieldInfo) mi).IsAssembly;
459                                 case MemberTypes.NestedType:
460                                         return !((Type) mi).IsNestedPrivate && !((Type) mi).IsNestedAssembly && !((Type) mi).IsNestedFamANDAssem;
461                                 case MemberTypes.Property:      // great, now we have to look at the methods
462                                         PropertyInfo pi = (PropertyInfo) mi;
463                                         MethodInfo miAccessor = pi.GetGetMethod ();
464                                         if (miAccessor == null)
465                                                 miAccessor = pi.GetSetMethod ();
466                                         if (miAccessor == null)
467                                                 return false;
468                                         return IsVisible (miAccessor);
469                                 case MemberTypes.Event: // ditto
470                                         EventInfo ei = (EventInfo) mi;
471                                         MethodInfo eiAccessor = ei.GetAddMethod ();
472                                         if (eiAccessor == null)
473                                                 eiAccessor = ei.GetRemoveMethod ();
474                                         if (eiAccessor == null)
475                                                 eiAccessor = ei.GetRaiseMethod ();
476                                         if (eiAccessor == null)
477                                                 return false;
478                                         return IsVisible (eiAccessor);
479                                 default:
480                                         throw new Exception ("Missing handler for MemberType: "+mi.MemberType.ToString ());
481                         }
482                 }
483
484                 static Accessibility GetAccessibility (Type type)
485                 {
486                         if (type.IsPublic)
487                                 return Accessibility.Public;
488                         else if (type.IsNotPublic)
489                                 return Accessibility.Private;
490                         return MissingMember.GetAccessibility (type);
491                 }
492         }
493 }