summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs')
-rw-r--r--tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs1316
1 files changed, 1316 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs b/tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs
new file mode 100644
index 0000000..33ff1dd
--- /dev/null
+++ b/tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs
@@ -0,0 +1,1316 @@
+// Copyright © Microsoft Corporation.
+// This source file is subject to the Microsoft Permissive License.
+// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
+// All other rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Text;
+using System.IO;
+using System.Xml;
+
+using System.Compiler;
+using Microsoft.Ddue.Tools.Reflection;
+
+namespace Microsoft.Ddue.Tools {
+
+
+ // Write out information gained from managed reflection
+
+ public class ManagedReflectionWriter : ApiVisitor {
+ private const string implement = "implement";
+
+ // Implementations
+
+ private const string implements = "implements";
+
+ private Dictionary < string, Object > assemblyNames = new Dictionary < string, Object >();
+
+ // Inheritence
+
+ // Keep track of descendents
+
+ private Dictionary < TypeNode, List < TypeNode > > descendentIndex = new Dictionary < TypeNode, List < TypeNode > >();
+
+ private Dictionary < string, List < MRefBuilderCallback > > endTagCallbacks = new Dictionary < string, List < MRefBuilderCallback > >();
+
+ // Keep track of interface implementors
+
+ private Dictionary < Interface, List < TypeNode > > implementorIndex = new Dictionary < Interface, List < TypeNode > >();
+
+ // private ApiFilter memberFilter = new ExternalDocumentedFilter();
+
+ private bool includeNamespaces = true;
+
+ private ApiNamer namer;
+
+ private List < Member > parsedMembers = new List < Member >();
+
+ private List < Namespace > parsedNamespaces = new List < Namespace >();
+
+ private List < TypeNode > parsedTypes = new List < TypeNode >();
+
+ // add-in callbacks
+
+ private Dictionary < string, List < MRefBuilderCallback > > startTagCallbacks = new Dictionary < string, List < MRefBuilderCallback > >();
+
+ // Stored data
+
+ private XmlWriter writer;
+
+ // Constructor
+
+ public ManagedReflectionWriter(TextWriter output) : this(output, new ExternalTopicFilter()) { }
+
+ public ManagedReflectionWriter(TextWriter output, ApiFilter filter) : this(output, filter, new OrcasNamer()) { }
+
+ public ManagedReflectionWriter(TextWriter output, ApiNamer namer) : this(output, new ExternalTopicFilter(), namer) { }
+
+ public ManagedReflectionWriter(TextWriter output, ApiFilter filter, ApiNamer namer) : base(filter) {
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Indent = true;
+ writer = XmlWriter.Create(output, settings);
+
+ this.namer = namer;
+ }
+
+ // Exposed data
+
+ public ApiNamer ApiNamer {
+ get {
+ return (namer);
+ }
+ set {
+ namer = value;
+ }
+ }
+
+ public bool IncludeNamespaces {
+ get {
+ return (includeNamespaces);
+ }
+ set {
+ includeNamespaces = value;
+ }
+ }
+
+ public Member[] Members {
+ get {
+ return (parsedMembers.ToArray());
+ }
+ }
+
+ public Namespace[] Namespaces {
+ get {
+ return (parsedNamespaces.ToArray());
+ }
+ }
+
+
+ public TypeNode[] Types {
+ get {
+ return (parsedTypes.ToArray());
+ }
+ }
+
+ // disposal
+
+ protected override void Dispose(bool disposing) {
+ if (disposing) {
+ writer.Close();
+ }
+ base.Dispose(disposing);
+ }
+
+ public void RegisterEndTagCallback(string name, MRefBuilderCallback callback) {
+ List < MRefBuilderCallback > current;
+ if (!endTagCallbacks.TryGetValue(name, out current)) {
+ current = new List < MRefBuilderCallback >();
+ endTagCallbacks.Add(name, current);
+ }
+ current.Add(callback);
+ }
+
+ public void RegisterStartTagCallback(string name, MRefBuilderCallback callback) {
+ List < MRefBuilderCallback > current;
+ if (!startTagCallbacks.TryGetValue(name, out current)) {
+ current = new List < MRefBuilderCallback >();
+ startTagCallbacks.Add(name, current);
+ }
+ current.Add(callback);
+ }
+
+ public void WriteMember(Member member) {
+ //Console.WriteLine("Write Member {0} [{1}]", member.FullName, member.DeclaringType.DeclaringModule.Name);
+ WriteMember(member, member.DeclaringType);
+ }
+
+ public void WriteMemberReference(Member member) {
+ if (member == null) throw new ArgumentNullException("member");
+ writer.WriteStartElement("member");
+ Member template = ReflectionUtilities.GetTemplateMember(member);
+ writer.WriteAttributeString("api", namer.GetMemberName(template));
+ if (!member.DeclaringType.IsStructurallyEquivalentTo(template.DeclaringType)) {
+ writer.WriteAttributeString("display-api", namer.GetMemberName(member));
+ }
+ WriteTypeReference(member.DeclaringType);
+ writer.WriteEndElement();
+ }
+
+ public void WriteTypeReference(TypeNode type) {
+ if (type == null) throw new ArgumentNullException("type");
+ WriteStartTypeReference(type);
+ writer.WriteEndElement();
+ }
+
+ protected override void VisitMember(Member member) {
+ //Console.WriteLine("Member: {0}", member.Name);
+ parsedMembers.Add(member);
+
+ writer.WriteStartElement("api");
+ writer.WriteAttributeString("id", namer.GetMemberName(member));
+ StartElementCallbacks("api", member);
+ WriteMember(member);
+ EndElementCallbacks("api", member);
+ writer.WriteEndElement();
+ }
+
+ protected override void VisitNamespace(Namespace space) {
+ parsedNamespaces.Add(space);
+ WriteNamespace(space);
+ base.VisitNamespace(space);
+ }
+
+ // visitation logic
+
+ protected override void VisitNamespaces(NamespaceList spaces) {
+
+ // construct a sorted assembly catalog
+ foreach (AssemblyNode assembly in this.Assemblies) {
+ assemblyNames.Add(assembly.StrongName, null);
+ }
+
+ // catalog type hierarchy and interface implementors
+ for (int i = 0; i < spaces.Count; i++) {
+ TypeNodeList types = spaces[i].Types;
+ for (int j = 0; j < types.Count; j++) {
+ TypeNode type = types[j];
+ if (ApiFilter.IsExposedType(type)) {
+ if (type.NodeType == NodeType.Class) PopulateDescendentIndex(type);
+ PopulateImplementorIndex(type);
+ }
+ }
+ }
+
+ // start the document
+ writer.WriteStartDocument();
+ writer.WriteStartElement("reflection");
+
+ // write assembly info
+ writer.WriteStartElement("assemblies");
+ foreach (AssemblyNode assembly in this.Assemblies) {
+ WriteAssembly(assembly);
+ }
+ writer.WriteEndElement();
+
+ // start api info
+ writer.WriteStartElement("apis");
+ StartElementCallbacks("apis", spaces);
+
+ // write it
+ WriteNamespaces(spaces);
+ base.VisitNamespaces(spaces);
+
+ // finish api info
+ EndElementCallbacks("apis", spaces);
+ writer.WriteEndElement();
+
+ // finish document
+ writer.WriteEndElement();
+ writer.WriteEndDocument();
+
+ }
+
+ protected override void VisitType(TypeNode type) {
+ //Console.WriteLine("Type: {0}", type.FullName);
+ parsedTypes.Add(type);
+ WriteType(type);
+ base.VisitType(type);
+ }
+
+ // Attributes
+
+ protected void WriteAttributes(AttributeList attributes, SecurityAttributeList securityAttributes) {
+ AttributeNode[] exposed = GetExposedAttributes(attributes, securityAttributes);
+ if (exposed.Length == 0) return;
+ writer.WriteStartElement("attributes");
+ for (int i = 0; i < exposed.Length; i++) {
+ AttributeNode attribute = exposed[i];
+ writer.WriteStartElement("attribute");
+
+ TypeNode type = attribute.Type;
+ WriteTypeReference(attribute.Type);
+ // WriteStringAttribute("type", namer.GetApiName(attribute.Type));
+
+ ExpressionList expressions = attribute.Expressions;
+ for (int j = 0; j < expressions.Count; j++) {
+ WriteExpression(expressions[j]);
+ }
+
+ writer.WriteEndElement();
+ }
+ writer.WriteEndElement();
+ }
+
+ protected void WriteExpression(Expression expression) {
+ if (expression.NodeType == NodeType.Literal) {
+ Literal argument = (Literal)expression;
+ writer.WriteStartElement("argument");
+ WriteLiteral(argument);
+ writer.WriteEndElement();
+ } else if (expression.NodeType == NodeType.NamedArgument) {
+ NamedArgument assignment = (NamedArgument)expression;
+ Literal value = (Literal)assignment.Value;
+ writer.WriteStartElement("assignment");
+ WriteStringAttribute("name", assignment.Name.Name);
+ WriteLiteral(value);
+ writer.WriteEndElement();
+ }
+ }
+
+ private static FieldList GetAppliedFields(EnumNode enumeration, long value) {
+ // if a single field matches, return it;
+ // otherwise return all fields that are in value
+ FieldList list = new FieldList();
+ MemberList members = enumeration.Members;
+ for (int i = 0; i < members.Count; i++) {
+ if (members[i].NodeType != NodeType.Field) continue;
+ Field field = (Field)members[i];
+ if (field.DefaultValue == null) continue;
+ long fieldValue = Convert.ToInt64(field.DefaultValue.Value);
+ if (fieldValue == value) {
+ return (new FieldList(new Field[1] { field }));
+ } else if ((fieldValue & value) == fieldValue) {
+ list.Add(field);
+ }
+ }
+ return (list);
+ }
+
+ // Static utility functions
+
+ private static Namespace GetNamespace(TypeNode type) {
+ if (type.DeclaringType != null) {
+ return (GetNamespace(type.DeclaringType));
+ } else {
+ return (new Namespace(type.Namespace));
+ }
+ }
+
+ private static string GetVisibility(Member api) {
+ if (api == null) throw new ArgumentNullException("api");
+ if (api.IsPublic) {
+ return ("public");
+ } else if (api.IsAssembly) {
+ return ("assembly");
+ } else if (api.IsFamilyOrAssembly) {
+ return ("family or assembly");
+ } else if (api.IsFamily) {
+ return ("family");
+ } else if (api.IsFamilyAndAssembly) {
+ return ("family and assembly");
+ } else if (api.IsPrivate) {
+ return ("private");
+ } else {
+ throw new InvalidOperationException(String.Format("Unknown access level for {0}", api.FullName));
+ }
+ }
+
+ private static bool IsValidXmlChar(char c) {
+ if (c < 0x20) {
+ return ((c == 0x9) || (c == 0xa));
+ } else {
+ return ((c <= 0xd7ff) || ((0xe000 <= c) && (c <= 0xfffd)));
+ }
+ }
+
+ private static bool IsValidXmlText(string text) {
+ foreach (char c in text) {
+ if (!IsValidXmlChar(c)) return (false);
+ }
+ return (true);
+ }
+
+ private void EndElementCallbacks(string name, Object info) {
+ List < MRefBuilderCallback > callbacks;
+ if (endTagCallbacks.TryGetValue(name, out callbacks)) {
+ foreach (MRefBuilderCallback callback in callbacks) callback.Invoke(writer, info);
+ }
+ }
+
+ private AttributeNode[] GetExposedAttributes(AttributeList attributes, SecurityAttributeList securityAttributes) {
+ if (attributes == null) Console.WriteLine("null attribute list");
+ if (securityAttributes == null) Console.WriteLine("null security attribute list");
+ List < AttributeNode > exposedAttributes = new List < AttributeNode >();
+ for (int i = 0; i < attributes.Count; i++) {
+ AttributeNode attribute = attributes[i];
+ if (attribute == null) Console.WriteLine("null attribute");
+ if (this.ApiFilter.IsExposedAttribute(attribute)) exposedAttributes.Add(attribute);
+ }
+ for (int i = 0; i < securityAttributes.Count; i++) {
+ SecurityAttribute securityAttribute = securityAttributes[i];
+ if (securityAttribute == null) Console.WriteLine("null security attribute");
+ AttributeList permissionAttributes = securityAttribute.PermissionAttributes;
+ //if (permissionAttributes == null) Console.WriteLine("null permission attribute list");
+ if (permissionAttributes == null) continue;
+ for (int j = 0; j < permissionAttributes.Count; j++) {
+ AttributeNode permissionAttribute = permissionAttributes[j];
+ //if (permissionAttribute == null) Console.WriteLine("null permission attribute");
+ // saw an example where this was null; ildasm shows no permission attribute, so skip it
+ if (permissionAttribute == null) continue;
+ if (this.ApiFilter.IsExposedAttribute(permissionAttribute)) exposedAttributes.Add(permissionAttribute);
+ }
+ }
+ return (exposedAttributes.ToArray());
+ }
+
+ private Member[] GetExposedImplementedMembers(IEnumerable < Member > members) {
+ List < Member > exposedImplementedMembers = new List < Member >();
+ foreach (Member member in members) {
+ if (this.ApiFilter.IsExposedMember(member)) {
+ exposedImplementedMembers.Add(member);
+ }
+ }
+ return (exposedImplementedMembers.ToArray());
+ }
+
+ private Interface[] GetExposedInterfaces(InterfaceList contracts) {
+ List < Interface > exposedContracts = new List < Interface >();
+ for (int i = 0; i < contracts.Count; i++) {
+ Interface contract = contracts[i];
+ if (this.ApiFilter.IsExposedType(contract)) {
+ // if generic, check whether specialization types are exposed
+ exposedContracts.Add(contract);
+ }
+ }
+ return (exposedContracts.ToArray());
+ }
+
+ private AttributeNode GetParamArrayAttribute(Parameter param)
+ {
+ AttributeList attributes = param.Attributes;
+ for (int i = 0, n = attributes == null ? 0 : attributes.Count; i < n; i++)
+ {
+ AttributeNode attr = attributes[i];
+ if (attr == null) continue;
+ if (attr.Type.FullName == "System.ParamArrayAttribute")
+ return attr;
+ }
+ return null;
+ }
+
+ private void PopulateDescendentIndex(TypeNode child) {
+
+ // get the parent of the type in question
+ TypeNode parent = child.BaseType;
+ if (parent == null) return;
+
+ // un-specialize the parent so we see specialized types as children
+ parent = ReflectionUtilities.GetTemplateType(parent);
+
+ // get the list of children for that parent (i.e. the sibling list)
+ List < TypeNode > siblings;
+ if (!descendentIndex.TryGetValue(parent, out siblings)) {
+ siblings = new List < TypeNode >();
+ descendentIndex[parent] = siblings;
+ }
+
+ // add the type in question to the sibling list
+ siblings.Add(child);
+
+ }
+
+ private void PopulateImplementorIndex(TypeNode type) {
+
+ // get the list of interfaces exposed by the type
+ Interface[] contracts = GetExposedInterfaces(type.Interfaces);
+
+ // for each implemented interface...
+ for (int i = 0; i < contracts.Length; i++) {
+
+ // get the unspecialized form of the interface
+ Interface contract = contracts[i];
+ if (contract.IsGeneric) contract = (Interface)ReflectionUtilities.GetTemplateType(contract);
+
+ // get the list of implementors
+ List < TypeNode > implementors;
+ if (!implementorIndex.TryGetValue(contract, out implementors)) {
+ implementors = new List < TypeNode >();
+ implementorIndex[contract] = implementors;
+ }
+
+ // and add the type to it
+ implementors.Add(type);
+ }
+ }
+
+ private void StartElementCallbacks(string name, Object info) {
+ List < MRefBuilderCallback > callbacks;
+ if (startTagCallbacks.TryGetValue(name, out callbacks)) {
+ foreach (MRefBuilderCallback callback in callbacks) callback.Invoke(writer, info);
+ }
+ }
+
+
+ // API data for all entities
+
+ private void WriteApiData(Member api) {
+ writer.WriteStartElement("apidata");
+
+ string name = api.Name.Name;
+
+ string group = null;
+ string subgroup = null;
+ string subsubgroup = null;
+
+ if (api.NodeType == NodeType.Namespace) {
+ group = "namespace";
+ } else if (api is TypeNode) {
+ group = "type";
+
+ TypeNode type = (TypeNode)api;
+ name = type.GetUnmangledNameWithoutTypeParameters();
+
+ switch (api.NodeType) {
+ case NodeType.Class:
+ subgroup = "class";
+ break;
+ case NodeType.Struct:
+ subgroup = "structure";
+ break;
+ case NodeType.Interface:
+ subgroup = "interface";
+ break;
+ case NodeType.EnumNode:
+ subgroup = "enumeration";
+ break;
+ case NodeType.DelegateNode:
+ subgroup = "delegate";
+ break;
+ }
+ } else {
+ group = "member";
+
+ switch (api.NodeType) {
+ case NodeType.Field:
+ subgroup = "field";
+ break;
+ case NodeType.Property:
+ subgroup = "property";
+ break;
+ case NodeType.InstanceInitializer:
+ case NodeType.StaticInitializer:
+ subgroup = "constructor";
+ // name = api.DeclaringType.GetUnmangledNameWithoutTypeParameters();
+ break;
+ case NodeType.Method:
+ subgroup = "method";
+ if ((api.IsSpecialName) && (name.StartsWith("op_"))) {
+ subsubgroup = "operator";
+ name = name.Substring(3);
+ }
+ break;
+ case NodeType.Event:
+ subgroup = "event";
+ break;
+ }
+
+ // Name of EIIs is just interface member name
+ int dotIndex = name.LastIndexOf(".");
+ if (dotIndex > 0) name = name.Substring(dotIndex + 1);
+
+ }
+
+
+ WriteStringAttribute("name", name);
+ WriteStringAttribute("group", group);
+ if (subgroup != null) WriteStringAttribute("subgroup", subgroup);
+ if (subsubgroup != null) WriteStringAttribute("subsubgroup", subsubgroup);
+
+ StartElementCallbacks("apidata", api);
+
+ // WriteStringAttribute("file", GetGuid(namer.GetApiName(api)).ToString());
+
+ EndElementCallbacks("apidata", api);
+ writer.WriteEndElement();
+ }
+
+ // writing logic
+
+ private void WriteAssembly(AssemblyNode assembly) {
+ // if (assembly == null) Console.WriteLine("null assembly");
+ // Console.WriteLine("assembly: {0}", assembly.Name);
+ writer.WriteStartElement("assembly");
+ // if (assembly.Name == null) Console.WriteLine("null assembly name");
+ WriteStringAttribute("name", assembly.Name);
+ // if (assembly.Version == null) Console.WriteLine("null assembly version");
+
+ // basic assembly data
+ writer.WriteStartElement("assemblydata");
+ WriteStringAttribute("version", assembly.Version.ToString());
+ WriteStringAttribute("culture", assembly.Culture.ToString());
+ byte[] key = assembly.PublicKeyOrToken;
+ writer.WriteStartAttribute("key");
+ writer.WriteBinHex(key, 0, key.Length);
+ writer.WriteEndAttribute();
+ WriteStringAttribute("hash", assembly.HashAlgorithm.ToString());
+ writer.WriteEndElement();
+
+ // assembly attribute data
+ WriteAttributes(assembly.Attributes, assembly.SecurityAttributes);
+
+ writer.WriteEndElement();
+ }
+
+ private void WriteAssignment(NamedArgument assignment) {
+ string name = assignment.Name.Name;
+ Literal value = (Literal)assignment.Value;
+ writer.WriteStartElement("assignment");
+ WriteStringAttribute("name", name);
+ WriteLiteral(value);
+ writer.WriteEndElement();
+ }
+
+ // utilities used to write attributes
+
+ private void WriteBooleanAttribute(string attribute, bool value) {
+ if (value) {
+ writer.WriteAttributeString(attribute, "true");
+ } else {
+ writer.WriteAttributeString(attribute, "false");
+ }
+ }
+
+ private void WriteBooleanAttribute(string attribute, bool value, bool defaultValue) {
+ if (value != defaultValue) {
+ WriteBooleanAttribute(attribute, value);
+ }
+ }
+
+ private void WriteEnumerationData(EnumNode enumeration) {
+ TypeNode underlying = enumeration.UnderlyingType;
+ if (underlying.FullName != "System.Int32") {
+ writer.WriteStartElement("enumerationbase");
+ WriteTypeReference(enumeration.UnderlyingType);
+ writer.WriteEndElement();
+ }
+ }
+
+ private void WriteEventData(Event trigger) {
+
+ Method adder = trigger.HandlerAdder;
+ Method remover = trigger.HandlerRemover;
+ Method caller = trigger.HandlerCaller;
+
+ WriteProcedureData(adder, trigger.OverriddenMember);
+
+ writer.WriteStartElement("eventdata");
+ if (adder != null) WriteBooleanAttribute("add", true);
+ if (remover != null) WriteBooleanAttribute("remove", true);
+ if (caller != null) WriteBooleanAttribute("call", true);
+ writer.WriteEndElement();
+
+ if (adder != null)
+ {
+ writer.WriteStartElement("adder");
+ WriteStringAttribute("name", string.Format("add_{0}", trigger.Name.Name));
+
+ WriteAttributes(adder.Attributes, adder.SecurityAttributes);
+ writer.WriteEndElement();
+ }
+ if (remover != null)
+ {
+ writer.WriteStartElement("remover");
+ WriteStringAttribute("name", string.Format("remove_{0}", trigger.Name.Name));
+
+ WriteAttributes(remover.Attributes, remover.SecurityAttributes);
+ writer.WriteEndElement();
+ }
+
+ writer.WriteStartElement("eventhandler");
+ WriteTypeReference(trigger.HandlerType);
+ writer.WriteEndElement();
+
+ // handlers should always be elegates, but I have seen a case where one is not, so check for this
+ DelegateNode handler = trigger.HandlerType as DelegateNode;
+ if (handler != null) {
+ ParameterList parameters = handler.Parameters;
+
+ if ((parameters != null) && (parameters.Count == 2) && (parameters[0].Type.FullName == "System.Object")) {
+ writer.WriteStartElement("eventargs");
+ WriteTypeReference(parameters[1].Type);
+ writer.WriteEndElement();
+ }
+ }
+
+ }
+
+
+ private void WriteFieldData(Field field) {
+ writer.WriteStartElement("fielddata");
+ WriteBooleanAttribute("literal", field.IsLiteral);
+ WriteBooleanAttribute("initonly", field.IsInitOnly);
+ WriteBooleanAttribute("volatile", field.IsVolatile, false);
+ WriteBooleanAttribute("serialized", (field.Flags & FieldFlags.NotSerialized) == 0);
+ writer.WriteEndElement();
+ }
+
+ private void WriteGenericParameter(TypeNode templateParameter)
+ {
+
+ ITypeParameter itp = (ITypeParameter)templateParameter;
+
+ writer.WriteStartElement("template");
+ writer.WriteAttributeString("name", templateParameter.Name.Name);
+
+ // evaluate constraints
+ bool reference = ((itp.TypeParameterFlags & TypeParameterFlags.ReferenceTypeConstraint) > 0);
+ bool value = ((itp.TypeParameterFlags & TypeParameterFlags.ValueTypeConstraint) > 0);
+ bool constructor = ((itp.TypeParameterFlags & TypeParameterFlags.DefaultConstructorConstraint) > 0);
+ bool contravariant = ((itp.TypeParameterFlags & TypeParameterFlags.Contravariant) > 0);
+ bool covariant = ((itp.TypeParameterFlags & TypeParameterFlags.Covariant) > 0);
+ InterfaceList interfaces = templateParameter.Interfaces;
+ TypeNode parent = templateParameter.BaseType;
+
+ // no need to show inheritance from ValueType if value flag is set
+ if (value && (parent != null) && (parent.FullName == "System.ValueType")) parent = null;
+
+ if ((parent != null) || (interfaces.Count > 0) || reference || value || constructor)
+ {
+ writer.WriteStartElement("constrained");
+ if (reference) WriteBooleanAttribute("ref", true);
+ if (value) WriteBooleanAttribute("value", true);
+ if (constructor) WriteBooleanAttribute("ctor", true);
+ if (parent != null) WriteTypeReference(parent);
+ WriteInterfaces(interfaces);
+ writer.WriteEndElement();
+ }
+ if (covariant || contravariant)
+ {
+ writer.WriteStartElement("variance");
+ if (contravariant) WriteBooleanAttribute("contravariant", true);
+ if (covariant) WriteBooleanAttribute("covariant", true);
+ writer.WriteEndElement();
+ }
+
+ writer.WriteEndElement();
+ }
+
+ private void WriteSpecializedTemplateArguments(TypeNodeList templateArguments)
+ {
+ if (templateArguments == null) return;
+ if (templateArguments.Count == 0) return;
+ writer.WriteStartElement("templates");
+ for (int i = 0; i < templateArguments.Count; i++)
+ {
+ WriteTypeReference(templateArguments[i]);
+ }
+ writer.WriteEndElement();
+ }
+
+ // Generic Parameters
+
+ private void WriteGenericParameters(TypeNodeList templateParameters)
+ {
+ if (templateParameters == null) return;
+ if (templateParameters.Count == 0) return;
+ writer.WriteStartElement("templates");
+ for (int i = 0; i < templateParameters.Count; i++)
+ {
+ WriteGenericParameter(templateParameters[i]);
+ }
+ writer.WriteEndElement();
+ }
+
+ private void WriteHierarchy(TypeNode type) {
+
+ writer.WriteStartElement("family");
+
+ // write ancestors
+ writer.WriteStartElement("ancestors");
+ for (TypeNode ancestor = type.BaseType; ancestor != null; ancestor = ancestor.BaseType) {
+ WriteTypeReference(ancestor);
+ }
+ writer.WriteEndElement();
+
+ // write descendents
+ if (descendentIndex.ContainsKey(type)) {
+ List < TypeNode > descendents = descendentIndex[type];
+ writer.WriteStartElement("descendents");
+ foreach (TypeNode descendent in descendents) WriteTypeReference(descendent);
+ writer.WriteEndElement();
+ }
+
+ writer.WriteEndElement();
+
+ }
+
+ private void WriteImplementedMembers(Member[] members) {
+ if ((members == null) || (members.Length == 0)) return;
+ Member[] exposedMembers = GetExposedImplementedMembers(members);
+ if ((exposedMembers == null) || (exposedMembers.Length == 0)) return;
+ writer.WriteStartElement(implements);
+ for (int i = 0; i < exposedMembers.Length; i++) {
+ Member member = exposedMembers[i];
+ //TypeNode type = member.DeclaringType;
+
+ WriteMemberReference(member);
+
+ }
+ writer.WriteEndElement();
+ }
+
+ // Interfaces
+
+ private void WriteImplementors(Interface contract) {
+ List < TypeNode > implementors;
+ if (!implementorIndex.TryGetValue(contract, out implementors)) return;
+ if ((implementors == null) || (implementors.Count == 0)) return;
+ writer.WriteStartElement("implementors");
+ StartElementCallbacks("implementors", implementors);
+ foreach (TypeNode implementor in implementors) {
+ WriteTypeReference(implementor);
+ }
+ writer.WriteEndElement();
+ EndElementCallbacks("implementors", implementors);
+ }
+
+ private void WriteInterface(Interface contract) {
+ // writer.WriteStartElement("implement");
+ WriteTypeReference(contract);
+ // writer.WriteAttributeString("interface", namer.GetTypeName(contract));
+ // writer.WriteEndElement();
+ }
+
+ private void WriteInterfaces(InterfaceList contracts) {
+ Interface[] implementedContracts = GetExposedInterfaces(contracts);
+ if (implementedContracts.Length == 0) return;
+ writer.WriteStartElement("implements");
+ StartElementCallbacks("implements", implementedContracts);
+ for (int i = 0; i < implementedContracts.Length; i++) {
+ WriteInterface(implementedContracts[i]);
+ }
+ writer.WriteEndElement();
+ EndElementCallbacks("implements", implementedContracts);
+ }
+
+ private void WriteLibraryReference(Module module) {
+ AssemblyNode assembly = module.ContainingAssembly;
+ writer.WriteStartElement("library");
+ WriteStringAttribute("assembly", assembly.Name);
+ WriteStringAttribute("module", module.Name);
+ WriteStringAttribute("kind", module.Kind.ToString());
+ writer.WriteEndElement();
+ }
+
+ private void WriteLiteral(Literal literal) {
+ WriteLiteral(literal, true);
+ }
+
+ private void WriteLiteral(Literal literal, bool showType) {
+ TypeNode type = literal.Type;
+ Object value = literal.Value;
+ if (showType) WriteTypeReference(type);
+ if (value == null) {
+ writer.WriteElementString("nullValue", String.Empty);
+ } else {
+ if (type.NodeType == NodeType.EnumNode) {
+ EnumNode enumeration = (EnumNode)type;
+ FieldList fields = GetAppliedFields(enumeration, Convert.ToInt64(value));
+ writer.WriteStartElement("enumValue");
+ for (int i = 0; i < fields.Count; i++) {
+ writer.WriteStartElement("field");
+ writer.WriteAttributeString("name", fields[i].Name.Name);
+ writer.WriteEndElement();
+ }
+ writer.WriteEndElement();
+ } else if (type.FullName == "System.Type") {
+ writer.WriteStartElement("typeValue");
+ WriteTypeReference((TypeNode)value);
+ writer.WriteEndElement();
+ } else {
+ string text = value.ToString();
+ if (!IsValidXmlText(text)) text = String.Empty;
+ writer.WriteElementString("value", text);
+ }
+ }
+ }
+
+
+ private void WriteMember(Member member, TypeNode type) {
+ //writer.WriteStartElement("api");
+ //writer.WriteAttributeString("id", namer.GetMemberName(member));
+ //Console.WriteLine("member: {0}", namer.GetMemberName(member));
+
+ WriteApiData(member);
+ WriteMemberData(member);
+
+ SecurityAttributeList securityAttributes = new SecurityAttributeList();
+ switch (member.NodeType) {
+ case NodeType.Field:
+ Field field = (Field)member;
+ WriteFieldData(field);
+ WriteValue(field.Type);
+ // write enumeration field values; expand later to all literal field values?
+ if (field.DeclaringType.NodeType == NodeType.EnumNode) {
+ WriteLiteral(new Literal(field.DefaultValue.Value, ((EnumNode)field.DeclaringType).UnderlyingType), false);
+ }
+ break;
+ case NodeType.Method:
+ Method method = (Method)member;
+ WriteMethodData(method);
+
+ // write the templates node with either the generic template params or the specialized template arguments
+ if (method.TemplateArguments != null)
+ WriteSpecializedTemplateArguments(method.TemplateArguments);
+ else
+ WriteGenericParameters(method.TemplateParameters);
+
+ WriteParameters(method.Parameters);
+ WriteValue(method.ReturnType);
+ WriteImplementedMembers(ReflectionUtilities.GetImplementedMethods(method));
+
+ if (method.SecurityAttributes != null) securityAttributes = method.SecurityAttributes;
+ break;
+ case NodeType.Property:
+ Property property = (Property)member;
+ WritePropertyData(property);
+ WriteParameters(property.Parameters);
+ WriteValue(property.Type);
+ WriteImplementedMembers(ReflectionUtilities.GetImplementedProperties(property));
+ break;
+ case NodeType.Event:
+ Event trigger = (Event)member;
+ WriteEventData(trigger);
+ WriteImplementedMembers(ReflectionUtilities.GetImplementedEvents(trigger));
+ break;
+ case NodeType.InstanceInitializer:
+ case NodeType.StaticInitializer:
+ Method constructor = (Method)member;
+ WriteParameters(constructor.Parameters);
+ break;
+
+ }
+
+ WriteMemberContainers(member, type);
+
+ WriteAttributes(member.Attributes, securityAttributes);
+
+ //writer.WriteEndElement();
+ }
+
+ private void WriteMemberContainers(Member member, TypeNode type) {
+ writer.WriteStartElement("containers");
+ WriteLibraryReference(type.DeclaringModule);
+ WriteNamespaceReference(GetNamespace(type));
+ WriteTypeReference(type);
+ writer.WriteEndElement();
+ }
+
+ // Member data
+
+ private void WriteMemberData(Member member) {
+
+ writer.WriteStartElement("memberdata");
+
+ WriteStringAttribute("visibility", GetVisibility(member));
+ WriteBooleanAttribute("static", member.IsStatic, false);
+ WriteBooleanAttribute("special", member.IsSpecialName, false);
+
+ // check overload status
+ // don't do this anymore: overload is a doc model concept and may be need to be tweaked afer versioning
+
+ WriteBooleanAttribute("default", ReflectionUtilities.IsDefaultMember(member), false);
+
+ StartElementCallbacks("memberdata", member);
+
+ EndElementCallbacks("memberdata", member);
+ writer.WriteEndElement();
+ }
+
+ private void WriteMethodData(Method method) {
+
+ WriteProcedureData(method, method.OverriddenMember);
+
+ // writer.WriteStartElement("methoddata");
+ // writer.WriteEndElement();
+ }
+
+ private void WriteNamespace(Namespace space) {
+ writer.WriteStartElement("api");
+ writer.WriteAttributeString("id", namer.GetNamespaceName(space));
+ StartElementCallbacks("api", space);
+
+ WriteApiData(space);
+ WriteNamespaceElements(space);
+
+ EndElementCallbacks("api", space);
+ writer.WriteEndElement();
+ }
+
+ // Members
+
+ private void WriteNamespaceElements(Namespace space) {
+ TypeNodeList types = space.Types;
+ if (types.Count == 0) return;
+ writer.WriteStartElement("elements");
+ for (int i = 0; i < types.Count; i++) {
+ TypeNode type = types[i];
+ //skip hidden types, but if a type is not exposed and has exposed members we must add it
+ if (!ApiFilter.IsExposedType(type) && !ApiFilter.HasExposedMembers(type)) continue;
+ writer.WriteStartElement("element");
+ writer.WriteAttributeString("api", namer.GetTypeName(type));
+ writer.WriteEndElement();
+ }
+ writer.WriteEndElement();
+ }
+
+ private void WriteNamespaceReference(Namespace space) {
+ writer.WriteStartElement("namespace");
+ writer.WriteAttributeString("api", namer.GetNamespaceName(space));
+ writer.WriteEndElement();
+ }
+
+ private void WriteNamespaces(NamespaceList spaces) {
+ // This is a part of the doc model; don't do this anymore
+ }
+
+ private void WriteParameter(Parameter parameter) {
+ writer.WriteStartElement("parameter");
+ writer.WriteAttributeString("name", parameter.Name.Name);
+ // writer.WriteAttributeString("type", namer.GetTypeName(parameter.Type));
+ if (parameter.IsIn) WriteBooleanAttribute("in", true);
+ if (parameter.IsOut) WriteBooleanAttribute("out", true);
+ if (GetParamArrayAttribute(parameter) != null) WriteBooleanAttribute("params", true);
+ WriteTypeReference(parameter.Type);
+ if (parameter.IsOptional && parameter.DefaultValue != null) WriteExpression(parameter.DefaultValue);
+ writer.WriteEndElement();
+ }
+
+ // Parameters
+
+ private void WriteParameters(ParameterList parameters) {
+ if (parameters.Count == 0) return;
+ writer.WriteStartElement("parameters");
+ for (int i = 0; i < parameters.Count; i++) {
+ WriteParameter(parameters[i]);
+ }
+ writer.WriteEndElement();
+ }
+
+ private void WriteProcedureData(Method method, Member overrides) {
+ writer.WriteStartElement("proceduredata");
+
+ WriteBooleanAttribute("abstract", method.IsAbstract, false);
+ WriteBooleanAttribute("virtual", method.IsVirtual);
+ WriteBooleanAttribute("final", method.IsFinal, false);
+
+ if (method.IsPrivate && method.IsVirtual) WriteBooleanAttribute("eii", true);
+
+ writer.WriteEndElement();
+
+ if (overrides != null) {
+ writer.WriteStartElement("overrides");
+ WriteMemberReference(overrides);
+ // WriteStringAttribute("overrides", namer.GetMemberName(overrides));
+ writer.WriteEndElement();
+ }
+
+ }
+
+ private void WritePropertyData(Property property) {
+
+ string property_visibility = GetVisibility(property);
+
+ Method getter = property.Getter;
+ Method setter = property.Setter;
+
+ Method accessor = getter;
+ if (accessor == null) accessor = setter;
+
+ // procedure data
+ WriteProcedureData(accessor, property.OverriddenMember);
+
+ // property data
+ writer.WriteStartElement("propertydata");
+ if (getter != null) {
+ WriteBooleanAttribute("get", true);
+ string getter_visibility = GetVisibility(getter);
+
+ if (getter_visibility != property_visibility) WriteStringAttribute("get-visibility", getter_visibility);
+ }
+ if (setter != null) {
+ WriteBooleanAttribute("set", true);
+ string setter_visibility = GetVisibility(setter);
+ if (setter_visibility != property_visibility) WriteStringAttribute("set-visibility", setter_visibility);
+ }
+ writer.WriteEndElement();
+
+ if (getter != null)
+ {
+ writer.WriteStartElement("getter");
+ WriteStringAttribute("name", string.Format("get_{0}", property.Name.Name));
+
+ WriteAttributes(getter.Attributes, getter.SecurityAttributes);
+ writer.WriteEndElement();
+ }
+ if (setter != null)
+ {
+ writer.WriteStartElement("setter");
+ WriteStringAttribute("name", string.Format("set_{0}", property.Name.Name.ToString()));
+
+ WriteAttributes(setter.Attributes, setter.SecurityAttributes);
+ writer.WriteEndElement();
+ }
+ }
+
+ private void WriteStartTypeReference(TypeNode type) {
+ switch (type.NodeType) {
+ case NodeType.ArrayType:
+ ArrayType array = type as ArrayType;
+ writer.WriteStartElement("arrayOf");
+ writer.WriteAttributeString("rank", array.Rank.ToString());
+ WriteTypeReference(array.ElementType);
+ // writer.WriteEndElement();
+ break;
+ case NodeType.Reference:
+ Reference reference = type as Reference;
+ writer.WriteStartElement("referenceTo");
+ WriteTypeReference(reference.ElementType);
+ // writer.WriteEndElement();
+ break;
+ case NodeType.Pointer:
+ Pointer pointer = type as Pointer;
+ writer.WriteStartElement("pointerTo");
+ WriteTypeReference(pointer.ElementType);
+ // writer.WriteEndElement();
+ break;
+ case NodeType.OptionalModifier:
+ TypeModifier optionalModifierClause = type as TypeModifier;
+ WriteStartTypeReference(optionalModifierClause.ModifiedType);
+ writer.WriteStartElement("optionalModifier");
+ WriteTypeReference(optionalModifierClause.Modifier);
+ writer.WriteEndElement();
+ break;
+ case NodeType.RequiredModifier:
+ TypeModifier requiredModifierClause = type as TypeModifier;
+ WriteStartTypeReference(requiredModifierClause.ModifiedType);
+ writer.WriteStartElement("requiredModifier");
+ WriteTypeReference(requiredModifierClause.Modifier);
+ writer.WriteEndElement();
+ break;
+ default:
+ if (type.IsTemplateParameter) {
+ ITypeParameter gtp = (ITypeParameter)type;
+ writer.WriteStartElement("template");
+ writer.WriteAttributeString("name", type.Name.Name);
+ writer.WriteAttributeString("index", gtp.ParameterListIndex.ToString());
+ writer.WriteAttributeString("api", namer.GetApiName(gtp.DeclaringMember));
+ // writer.WriteEndElement();
+ } else {
+ writer.WriteStartElement("type");
+
+ if (type.IsGeneric) {
+ TypeNode template = ReflectionUtilities.GetTemplateType(type);
+ writer.WriteAttributeString("api", namer.GetTypeName(template));
+ WriteBooleanAttribute("ref", !template.IsValueType);
+
+ // record specialization
+ TypeNodeList arguments = type.TemplateArguments;
+ if ((arguments != null) && (arguments.Count > 0)) {
+ writer.WriteStartElement("specialization");
+ // writer.WriteAttributeString("of", namer.GetTypeName(currentTemplate));
+ for (int i = 0; i < arguments.Count; i++) {
+ WriteTypeReference(arguments[i]);
+ }
+ writer.WriteEndElement();
+ }
+
+ } else {
+ writer.WriteAttributeString("api", namer.GetTypeName(type));
+ WriteBooleanAttribute("ref", !type.IsValueType);
+ }
+
+ // record outer types (because they may be specialized, and otherwise that information is lost)
+ if (type.DeclaringType != null) WriteTypeReference(type.DeclaringType);
+
+ }
+ break;
+ }
+ }
+
+ private void WriteStringAttribute(string attribute, string value) {
+ writer.WriteAttributeString(attribute, value);
+ }
+
+ private void WriteType(TypeNode type) {
+ writer.WriteStartElement("api");
+ writer.WriteAttributeString("id", namer.GetTypeName(type));
+ StartElementCallbacks("api", type);
+
+ WriteApiData(type);
+ WriteTypeData(type);
+
+ switch (type.NodeType) {
+ case NodeType.Class:
+ case NodeType.Struct:
+ WriteGenericParameters(type.TemplateParameters);
+ WriteInterfaces(type.Interfaces);
+ WriteTypeElements(type);
+ break;
+ case NodeType.Interface:
+ WriteGenericParameters(type.TemplateParameters);
+ WriteInterfaces(type.Interfaces);
+ WriteImplementors((Interface)type);
+ WriteTypeElements(type);
+ break;
+ case NodeType.DelegateNode:
+ DelegateNode handler = (DelegateNode)type;
+ WriteGenericParameters(handler.TemplateParameters);
+ WriteParameters(handler.Parameters);
+ WriteValue(handler.ReturnType);
+ break;
+ case NodeType.EnumNode:
+ WriteEnumerationData((EnumNode)type);
+ WriteTypeElements(type);
+ break;
+ }
+
+ WriteTypeContainers(type);
+
+ WriteAttributes(type.Attributes, type.SecurityAttributes);
+
+ EndElementCallbacks("api", type);
+ writer.WriteEndElement();
+
+ }
+
+ private void WriteTypeContainers(TypeNode type) {
+
+ writer.WriteStartElement("containers");
+ WriteLibraryReference(type.DeclaringModule);
+ WriteNamespaceReference(GetNamespace(type));
+
+ // for nested types, record outer types
+ TypeNode outer = type.DeclaringType;
+ if (outer != null) WriteTypeReference(outer);
+
+ writer.WriteEndElement();
+
+ }
+
+ // Type data
+
+ private void WriteTypeData(TypeNode type) {
+ writer.WriteStartElement("typedata");
+
+ // data for all types
+ WriteStringAttribute("visibility", GetVisibility(type));
+ WriteBooleanAttribute("abstract", type.IsAbstract, false);
+ WriteBooleanAttribute("sealed", type.IsSealed, false);
+ WriteBooleanAttribute("serializable", (type.Flags & TypeFlags.Serializable) != 0);
+
+ // interop data
+ TypeFlags layout = type.Flags & TypeFlags.LayoutMask;
+ switch (layout) {
+ case TypeFlags.AutoLayout:
+ WriteStringAttribute("layout", "auto");
+ break;
+ case TypeFlags.SequentialLayout:
+ WriteStringAttribute("layout", "sequential");
+ break;
+ case TypeFlags.ExplicitLayout:
+ WriteStringAttribute("layout", "explicit");
+ break;
+ }
+ TypeFlags format = type.Flags & TypeFlags.StringFormatMask;
+ switch (format) {
+ case TypeFlags.AnsiClass:
+ WriteStringAttribute("format", "ansi");
+ break;
+ case TypeFlags.UnicodeClass:
+ WriteStringAttribute("format", "unicode");
+ break;
+ case TypeFlags.AutoClass:
+ WriteStringAttribute("format", "auto");
+ break;
+ }
+ // also import
+
+ StartElementCallbacks("typedata", type);
+
+
+ EndElementCallbacks("typedata", type);
+ writer.WriteEndElement();
+
+ // for classes, recored base type
+ if (type is Class) {
+ WriteHierarchy(type);
+ // TypeNode parent = type.BaseType;
+ // if (parent != null) WriteStringAttribute("parent", namer.GetTypeName(parent));
+ }
+
+ }
+
+ private void WriteTypeElements(TypeNode type) {
+
+ // collect members
+ MemberDictionary members = new MemberDictionary(type, this.ApiFilter);
+ if (members.Count == 0) return;
+
+ writer.WriteStartElement("elements");
+ StartElementCallbacks("elements", members);
+
+ foreach (Member member in members) {
+ writer.WriteStartElement("element");
+
+ Member template = ReflectionUtilities.GetTemplateMember(member);
+ writer.WriteAttributeString("api", namer.GetMemberName(template));
+
+ bool write = false;
+
+ // inherited, specialized generics get a displayed target different from the target
+ // we also write out their info, since it can't be looked up anywhere
+ if (!member.DeclaringType.IsStructurallyEquivalentTo(template.DeclaringType)) {
+ writer.WriteAttributeString("display-api", namer.GetMemberName(member));
+ write = true;
+ }
+
+ // if a member is from a type in a dependency assembly, write out its info, since it can't be looked up in this file
+ if (!assemblyNames.ContainsKey(member.DeclaringType.DeclaringModule.ContainingAssembly.StrongName)) write = true;
+ // if (Array.BinarySearch(assemblyNames, member.DeclaringType.DeclaringModule.ContainingAssembly.Name) < 0) write = true;
+
+ if (write) WriteMember(member);
+
+ writer.WriteEndElement();
+ }
+
+ EndElementCallbacks("elements", members);
+ writer.WriteEndElement();
+
+ }
+
+ // Return value or property value or field value
+
+ private void WriteValue(TypeNode type) {
+ if (type.FullName == "System.Void") return;
+ writer.WriteStartElement("returns");
+ WriteTypeReference(type);
+ // writer.WriteAttributeString("type", namer.GetTypeName(type));
+ writer.WriteEndElement();
+ }
+
+ }
+
+}