MRefWriter.cs :  » Development » Sandcastle » Microsoft » Ddue » Tools » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » Sandcastle 
Sandcastle » Microsoft » Ddue » Tools » MRefWriter.cs
// 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();
        }

    }

}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.