Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

Commit

Permalink
Initial import of corcompare.
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfbjarne committed May 5, 2022
1 parent 84a7db4 commit 4516e13
Show file tree
Hide file tree
Showing 8 changed files with 2,961 additions and 0 deletions.
56 changes: 56 additions & 0 deletions corcompare/AssemblyResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// AssemblyResolver.cs
//
// Author:
// Jb Evain ([email protected])
//
// (C) 2007 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.IO;

using Mono.Cecil;

namespace Mono.ApiTools {

class AssemblyResolver : DefaultAssemblyResolver {

public AssemblyDefinition ResolveFile (string file)
{
AddSearchDirectory (Path.GetDirectoryName (file));
var assembly = AssemblyDefinition.ReadAssembly (file, new ReaderParameters { AssemblyResolver = this, InMemory = true });
RegisterAssembly (assembly);

return assembly;
}

public AssemblyDefinition ResolveStream (Stream stream)
{
var assembly = AssemblyDefinition.ReadAssembly (stream, new ReaderParameters { AssemblyResolver = this, InMemory = true });
RegisterAssembly (assembly);

return assembly;
}
}
}
10 changes: 10 additions & 0 deletions corcompare/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
thisdir = tools/corcompare
SUBDIRS =
include ../../build/rules.make

LIB_REFS = Mono.Cecil System.Xml System.Core System
LOCAL_MCS_FLAGS =

PROGRAM = mono-api-info.exe

include ../../build/executable.make
238 changes: 238 additions & 0 deletions corcompare/Util.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Text;
using Mono.Cecil;

namespace Mono.ApiTools {

class TypeHelper {

public TypeHelper (bool ignoreResolutionErrors, bool ignoreInheritedInterfaces)
{
IgnoreResolutionErrors = ignoreResolutionErrors;
IgnoreInheritedInterfaces = ignoreInheritedInterfaces;
}

public bool IgnoreResolutionErrors { get; }

public bool IgnoreInheritedInterfaces { get; }

public AssemblyResolver Resolver { get; } = new AssemblyResolver();

internal bool TryResolve (CustomAttribute attribute)
{
if (attribute == null)
throw new ArgumentNullException (nameof (attribute));

try {
var has = attribute.HasProperties;
return true;
} catch (AssemblyResolutionException) when (IgnoreResolutionErrors) {
return false;
}
}

internal bool IsPublic (TypeReference typeref)
{
if (typeref == null)
throw new ArgumentNullException ("typeref");

try {
var td = typeref.Resolve ();
if (td == null)
return false;

return td.IsPublic || (td.IsNestedPublic && IsPublic (td.DeclaringType));
} catch (AssemblyResolutionException) when (IgnoreResolutionErrors) {
return true;
}
}

internal bool IsDelegate (TypeReference typeref)
{
return IsDerivedFrom (typeref, "System.MulticastDelegate");
}

internal bool IsDerivedFrom (TypeReference type, string derivedFrom)
{
bool first = true;
foreach (var def in WalkHierarchy (type)) {
if (first) {
first = false;
continue;
}

if (def.FullName == derivedFrom)
return true;
}

return false;
}

internal IEnumerable<TypeDefinition> WalkHierarchy (TypeReference type)
{
for (var def = type.Resolve (); def != null; def = GetBaseType (def))
yield return def;
}

internal IEnumerable<TypeReference> GetInterfaces (TypeReference type)
{
var ifaces = new Dictionary<string, TypeReference> ();

foreach (var def in WalkHierarchy (type)) {
foreach (var iface in def.Interfaces)
ifaces [iface.InterfaceType.FullName] = iface.InterfaceType;
if (IgnoreInheritedInterfaces)
break;
}

return ifaces.Values;
}

internal TypeDefinition GetBaseType (TypeDefinition child)
{
if (child.BaseType == null)
return null;

try {
return child.BaseType.Resolve ();
} catch (AssemblyResolutionException) when (IgnoreResolutionErrors) {
return null;
}
}

internal MethodDefinition GetMethod (MethodReference method)
{
if (method == null)
throw new ArgumentNullException (nameof (method));

try {
return method.Resolve ();
} catch (AssemblyResolutionException) when (IgnoreResolutionErrors) {
return null;
}
}

internal bool IsPublic (CustomAttribute att)
{
return IsPublic (att.AttributeType);
}

internal string GetFullName (CustomAttribute att)
{
return att.AttributeType.FullName;
}

internal TypeDefinition GetTypeDefinition (CustomAttribute att)
{
return att.AttributeType.Resolve ();
}

bool IsOverride (MethodDefinition method)
{
return method.IsVirtual && !method.IsNewSlot;
}

public 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;
}

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;
}

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 bool TypeMatch (IModifierType a, IModifierType b)
{
if (!TypeMatch (a.ModifierType, b.ModifierType))
return false;

return TypeMatch (a.ElementType, b.ElementType);
}

public 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 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 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;
}
}
}
Loading

0 comments on commit 4516e13

Please sign in to comment.