// Copyright (c) Microsoft Corporation. All rights reserved.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Compiler;
namespace Microsoft.Ddue.Tools.Reflection{
public class ApiVisitor : IDisposable {
private static Comparison < Member > memberComparison = new Comparison < Member >(CompareMembers);
// Sorting logic
private static Comparison < Namespace > namespaceComparison = new Comparison < Namespace >(CompareMembers);
private static Comparison < TypeNode > typeComparison = new Comparison < TypeNode >(CompareMembers);
private List < AssemblyNode > accessoryAssemblies = new List < AssemblyNode >();
// Disposal logic
private List < AssemblyNode > assemblies = new List < AssemblyNode >();
// object model store
private Dictionary < string, Namespace > catalog = new Dictionary < string, Namespace >();
private ApiFilter filter;
// Keep track of any metadata load errors
private Dictionary < string, Exception > loadErrors = new Dictionary < string, Exception >();
// Revised assembly storage
private AssemblyResolver resolver = new AssemblyResolver();
protected ApiVisitor(ApiFilter filter) {
this.filter = filter;
}
protected ApiVisitor() : this(new NoFilter()) { }
public AssemblyNode[] AccessoryAssemblies {
get {
return (accessoryAssemblies.ToArray());
}
}
public ApiFilter ApiFilter {
get {
return (filter);
}
set {
filter = value;
}
}
public AssemblyNode[] Assemblies {
get {
return (assemblies.ToArray());
}
}
public Dictionary < string, Exception > LoadErrors {
get {
return (loadErrors);
}
}
public AssemblyResolver Resolver {
get {
return (resolver);
}
set {
resolver = value;
}
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
foreach (AssemblyNode assembly in assemblies) {
// Console.WriteLine(loadedModule.Name);
assembly.Dispose();
}
foreach (AssemblyNode accessoryAssembly in accessoryAssemblies) {
accessoryAssembly.Dispose();
}
}
}
public void LoadAccessoryAssemblies(string filePattern) {
// get the full path to the relevent directory
string directoryPath = Path.GetDirectoryName(filePattern);
if ((directoryPath == null) || (directoryPath.Length == 0)) directoryPath = Environment.CurrentDirectory;
directoryPath = Path.GetFullPath(directoryPath);
// get the file name, which may contain wildcards
string filePath = Path.GetFileName(filePattern);
// look up the files and load them
string[] files = Directory.GetFiles(directoryPath, filePath);
foreach (string file in files) {
LoadAccessoryAssembly(file);
}
}
// Accessory modules
//private IDictionary cache = new Hashtable();
public void LoadAccessoryAssembly(string filePath) {
AssemblyNode assembly = AssemblyNode.GetAssembly(filePath, null, false, false, false, false); // this causes non-classes to register as classes
if (assembly != null) {
if (assembly.Name == "mscorlib") ResetMscorlib(assembly);
resolver.Add(assembly);
//assembly.AssemblyReferenceResolutionAfterProbingFailed += unresolvedModuleHandler;
accessoryAssemblies.Add(assembly);
}
}
public void LoadAssemblies(string filePattern) {
// get the full path to the relevent directory
string directoryPath = Path.GetDirectoryName(filePattern);
if ((directoryPath == null) || (directoryPath.Length == 0)) directoryPath = Environment.CurrentDirectory;
directoryPath = Path.GetFullPath(directoryPath);
// get the file name, which may contain wildcards
string filePath = Path.GetFileName(filePattern);
// look up the files and load them
string[] files = Directory.GetFiles(directoryPath, filePath);
foreach (string file in files) {
LoadAssembly(file);
}
}
// Parsing logic
public void LoadAssembly(string filePath) {
//Console.WriteLine("loading {0}", filePath);
//AssemblyNode assembly = AssemblyNode.GetAssembly(filePath); // this causes mscorlib to be missing members
//AssemblyNode assembly = AssemblyNode.GetAssembly(filePath, cache); // this causes compact framework non-classes to register as classes
//AssemblyNode assembly = AssemblyNode.GetAssembly(filePath, cache, false, false, true, false); // this causes missing mscorlib members
//AssemblyNode assembly = AssemblyNode.GetAssembly(filePath, cache, false, false, false, false); // this causes non-classes to register as classes
//AssemblyNode assembly = AssemblyNode.GetAssembly(filePath, null, false, false, true, false); // this causes missing mscorlib members
AssemblyNode assembly = AssemblyNode.GetAssembly(filePath, null, false, false, false, false); // this causes non-classes to register as classes
if (assembly != null) {
if (assembly.Name == "mscorlib") ResetMscorlib(assembly);
// Console.WriteLine("assembly = {0}", assembly.Name);
resolver.Add(assembly);
//assembly.AssemblyReferenceResolutionAfterProbingFailed += unresolvedModuleHandler;
assemblies.Add(assembly);
//Console.WriteLine("{0} has {1} types", assembly.Name, assembly.ExportedTypes.Count);
//StoreTypes(assembly.Types);
}
}
// Visit Object Model
public void VisitApis() {
// store types
// we have to do this after all assemblies are registered because the resolution may not work unless
// all the assemblies we need are in the resolver cache
//Console.WriteLine("storing types");
foreach (AssemblyNode assembly in assemblies) {
//Console.WriteLine("assembly {0}", assembly.Name);
//Console.WriteLine("has {0} types", assembly.Types.Count);
StoreTypes(assembly.Types);
//Console.WriteLine("done with assembly");
}
//Console.WriteLine("done storing types");
//Console.WriteLine("visiting namespaces");
NamespaceList spaces = new NamespaceList();
foreach (Namespace space in catalog.Values) {
if (filter.IsExposedNamespace(space)) spaces.Add(space);
}
VisitNamespaces(spaces);
}
protected virtual void VisitEntity(Member entity) {
// inherit and insert logic here
}
protected virtual void VisitMember(Member member) {
VisitEntity(member);
}
protected virtual void VisitMembers(MemberList members) {
// sort members by name
Member[] sorted_members = new Member[members.Count];
for (int i = 0; i < members.Count; i++) sorted_members[i] = members[i];
Array.Sort < Member >(sorted_members, memberComparison);
// visit them
foreach (Member member in sorted_members) {
// don't visit nested types, as they are already visited
if (member is TypeNode) continue;
if (filter.IsExposedMember(member))
{
VisitMember(member);
}
}
}
protected virtual void VisitNamespace(Namespace space) {
//Console.WriteLine("Visit Entity {0}",space.FullName);
VisitEntity(space);
TypeNodeList types = space.Types;
VisitTypes(types);
}
protected virtual void VisitNamespaces(NamespaceList spaces) {
// sort namespaces by name
Namespace[] sorted_spaces = new Namespace[spaces.Count];
for (int i = 0; i < spaces.Count; i++) sorted_spaces[i] = spaces[i];
Array.Sort < Namespace >(sorted_spaces, namespaceComparison);
// visit them
foreach (Namespace space in sorted_spaces) {
if (filter.IsExposedNamespace(space)) VisitNamespace(space);
}
}
protected virtual void VisitType(TypeNode type) {
//Console.WriteLine(type.FullName);
VisitEntity(type);
MemberList members = type.Members;
//Console.WriteLine("{0}: {1}", type.FullName, members.Length);
VisitMembers(members);
}
protected virtual void VisitTypes(TypeNodeList types) {
// sort types by name
TypeNode[] sorted_types = new TypeNode[types.Count];
for (int i = 0; i < types.Count; i++) sorted_types[i] = types[i];
Array.Sort < TypeNode >(sorted_types, typeComparison);
// visit them
foreach (TypeNode type in sorted_types) {
//Console.WriteLine("visiting {0}", type.Name);
//visit this type if it is exposed, or has members that are set as exposed
if (filter.IsExposedType(type) || filter.HasExposedMembers(type))
VisitType(type); //visit type and members
}
}
private static int CompareMembers(Member a, Member b) {
return (String.Compare(a.FullName, b.FullName));
}
private static int CompareNamespaces(Namespace a, Namespace b) {
return (String.Compare(a.Name.Name, b.Name.Name));
}
private static int CompareTypes(TypeNode a, TypeNode b) {
return (String.Compare(a.Name.Name, b.Name.Name));
}
private static string GetNamespaceName(TypeNode type) {
TypeNode parent = type.DeclaringType;
if (parent != null) {
return (GetNamespaceName(parent));
} else {
if (type.Namespace == null) {
return (String.Empty);
} else {
return (type.Namespace.Name);
}
}
}
private void ResetMscorlib(AssemblyNode assembly) {
TargetPlatform.Clear();
CoreSystemTypes.Clear();
CoreSystemTypes.SystemAssembly = assembly;
CoreSystemTypes.Initialize(true, false);
}
private void StoreType(TypeNode type) {
//Console.WriteLine("type: {0} ", type.Name);
/*
if (type.Name == null) {
// CCI seems to occasionally construct corrupted, phantom types, which we should reject
// Console.WriteLine("unidentified type rejected");
return;
}
*/
string spaceName = GetNamespaceName(type);
//Console.WriteLine("in space: {0}", spaceName);
Namespace space;
if (!catalog.TryGetValue(spaceName, out space)) {
space = new Namespace(new Identifier(spaceName));
catalog.Add(spaceName, space);
}
if (space.Types == null) Console.WriteLine("null type list");
space.Types.Add(type);
//Console.WriteLine("getting members");
MemberList members = type.Members;
//Console.WriteLine("got {0} members", members.Count);
for (int i = 0; i < members.Count; i++) {
TypeNode nestedType = members[i] as TypeNode;
if (nestedType != null) {
//Console.WriteLine("nested type {0}", type.FullName);
StoreType(nestedType);
}
}
//Console.WriteLine("done storing type");
}
private void StoreTypes(TypeNodeList types) {
//Console.WriteLine("{0} types", types.Length);
for (int i = 0; i < types.Count; i++) {
StoreType(types[i]);
}
}
}
}
|