// 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();
}
}
}
|