[mono-api-info] Add an is-override attribute to determine if a method is overriding...
authorRolf Bjarne Kvinge <rolf@xamarin.com>
Thu, 28 Jan 2016 12:13:25 +0000 (13:13 +0100)
committerRolf Bjarne Kvinge <rolf@xamarin.com>
Thu, 28 Jan 2016 14:32:52 +0000 (15:32 +0100)
mcs/tools/corcompare/Util.cs
mcs/tools/corcompare/mono-api-info.cs

index 782280535ddabeb45e580c696de2856c46866d13..fa643ed20f825ae59d74f69e96dc55358e52c089 100644 (file)
@@ -83,5 +83,112 @@ namespace CorCompare {
                {
                        return att.AttributeType.Resolve ();
                }
+
+               static bool IsOverride (MethodDefinition method)
+               {
+                       return method.IsVirtual && !method.IsNewSlot;
+               }
+
+               public static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
+               {
+                       if (!IsOverride (method))
+                               return method;
+
+                       var @base = GetBaseType (method.DeclaringType);
+                       while (@base != null) {
+                               MethodDefinition base_method = TryMatchMethod (@base.Resolve (), method);
+                               if (base_method != null)
+                                       return GetBaseMethodInTypeHierarchy (base_method) ?? base_method;
+
+                               @base = GetBaseType (@base);
+                       }
+
+                       return method;
+               }
+
+               static MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method)
+               {
+                       if (!type.HasMethods)
+                               return null;
+
+                       foreach (MethodDefinition candidate in type.Methods)
+                               if (MethodMatch (candidate, method))
+                                       return candidate;
+
+                       return null;
+               }
+
+               static bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
+               {
+                       if (!candidate.IsVirtual)
+                               return false;
+
+                       if (candidate.Name != method.Name)
+                               return false;
+
+                       if (!TypeMatch (candidate.ReturnType, method.ReturnType))
+                               return false;
+
+                       if (candidate.Parameters.Count != method.Parameters.Count)
+                               return false;
+
+                       for (int i = 0; i < candidate.Parameters.Count; i++)
+                               if (!TypeMatch (candidate.Parameters [i].ParameterType, method.Parameters [i].ParameterType))
+                                       return false;
+
+                       return true;
+               }
+
+               public static bool TypeMatch (IModifierType a, IModifierType b)
+               {
+                       if (!TypeMatch (a.ModifierType, b.ModifierType))
+                               return false;
+
+                       return TypeMatch (a.ElementType, b.ElementType);
+               }
+
+               public static bool TypeMatch (TypeSpecification a, TypeSpecification b)
+               {
+                       if (a is GenericInstanceType)
+                               return TypeMatch ((GenericInstanceType) a, (GenericInstanceType) b);
+
+                       if (a is IModifierType)
+                               return TypeMatch ((IModifierType) a, (IModifierType) b);
+
+                       return TypeMatch (a.ElementType, b.ElementType);
+               }
+
+               public static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
+               {
+                       if (!TypeMatch (a.ElementType, b.ElementType))
+                               return false;
+
+                       if (a.GenericArguments.Count != b.GenericArguments.Count)
+                               return false;
+
+                       if (a.GenericArguments.Count == 0)
+                               return true;
+
+                       for (int i = 0; i < a.GenericArguments.Count; i++)
+                               if (!TypeMatch (a.GenericArguments [i], b.GenericArguments [i]))
+                                       return false;
+
+                       return true;
+               }
+
+               public static bool TypeMatch (TypeReference a, TypeReference b)
+               {
+                       if (a is GenericParameter)
+                               return true;
+
+                       if (a is TypeSpecification || b is TypeSpecification) {
+                               if (a.GetType () != b.GetType ())
+                                       return false;
+
+                               return TypeMatch ((TypeSpecification) a, (TypeSpecification) b);
+                       }
+
+                       return a.FullName == b.FullName;
+               }
        }
 }
index f9189a2ce80bf193d39b3e676fcf64028db18330..8b1ad945095c64d208ea0ce2d8626209b6c68709 100644 (file)
@@ -1010,6 +1010,15 @@ namespace CorCompare
                                AddAttribute ("sealed", "true");
                        if (mbase.IsStatic)
                                AddAttribute ("static", "true");
+                       var baseMethod = TypeHelper.GetBaseMethodInTypeHierarchy (mbase);
+                       if (baseMethod != null && baseMethod != mbase) {
+                               // This indicates whether this method is an override of another method.
+                               // This information is not necessarily available in the api info for any
+                               // particular assembly, because a method is only overriding another if
+                               // there is a base virtual function with the same signature, and that
+                               // base method can come from another assembly.
+                               AddAttribute ("is-override", "true");
+                       }
                        string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
                        if (rettype != "System.Void" || !mbase.IsConstructor)
                                AddAttribute ("returntype", (rettype));