// Copyright (c) Microsoft Corporation. All rights reserved.
//
using System;
using System.Collections.Generic;
using System.Compiler;
namespace Microsoft.Ddue.Tools.Reflection{
public static class ReflectionUtilities {
public static Event[] GetImplementedEvents(Event trigger) {
List < Event > list = new List < Event >();
// get the adder
Method adder = trigger.HandlerAdder;
// get interface methods corresponding to this adder
Method[] implementedAdders = GetImplementedMethods(adder);
// get the events corresponding to the implemented adders
foreach (Method implementedAdder in implementedAdders) {
Event implementedTrigger = GetEventFromAdder(implementedAdder);
if (implementedTrigger != null) list.Add(implementedTrigger);
}
return (list.ToArray());
}
public static Method[] GetImplementedMethods(Method method) {
List < Method > list = new List < Method >();
// Explicit implementations
MethodList explicitImplementations = method.ImplementedInterfaceMethods;
if (explicitImplementations != null) {
for (int i = 0; i < explicitImplementations.Count; i++) {
Method explicitImplementation = explicitImplementations[i];
list.Add(explicitImplementation);
}
}
// Implicit implementations
MethodList implicitImplementations = method.ImplicitlyImplementedInterfaceMethods;
if (implicitImplementations != null) {
for (int i = 0; i < implicitImplementations.Count; i++) {
Method implicitImplementation = implicitImplementations[i];
list.Add(implicitImplementation);
}
}
return (list.ToArray());
}
public static Property[] GetImplementedProperties(Property property) {
List < Property > list = new List < Property >();
// get an accessor
Method accessor = property.Getter;
if (accessor == null) accessor = property.Setter;
if (accessor == null) return (new Property[0]);
// get the interface methods corresponding to this accessor
Method[] methods = GetImplementedMethods(accessor);
// look for properties corresponding to these methods
for (int i = 0; i < methods.Length; i++) {
Method method = methods[i];
Property entry = GetPropertyFromAccessor(method);
if (entry != null) list.Add(entry);
}
return (list.ToArray());
}
public static Namespace GetNamespace(TypeNode type) {
if (type.DeclaringType != null) {
return (GetNamespace(type.DeclaringType));
} else {
return (new Namespace(type.Namespace));
}
}
public static Member GetTemplateMember(Member member) {
if (member == null) throw new ArgumentNullException("member");
// if the containing type isn't generic, the member is the template member
TypeNode type = member.DeclaringType;
if (!type.IsGeneric) return (member);
// if the containing type isn't specialized, the member is the template member
if (!IsSpecialized(type)) return (member);
// get the template type, and look for members with the same name
TypeNode template = ReflectionUtilities.GetTemplateType(member.DeclaringType);
Identifier name = member.Name;
MemberList candidates = template.GetMembersNamed(name);
// if no candidates, say so (this shouldn't happen)
if (candidates.Count == 0) throw new InvalidOperationException("No members in the template had the name found in the specialization. This is not possible, but apparently it happened.");
// if only one candidate, return it
if (candidates.Count == 1) return (candidates[0]);
// multiple candidates, so now we need to compare parameters
ParameterList parameters = GetParameters(member);
for (int i = 0; i < candidates.Count; i++) {
Member candidate = candidates[i];
// candidate must be same kind of node
if (candidate.NodeType != member.NodeType) continue;
// if parameters match, this is the one
if (ParametersMatch(parameters, GetParameters(candidate))) return (candidate);
}
Console.WriteLine(member.DeclaringType.FullName);
Console.WriteLine(member.FullName);
throw new InvalidOperationException("No members in the template matched the parameters of the specialization. This is not possible.");
}
public static TypeNode GetTemplateType(TypeNode type) {
if (type == null) throw new ArgumentNullException("type");
// Console.WriteLine(type.FullName);
// only generic types have templates
if (!type.IsGeneric) return (type);
if (type.DeclaringType == null) {
// if the type is not nested, life is simpler
// if the type is not specified, the type is the template
if (type.TemplateArguments == null) return (type);
// otherwise, construct the template type identifier and use it to fetch the template type
Module templateModule = type.DeclaringModule;
Identifier name = new Identifier(String.Format("{0}`{1}", type.GetUnmangledNameWithoutTypeParameters(), type.TemplateArguments.Count));
Identifier space = type.Namespace;
TypeNode template = templateModule.GetType(space, name);
return (template);
} else {
// if the type is nested, life is harder; we have to walk up the chain, constructing
// un-specialized identifiers as we go, then walk back down the chain, fetching
// template types as we go
// create a stack to keep track of identifiers
Stack < Identifier > identifiers = new Stack < Identifier >();
// populate the stack with the identifiers of all the types up to the outermost type
TypeNode current = type;
while (true) {
int count = 0;
if ((current.TemplateArguments != null) && (current.TemplateArguments.Count > count)) count = current.TemplateArguments.Count;
if ((current.TemplateParameters != null) && (current.TemplateParameters.Count > count)) count = current.TemplateParameters.Count;
TypeNodeList arguments = current.TemplateParameters;
if (count == 0) {
identifiers.Push(new Identifier(current.GetUnmangledNameWithoutTypeParameters()));
} else {
identifiers.Push(new Identifier(String.Format("{0}`{1}", current.GetUnmangledNameWithoutTypeParameters(), count)));
}
// Console.WriteLine("U {0} {1}", identifiers.Peek(), CountArguments(current));
if (current.DeclaringType == null) break;
current = current.DeclaringType;
}
// fetch a TypeNode representing that outermost type
Module module = current.DeclaringModule;
Identifier space = current.Namespace;
current = module.GetType(space, identifiers.Pop());
// move down the stack to the inner type we want
while (identifiers.Count > 0) {
current = (TypeNode)current.GetMembersNamed(identifiers.Pop())[0];
// Console.WriteLine("D {0} {1}", current.GetFullUnmangledNameWithTypeParameters(), CountArguments(current));
}
// whew, finally we've got it
return (current);
}
}
public static bool IsDefaultMember(Member member) {
if (member == null) throw new ArgumentNullException("member");
TypeNode type = member.DeclaringType;
MemberList defaultMembers = type.DefaultMembers;
for (int i = 0; i < defaultMembers.Count; i++) {
Member defaultMember = defaultMembers[i];
if (member == defaultMember) return (true);
}
return (false);
}
private static Event GetEventFromAdder(Method adder) {
if (adder == null) throw new ArgumentNullException("adder");
TypeNode type = adder.DeclaringType;
MemberList members = type.Members;
foreach (Member member in members) {
if (member.NodeType != NodeType.Event) continue;
Event trigger = member as Event;
if (trigger.HandlerAdder == adder) return (trigger);
}
return (null);
}
private static ParameterList GetParameters(Member member) {
Method method = member as Method;
if (method != null) return (method.Parameters);
Property property = member as Property;
if (property != null) return (property.Parameters);
return (new ParameterList());
}
private static Property GetPropertyFromAccessor(Method accessor) {
if (accessor == null) throw new ArgumentNullException("accessor");
TypeNode type = accessor.DeclaringType;
MemberList members = type.Members;
foreach (Member member in members) {
if (member.NodeType != NodeType.Property) continue;
Property property = member as Property;
if (property.Getter == accessor) return (property);
if (property.Setter == accessor) return (property);
}
return (null);
}
private static bool IsSpecialized(TypeNode type) {
for (TypeNode t = type; t != null; t = t.DeclaringType) {
TypeNodeList templates = t.TemplateArguments;
if ((templates != null) && (templates.Count > 0)) return (true);
}
return (false);
}
// parameters1 should be fully specialized; parameters2
private static bool ParametersMatch(ParameterList parameters1, ParameterList parameters2) {
if (parameters1.Count != parameters2.Count) return (false);
for (int i = 0; i < parameters1.Count; i++) {
TypeNode type1 = parameters1[i].Type;
TypeNode type2 = parameters2[i].Type;
// we can't determine the equivilence of template parameters; this is probably not good
if (type1.IsTemplateParameter || type2.IsTemplateParameter) continue;
// the node type must be the same; this is probably a fast check
if (type1.NodeType != type2.NodeType) return (false);
// if they are "normal" types, we will compare them
// comparing arrays, pointers, etc. is dangerous, because the types they contian may be template parameters
if ((type1.NodeType == NodeType.Class) || (type1.NodeType == NodeType.Struct) || (type1.NodeType == NodeType.Interface) ||
(type1.NodeType == NodeType.EnumNode) || (type1.NodeType == NodeType.DelegateNode)) {
type1 = GetTemplateType(type1);
type2 = GetTemplateType(type2);
if (!type2.IsStructurallyEquivalentTo(type1)) {
// Console.WriteLine("{0} !~ {1}", type1.FullName, type2.FullName);
return (false);
} else {
// Console.WriteLine("{0} ~ {1}", type1.FullName, type2.FullName);
}
}
}
return (true);
}
private static bool TypeMatch(TypeNode type1, TypeNode type2) {
// the two types must be of the same kind
if (type1.NodeType != type2.NodeType) return (false);
if (type1.NodeType == NodeType.ArrayType) {
// they are arrays, so check elements
ArrayType array1 = (ArrayType)type1;
ArrayType array2 = (ArrayType)type2;
return (TypeMatch(array1.ElementType, array2.ElementType));
} else {
// they are normal types
return (type1.IsStructurallyEquivalentTo(type2));
}
}
}
}
|