/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using dnlib.DotNet; namespace dnSpy.Contracts.Decompiler { /// /// Member comparer base class /// /// public abstract class MemberRefComparer : IComparer where T : class, IMemberRef { /// /// Compares two instances /// /// First instance to compare /// Second instance to compare /// public int Compare([AllowNull] T x, [AllowNull] T y) { if ((object?)x == y) return 0; if (x is null) return -1; if (y is null) return 1; int c = StringComparer.OrdinalIgnoreCase.Compare(x.Name, y.Name); if (c != 0) return c; c = x.MDToken.Raw.CompareTo(y.MDToken.Raw); if (c != 0) return c; return x.GetHashCode().CompareTo(y.GetHashCode()); } } /// /// comparer /// public sealed class TypeDefComparer : MemberRefComparer { /// /// Gets the instance /// public static readonly TypeDefComparer Instance = new TypeDefComparer(); } /// /// comparer /// public sealed class MemberRefComparer : MemberRefComparer { /// /// Gets the instance /// public static readonly MemberRefComparer Instance = new MemberRefComparer(); } /// /// comparer /// public sealed class FieldDefComparer : MemberRefComparer { /// /// Gets the instance /// public static readonly FieldDefComparer Instance = new FieldDefComparer(); } /// /// comparer /// public sealed class EventDefComparer : MemberRefComparer { /// /// Gets the instance /// public static readonly EventDefComparer Instance = new EventDefComparer(); } /// /// comparer /// public sealed class PropertyDefComparer : MemberRefComparer { /// /// Gets the instance /// public static readonly PropertyDefComparer Instance = new PropertyDefComparer(); } /// /// comparer /// public sealed class MethodDefComparer : IComparer { /// /// Gets the instance /// public static readonly MethodDefComparer Instance = new MethodDefComparer(); /// /// Compares two instances /// /// First instance to compare /// Second instance to compare /// public int Compare([AllowNull] MethodDef x, [AllowNull] MethodDef y) => MethodRefComparer.Instance.Compare(x, y); } /// /// Method reference comparer /// public sealed class MethodRefComparer : IComparer { /// /// Gets the instance /// public static readonly MethodRefComparer Instance = new MethodRefComparer(); /// /// Compares two instances /// /// First instance to compare /// Second instance to compare /// public int Compare([AllowNull] IMethod x, [AllowNull] IMethod y) { if ((object?)x == y) return 0; if (x is null) return -1; if (y is null) return 1; int c = StringComparer.OrdinalIgnoreCase.Compare(x.Name, y.Name); if (c != 0) return c; return CompareNoName(x, y); } internal static int CompareNoName(IMethod x, IMethod y) { int c = x.MethodSig.GetParamCount().CompareTo(y.MethodSig.GetParamCount()); if (c != 0) return c; c = x.MethodSig.GetGenParamCount().CompareTo(y.MethodSig.GetGenParamCount()); if (c != 0) return c; c = x.MDToken.Raw.CompareTo(y.MDToken.Raw); if (c != 0) return c; return x.GetHashCode().CompareTo(y.GetHashCode()); } } /// /// Property reference comparer /// public sealed class PropertyRefComparer : IComparer { /// /// Gets the instance /// public static readonly PropertyRefComparer Instance = new PropertyRefComparer(); static int GetAccessor(string name, out string propName) { if (name.StartsWith("get_")) { propName = name.Substring(4); return 0; } if (name.StartsWith("set_")) { propName = name.Substring(4); return 1; } propName = name; return int.MaxValue; } /// /// Compares two instances /// /// First instance to compare /// Second instance to compare /// public int Compare([AllowNull] IMethod x, [AllowNull] IMethod y) { if ((object?)x == y) return 0; if (x is null) return -1; if (y is null) return 1; string xn = x.Name; string yn = y.Name; int xacc = GetAccessor(xn, out var xPropName); int yacc = GetAccessor(yn, out var yPropName); int c = StringComparer.OrdinalIgnoreCase.Compare(xPropName, yPropName); if (c != 0) return c; c = xacc - yacc; if (c != 0) return c; return MethodRefComparer.CompareNoName(x, y); } } /// /// Event reference comparer /// public sealed class EventRefComparer : IComparer { /// /// Gets the instance /// public static readonly EventRefComparer Instance = new EventRefComparer(); static int GetAccessor(string name, out string propName) { if (name.StartsWith("add_")) { propName = name.Substring(4); return 0; } if (name.StartsWith("remove_")) { propName = name.Substring(7); return 1; } if (name.StartsWith("raise_")) { propName = name.Substring(6); return 2; } propName = name; return int.MaxValue; } /// /// Compares two instances /// /// First instance to compare /// Second instance to compare /// public int Compare([AllowNull] IMethod x, [AllowNull] IMethod y) { if ((object?)x == y) return 0; if (x is null) return -1; if (y is null) return 1; string xn = x.Name; string yn = y.Name; int xacc = GetAccessor(xn, out var xPropName); int yacc = GetAccessor(yn, out var yPropName); int c = StringComparer.OrdinalIgnoreCase.Compare(xPropName, yPropName); if (c != 0) return c; c = xacc - yacc; if (c != 0) return c; return MethodRefComparer.CompareNoName(x, y); } } }