summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-09-20 21:18:59 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2009-09-21 08:06:22 -0700
commitbbe3f9cc9c8a1e5909273c1a162a63ea7a66afd8 (patch)
treec91f66e642c4d26fca266e226b3f2765f546d700 /tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs
parent627014f0bbc3fd576277375e70f8391d150b0a67 (diff)
downloadDotNetOpenAuth-bbe3f9cc9c8a1e5909273c1a162a63ea7a66afd8.zip
DotNetOpenAuth-bbe3f9cc9c8a1e5909273c1a162a63ea7a66afd8.tar.gz
DotNetOpenAuth-bbe3f9cc9c8a1e5909273c1a162a63ea7a66afd8.tar.bz2
Switched out the Sandcastle binaries for the source code.
Diffstat (limited to 'tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs')
-rw-r--r--tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs217
1 files changed, 217 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs b/tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs
new file mode 100644
index 0000000..9a6115f
--- /dev/null
+++ b/tools/Sandcastle/Source/MRefBuilder/ExtensionMethodAddIn.cs
@@ -0,0 +1,217 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Xml;
+using System.Xml.XPath;
+
+using System.Compiler;
+
+using Microsoft.Ddue.Tools.Reflection;
+
+namespace Microsoft.Ddue.Tools {
+
+ // Extension method add in
+
+ public class ExtensionMethodAddIn : MRefBuilderAddIn {
+
+ private Dictionary < TypeNode, List < Method > > index = new Dictionary < TypeNode, List < Method > >();
+
+ private bool isExtensionMethod = false;
+
+ private ManagedReflectionWriter reflector;
+
+ public ExtensionMethodAddIn(ManagedReflectionWriter reflector, XPathNavigator configuration) : base(reflector, configuration) {
+ this.reflector = reflector;
+ reflector.RegisterStartTagCallback("apis", new MRefBuilderCallback(RecordExtensionMethods));
+ reflector.RegisterEndTagCallback("elements", new MRefBuilderCallback(AddExtensionMethods));
+ reflector.RegisterStartTagCallback("apidata", new MRefBuilderCallback(AddExtensionSubsubgroup));
+ }
+
+ private void AddExtensionMethod(XmlWriter writer, TypeNode type, Method extensionMethodTemplate, TypeNode specialization) {
+
+ // Construct the extension method for naming
+ Method extensionMethodTemplate2 = extensionMethodTemplate;
+ if (extensionMethodTemplate2.IsGeneric && (specialization != null)) extensionMethodTemplate2 = extensionMethodTemplate.GetTemplateInstance(type, specialization);
+ TypeNode extensionMethodTemplateReturnType = extensionMethodTemplate2.ReturnType;
+ ParameterList extensionMethodTemplateParameters = extensionMethodTemplate2.Parameters;
+
+ ParameterList extensionMethodParameters = new ParameterList();
+ for (int i = 1; i < extensionMethodTemplateParameters.Length; i++) {
+ Parameter extensionMethodParameter = extensionMethodTemplateParameters[i];
+ extensionMethodParameters.Add(extensionMethodParameter);
+ }
+ Method extensionMethod = new Method(extensionMethodTemplate.DeclaringType, new AttributeList(), extensionMethodTemplate.Name, extensionMethodParameters, extensionMethodTemplate.ReturnType, null);
+ extensionMethod.Flags = extensionMethodTemplate.Flags & ~MethodFlags.Static;
+
+ //Method specializedMethod == extensionMethod.Get
+
+ // Get the names
+ string extensionMethodId = reflector.ApiNamer.GetMemberName(extensionMethod);
+ string extensionMethodTemplateId = reflector.ApiNamer.GetMemberName(extensionMethodTemplate);
+
+ writer.WriteStartElement("element");
+ writer.WriteAttributeString("api", extensionMethodTemplateId);
+ writer.WriteAttributeString("display-api", extensionMethodId);
+ writer.WriteAttributeString("source", "extension");
+ isExtensionMethod = true;
+ reflector.WriteMember(extensionMethod);
+ isExtensionMethod = false;
+ writer.WriteEndElement();
+
+ }
+
+ private void AddExtensionMethods(XmlWriter writer, Object info) {
+
+ MemberDictionary members = info as MemberDictionary;
+ if (members == null) return;
+
+ TypeNode type = members.Type;
+
+ InterfaceList contracts = type.Interfaces;
+ foreach (Interface contract in contracts) {
+ List < Method > extensionMethods = null;
+ if (index.TryGetValue(contract, out extensionMethods)) {
+ foreach (Method extensionMethod in extensionMethods) AddExtensionMethod(writer, type, extensionMethod, null);
+ }
+ if (contract.IsGeneric && (contract.TemplateArguments != null) && (contract.TemplateArguments.Length > 0)) {
+ Interface templateContract = (Interface)ReflectionUtilities.GetTemplateType(contract);
+ TypeNode specialization = contract.TemplateArguments[0];
+ if (index.TryGetValue(templateContract, out extensionMethods)) {
+ foreach (Method extensionMethod in extensionMethods) {
+ if (IsValidTemplateArgument(specialization, extensionMethod.TemplateParameters[0])) {
+ AddExtensionMethod(writer, type, extensionMethod, specialization);
+ }
+ }
+ }
+ }
+ }
+
+ TypeNode comparisonType = type;
+ while (comparisonType != null) {
+ List < Method > extensionMethods = null;
+ if (index.TryGetValue(comparisonType, out extensionMethods)) {
+ foreach (Method extensionMethod in extensionMethods) AddExtensionMethod(writer, type, extensionMethod, null);
+ }
+ if (comparisonType.IsGeneric && (comparisonType.TemplateArguments != null) && (comparisonType.TemplateArguments.Length > 0)) {
+ TypeNode templateType = ReflectionUtilities.GetTemplateType(comparisonType);
+ TypeNode specialization = comparisonType.TemplateArguments[0];
+ if (index.TryGetValue(templateType, out extensionMethods)) {
+ foreach (Method extensionMethod in extensionMethods) {
+ if (IsValidTemplateArgument(specialization, extensionMethod.TemplateParameters[0])) {
+ AddExtensionMethod(writer, type, extensionMethod, specialization);
+ }
+ }
+ }
+ }
+ comparisonType = comparisonType.BaseType;
+ }
+ }
+
+ private void AddExtensionSubsubgroup(XmlWriter writer, Object data) {
+ if (isExtensionMethod) writer.WriteAttributeString("subsubgroup", "extension");
+ }
+
+ private bool HasExtensionAttribute(Method method) {
+ AttributeList attributes = method.Attributes;
+ foreach (AttributeNode attribute in attributes) {
+ if (attribute.Type.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") return (true);
+ }
+ return (false);
+ }
+
+ private bool IsValidTemplateArgument(TypeNode type, TypeNode parameter) {
+ if (type == null) throw new ArgumentNullException("type");
+ if (parameter == null) throw new ArgumentNullException("parameter");
+
+ // check that the parameter really is a type parameter
+
+ ITypeParameter itp = parameter as ITypeParameter;
+ if (itp == null) throw new ArgumentException("parameter");
+
+ // test constraints
+
+ bool reference = ((itp.TypeParameterFlags & TypeParameterFlags.ReferenceTypeConstraint) > 0);
+ if (reference && type.IsValueType) return (false);
+
+ bool value = ((itp.TypeParameterFlags & TypeParameterFlags.ValueTypeConstraint) > 0);
+ if (value && !type.IsValueType) return (false);
+
+ bool constructor = ((itp.TypeParameterFlags & TypeParameterFlags.DefaultConstructorConstraint) > 0);
+
+
+ InterfaceList contracts = parameter.Interfaces;
+ if (contracts != null) {
+ foreach (Interface contract in contracts) {
+ if (!type.IsAssignableTo(contract)) return (false);
+ }
+ }
+
+ TypeNode parent = parameter.BaseType;
+ if ((parent != null) && !type.IsAssignableTo(parent)) return (false);
+
+ // okay, passed all tests
+
+ return (true);
+
+ }
+
+ private void RecordExtensionMethods(XmlWriter writer, Object info) {
+ NamespaceList spaces = (NamespaceList)info;
+ foreach (Namespace space in spaces) {
+ TypeNodeList types = space.Types;
+ foreach (TypeNode type in types) {
+
+ MemberList members = type.Members;
+
+ // go through the members, looking for fields signaling attached properties
+ foreach (Member member in members) {
+
+ Method method = member as Method;
+ if (method == null) continue;
+
+ if (!reflector.ApiFilter.IsExposedMember(method)) continue;
+
+ if (!HasExtensionAttribute(method)) continue;
+
+ ParameterList parameters = method.Parameters;
+ TypeNode extendedType = parameters[0].Type;
+
+ // recognize Method<T>(Type<T>, ...) extension methods
+ if (method.IsGeneric && (method.TemplateParameters.Length == 1)) {
+ if (extendedType.IsGeneric && (extendedType.TemplateArguments != null) && (extendedType.TemplateArguments.Length == 1)) {
+ TypeNode arg = extendedType.TemplateArguments[0];
+ if (arg.IsTemplateParameter) {
+ ITypeParameter gtp = (ITypeParameter)arg;
+ if ((gtp.DeclaringMember == method) && (gtp.ParameterListIndex == 0)) {
+ extendedType = ReflectionUtilities.GetTemplateType(extendedType);
+ }
+ }
+ }
+ }
+
+ List < Method > methods = null;
+ if (!index.TryGetValue(extendedType, out methods)) {
+ methods = new List < Method >();
+ index.Add(extendedType, methods);
+ }
+
+ methods.Add(method);
+
+ }
+ }
+
+ }
+
+ /*
+ Console.WriteLine("Recorded {0} extension methods", index.Count);
+ foreach (TypeNode type in index.Keys) {
+ Console.WriteLine(type.FullName);
+ }
+ */
+ }
+
+ }
+
+}