diff options
Diffstat (limited to 'tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs')
-rw-r--r-- | tools/Sandcastle/Source/MRefBuilder/MRefWriter.cs | 1316 |
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(); + } + + } + +} |