summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/Reflection/Reflection.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/Reflection/Reflection.cs')
-rw-r--r--tools/Sandcastle/Source/Reflection/Reflection.cs298
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));
+ }
+ }
+
+ }
+
+}