diff options
Diffstat (limited to 'tools/Sandcastle/Source/Reflection/Reflection.cs')
-rw-r--r-- | tools/Sandcastle/Source/Reflection/Reflection.cs | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/Reflection/Reflection.cs b/tools/Sandcastle/Source/Reflection/Reflection.cs new file mode 100644 index 0000000..e646cc6 --- /dev/null +++ b/tools/Sandcastle/Source/Reflection/Reflection.cs @@ -0,0 +1,298 @@ +// 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)); + } + } + + } + +} |