more errors/attributes
[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 { return TypeInfoBest.Name; }
55                 }
56
57                 public override string Type
58                 {
59                         get
60                         {
61                                 Type type = TypeInfo;
62                                 if (type.IsEnum)
63                                         return "enum";
64                                 else if (type.IsInterface)
65                                         return "interface";
66                                 else if (type.IsValueType)
67                                         return "struct";
68                                 else if (IsDelegate)
69                                         return "delegate";
70                                 else
71                                         return "class";
72                         }
73                 }
74
75                 public Type TypeInfo
76                 {
77                         get { return (typeMono != null) ? typeMono : typeMS; }
78                 }
79
80                 public Type TypeInfoBest
81                 {
82                         get { return (typeMS == null) ? typeMono : typeMS; }
83                 }
84
85                 public bool IsDelegate
86                 {
87                         get
88                         {
89                                 Type typeBest = TypeInfoBest;
90                                 if (typeBest.IsEnum || typeBest.IsInterface || typeBest.IsValueType)
91                                         return false;
92                                 Type type = typeBest.BaseType;
93                                 while (type != null)
94                                 {
95                                         if (type.FullName == "System.Delegate")
96                                                 return true;
97                                         type = type.BaseType;
98                                 }
99                                 return false;
100                         }
101                 }
102
103                 public MissingMember CreateMember (MemberInfo infoMono, MemberInfo infoMS)
104                 {
105                         MemberTypes mt = (infoMono != null) ? infoMono.MemberType : infoMS.MemberType;
106                         MissingMember mm;
107                         switch (mt)
108                         {
109                                 case MemberTypes.Method:
110                                         mm = new MissingMethod (infoMono, infoMS);
111                                         break;
112                                 case MemberTypes.Property:
113                                         mm = new MissingProperty (infoMono, infoMS);
114                                         break;
115                                 case MemberTypes.Event:
116                                         mm = new MissingEvent (infoMono, infoMS);
117                                         break;
118                                 case MemberTypes.Field:
119                                         mm = new MissingField (infoMono, infoMS);
120                                         break;
121                                 case MemberTypes.Constructor:
122                                         mm = new MissingConstructor (infoMono, infoMS);
123                                         break;
124                                 case MemberTypes.NestedType:
125                                         mm = new MissingNestedType (infoMono, infoMS);
126                                         break;
127                                 default:
128                                         throw new Exception ("Unexpected MemberType: " + mt.ToString());
129                         }
130                         mm.Analyze ();
131                         return mm;
132                 }
133
134
135                 public void AddMember (MissingMember mm)
136                 {
137                         switch (mm.Info.MemberType)
138                         {
139                                 case MemberTypes.Method:
140                                         nsMethods.AddChildren (mm.Status);
141                                         rgMethods.Add (mm);
142                                         break;
143                                 case MemberTypes.Property:
144                                         nsProperties.AddChildren (mm.Status);
145                                         rgProperties.Add (mm);
146                                         break;
147                                 case MemberTypes.Event:
148                                         nsEvents.AddChildren (mm.Status);
149                                         rgEvents.Add (mm);
150                                         break;
151                                 case MemberTypes.Field:
152                                         nsFields.AddChildren (mm.Status);
153                                         rgFields.Add (mm);
154                                         break;
155                                 case MemberTypes.Constructor:
156                                         nsConstructors.AddChildren (mm.Status);
157                                         rgConstructors.Add (mm);
158                                         break;
159                                 case MemberTypes.NestedType:
160                                         nsNestedTypes.AddChildren (mm.Status);
161                                         rgNestedTypes.Add (mm);
162                                         break;
163                                 default:
164                                         throw new Exception ("Unexpected MemberType: " + mm.Info.ToString());
165                         }
166                 }
167
168                 public void AddMember (MemberInfo infoMono, MemberInfo infoMS)
169                 {
170                         AddMember (CreateMember (infoMono, infoMS));
171                 }
172
173                 public override XmlElement CreateXML (XmlDocument doc)
174                 {
175                         XmlElement eltClass = base.CreateXML (doc);
176                         XmlElement eltMember;
177
178                         eltMember = MissingBase.CreateMemberCollectionElement ("methods", rgMethods, nsMethods, doc);
179                         if (eltMember != null) 
180                                 eltClass.AppendChild (eltMember);
181
182                         eltMember = MissingBase.CreateMemberCollectionElement ("properties", rgProperties, nsProperties, doc);
183                         if (eltMember != null) 
184                                 eltClass.AppendChild (eltMember);
185
186                         eltMember = MissingBase.CreateMemberCollectionElement ("events", rgEvents, nsEvents, doc);
187                         if (eltMember != null) 
188                                 eltClass.AppendChild (eltMember);
189
190                         eltMember = MissingBase.CreateMemberCollectionElement ("fields", rgFields, nsFields, doc);
191                         if (eltMember != null) 
192                                 eltClass.AppendChild (eltMember);
193
194                         eltMember = MissingBase.CreateMemberCollectionElement ("constructors", rgConstructors, nsConstructors, doc);
195                         if (eltMember != null) 
196                                 eltClass.AppendChild (eltMember);
197
198                         eltMember = MissingBase.CreateMemberCollectionElement ("nestedTypes", rgNestedTypes, nsNestedTypes, doc);
199                         if (eltMember != null) 
200                                 eltClass.AppendChild (eltMember);
201
202                         eltMember = MissingBase.CreateMemberCollectionElement ("interfaces", rgInterfaces, nsInterfaces, doc);
203                         if (eltMember != null) 
204                                 eltClass.AppendChild (eltMember);
205
206                         return eltClass;
207                 }
208
209                 public override NodeStatus Analyze ()
210                 {
211                         Hashtable htMono = new Hashtable ();
212                         if (typeMono != null)
213                         {
214                                 ArrayList rgIgnoreMono = new ArrayList ();
215                                 foreach (MemberInfo miMono in typeMono.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
216                                 {
217                                         if (typeMono == miMono.DeclaringType)
218                                         {
219                                                 string strName = MissingMember.GetUniqueName (miMono);
220                                                 htMono.Add (strName, miMono);
221
222                                                 // ignore any property/event accessors
223                                                 if (miMono.MemberType == MemberTypes.Property)
224                                                 {
225                                                         PropertyInfo pi = (PropertyInfo) miMono;
226                                                         MemberInfo miGet = pi.GetGetMethod ();
227                                                         if (miGet != null)
228                                                                 rgIgnoreMono.Add (miGet);
229                                                         MemberInfo miSet = pi.GetSetMethod ();
230                                                         if (miSet != null)
231                                                                 rgIgnoreMono.Add (miSet);
232                                                 }
233                                                 else if (miMono.MemberType == MemberTypes.Event)
234                                                 {
235                                                         EventInfo ei = (EventInfo) miMono;
236                                                         MemberInfo miAdd = ei.GetAddMethod ();
237                                                         if (miAdd != null)
238                                                                 rgIgnoreMono.Add (miAdd);
239                                                         MemberInfo miRemove = ei.GetRemoveMethod ();
240                                                         if (miRemove != null)
241                                                                 rgIgnoreMono.Add (miRemove);
242                                                         MemberInfo miRaise = ei.GetRaiseMethod ();
243                                                         if (miRaise != null)
244                                                                 rgIgnoreMono.Add (miRaise);
245                                                 }
246                                         }
247                                 }
248                                 foreach (MemberInfo miIgnore in rgIgnoreMono)
249                                         htMono.Remove (MissingMember.GetUniqueName (miIgnore));
250                         }
251                         Hashtable htMethodsMS = new Hashtable ();
252                         if (typeMS != null)
253                         {
254                                 ICollection colMembersMS = typeMS.GetMembers (BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
255                                 Hashtable htIgnoreMS = new Hashtable ();
256                                 foreach (MemberInfo miMS in colMembersMS)
257                                 {
258                                         // ignore any property/event accessors
259                                         if (miMS.MemberType == MemberTypes.Property)
260                                         {
261                                                 PropertyInfo pi = (PropertyInfo) miMS;
262                                                 MemberInfo miGet = pi.GetGetMethod ();
263                                                 if (miGet != null)
264                                                         htIgnoreMS.Add (miGet, miMS);
265                                                 MemberInfo miSet = pi.GetSetMethod ();
266                                                 if (miSet != null)
267                                                         htIgnoreMS.Add (miSet, miMS);
268                                         }
269                                         else if (miMS.MemberType == MemberTypes.Event)
270                                         {
271                                                 EventInfo ei = (EventInfo) miMS;
272                                                 MemberInfo miAdd = ei.GetAddMethod ();
273                                                 if (miAdd != null)
274                                                         htIgnoreMS.Add (miAdd, miMS);
275                                                 MemberInfo miRemove = ei.GetRemoveMethod ();
276                                                 if (miRemove != null)
277                                                         htIgnoreMS.Add (miRemove, miMS);
278                                                 MemberInfo miRaise = ei.GetRaiseMethod ();
279                                                 if (miRaise != null)
280                                                         htIgnoreMS.Add (miRaise, miMS);
281                                         }
282                                 }
283                                 foreach (MemberInfo miMS in colMembersMS)
284                                 {
285                                         if (miMS != null && miMS.DeclaringType == typeMS && !htIgnoreMS.Contains (miMS))
286                                         {
287                                                 string strNameUnique = MissingMember.GetUniqueName (miMS);
288                                                 MemberInfo miMono = (MemberInfo) htMono [strNameUnique];
289
290                                                 MissingMember mm = CreateMember (miMono, miMS);
291
292                                                 bool fVisibleMS = IsVisible (miMS);
293                                                 if (miMono == null)
294                                                 {
295                                                         if (fVisibleMS)
296                                                                 AddMember (mm);
297                                                 }
298                                                 else
299                                                 {
300                                                         bool fVisibleMono = IsVisible (miMono);
301
302                                         /*
303                                                         if (fVisibleMS != fVisibleMono)
304                                                         {
305                                                                 if (fVisibleMS)
306                                                                         mm.Status.AddWarning ("Should be visible");
307                                                                 else
308                                                                         mm.Status.AddWarning ("Should be hidden");
309                                                         }
310                                         */
311
312                                                         if (miMono.MemberType != miMS.MemberType)
313                                                         {
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 ()+"']");
317                                                                 //AddMember (mm2);
318                                                                 mm.Status.AddWarning ("MemberType mismatch, is: '" + miMono.MemberType.ToString () + "' [should be: '" + miMS.MemberType.ToString ()+"']");
319                                                                 AddMember (mm);
320                                                         }
321                                                         else if (fVisibleMS || fVisibleMono)
322                                                         {
323                                                                 AddMember (mm);
324                                                         }
325
326                                                         htMono.Remove (strNameUnique);
327                                                 }
328
329                                                 switch (miMS.MemberType)
330                                                 {
331                                                         case MemberTypes.Method:
332                                                         {
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);
338                                                                 break;
339                                                         }
340                                                 }
341                                         }
342                                 }
343                         }
344                         foreach (MemberInfo miMono in htMono.Values)
345                         {
346                                 if (IsVisible (miMono))
347                                 {
348                                         MissingMember mm = CreateMember (miMono, null);
349                                         switch (miMono.MemberType)
350                                         {
351                                                 case MemberTypes.Method:
352                                                 {
353                                                         string strNameMonoFull = miMono.ToString ();
354                                                         int ichMono = strNameMonoFull.IndexOf (' ');
355                                                         string strNameMono = strNameMonoFull.Substring (ichMono + 1);
356                                                         MemberInfo miMS = (MemberInfo) htMethodsMS [strNameMono];
357                                                         if (miMS != null)
358                                                         {
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+"']");
365                                                         }
366                                                         break;
367                                                 }
368                                         }
369                                         AddMember (mm);
370                                 }
371                         }
372
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),
378                                 rgAttributes);
379
380                         rgInterfaces = new ArrayList ();
381                         if (typeMono != null && typeMS != null)
382                         {
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)
387                                 {
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+"']");
390                                 }
391
392                                 // compare the interfaces
393                                 Hashtable htInterfacesMono = new Hashtable ();
394                                 Type [] rgInterfacesMono = typeMono.GetInterfaces ();
395                                 foreach (Type ifaceMono in rgInterfacesMono)
396                                 {
397                                         if (ifaceMono != null)
398                                         {
399                                                 string strName = ifaceMono.FullName;
400                                                 htInterfacesMono.Add (strName, ifaceMono);
401                                         }
402                                 }
403                                 Type [] rgInterfacesMS = typeMS.GetInterfaces ();
404                                 foreach (Type ifaceMS in rgInterfacesMS)
405                                 {
406                                         if (ifaceMS != null)
407                                         {
408                                                 string strName = ifaceMS.FullName;
409                                                 Type ifaceMono = (Type) htInterfacesMono [strName];
410                                                 MissingInterface mi = new MissingInterface (ifaceMono, ifaceMS);
411                                                 mi.Analyze ();
412                                                 rgInterfaces.Add (mi);
413                                                 if (ifaceMono != null)
414                                                         htInterfacesMono.Remove (strName);
415                                                 nsInterfaces.AddChildren (mi.Status);
416                                         }
417                                 }
418                                 foreach (Type ifaceMono in htInterfacesMono.Values)
419                                 {
420                                         MissingInterface mi = new MissingInterface (ifaceMono, null);
421                                         mi.Analyze ();
422                                         rgInterfaces.Add (mi);
423                                         //Console.WriteLine ("WARNING: additional interface on "+typeMono.FullName+": '"+ifaceMono.FullName+"'");
424                                         nsInterfaces.AddChildren (mi.Status);
425                                 }
426
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");
432
433                                 Accessibility accessibilityMono = GetAccessibility (typeMono);
434                                 Accessibility accessibilityMS   = GetAccessibility (typeMS);
435                                 if (accessibilityMono != accessibilityMS)
436                                         m_nodeStatus.AddWarning ("Should be "+AccessibilityToString (accessibilityMono));
437
438                                 AddFlagWarning (typeMono.IsSealed, typeMS.IsSealed, "sealed");
439                                 AddFlagWarning (typeMono.IsAbstract, typeMS.IsAbstract, "abstract");
440                         }
441
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);
451
452                         return m_nodeStatus;
453                 }
454
455                 MissingMethod FindMethod (MethodInfo mi)
456                 {
457                         if (mi != null)
458                         {
459                                 string strName = mi.Name;
460                                 foreach (MissingMethod method in rgMethods)
461                                 {
462                                         if (strName == method.BestInfo.Name)
463                                                 return method;
464                                 }
465                         }
466                         return null;
467                 }
468
469                 static bool IsVisible (MemberInfo mi)
470                 {
471                         // this is just embarrasing, couldn't they have virtualized this?
472                         switch (mi.MemberType)
473                         {
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)
487                                                 return false;
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)
497                                                 return false;
498                                         return IsVisible (eiAccessor);
499                                 default:
500                                         throw new Exception ("Missing handler for MemberType: "+mi.MemberType.ToString ());
501                         }
502                 }
503
504                 static Accessibility GetAccessibility (Type type)
505                 {
506                         if (type.IsPublic)
507                                 return Accessibility.Public;
508                         else if (type.IsNotPublic)
509                                 return Accessibility.Private;
510                         return MissingMember.GetAccessibility (type);
511                 }
512         }
513 }