singrdk/base/Windows/RefGraph/refgraph.sg

1314 lines
41 KiB
Plaintext

// ----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ----------------------------------------------------------------------------
using System;
using System.IO;
using System.Xml;
using System.Compiler;
using System.Collections;
using Microsoft.SpecSharp.Collections;
using Microsoft.Contracts;
public class Test{
public static bool oneLine = false;
public static bool staticsOnly = false;
public static bool verbose = false;
public static bool outputXml = false;
public static bool outputLogicalModulesOnly = false;
public static bool outputTypesOnly = false;
public static string outputFileName;
public static ArrayList! fileList = new ArrayList();
static Hashtable! referenceAssemblyCache = new Hashtable();
public static int Main(string[] args){
string[]! nargs = (string[]!)args;
bool needHelp = false;
bool firstModuleOverridesStdLib = false;
if (nargs.Length == 0) {
Usage();
return 0;
}
RefGraph rg = new RefGraph();
// Process flags first
foreach (string! file in nargs) {
if (file.Length >= 2 && (file[0] == '/' || file[0] == '-')) {
switch (file[1]) {
case 'b':
System.Diagnostics.Debugger.Break();
break;
case '?':
case 'h':
case 'H':
needHelp = true;
break;
case 'l':
case 'L':
oneLine = true;
assert outputXml == false;
break;
case 'm':
case 'M':
outputLogicalModulesOnly = true;
break;
case 'n':
case 'N':
firstModuleOverridesStdLib = true;
break;
case 'o':
case 'O':
outputFileName = file.Substring(3);
break;
case 's':
case 'S':
staticsOnly = true;
break;
case 't':
case 'T':
outputTypesOnly = true;
break;
case 'v':
case 'V':
verbose = true;
break;
case 'x':
case 'X':
outputXml = true;
assert oneLine == false;
break;
default:
needHelp = true;
break;
}
}
else {
fileList.Add(file);
}
}
if (needHelp || fileList.Count == 0) {
Usage();
return 0;
}
// Now process files
string lastModuleName = null;
ArrayList assemblies = new ArrayList();
foreach (object! fileObj in fileList) {
string file = (string) fileObj;
string fullpath = Path.GetFullPath(file);
lastModuleName = Path.GetFileNameWithoutExtension(file);
if (firstModuleOverridesStdLib) {
string dir = Path.GetDirectoryName(fullpath);
SystemTypes.Initialize(false, false);
SystemTypes.Clear();
TargetPlatform.SetToV1_1(dir);
SystemAssemblyLocation.Location = fullpath;
SystemCompilerRuntimeAssemblyLocation.Location =
Path.Combine(dir, "System.Compiler.Runtime.dll");
SystemTypes.Initialize(true, true);
// So we don't try to override it again (once is enough)
firstModuleOverridesStdLib = false;
}
if (verbose) {
Console.WriteLine("Scanning: " + file);
}
AssemblyNode assembly = AssemblyNode.GetAssembly(fullpath, referenceAssemblyCache, true, true, true);
assert assembly != null;
assert assembly.Name != null;
referenceAssemblyCache[assembly.Name] = assembly;
assembly.AssemblyReferenceResolution += new Module.AssemblyReferenceResolver(ResolveAssemblyReference);
assemblies.Add(assembly);
}
foreach (object! assemblyObj in assemblies) {
AssemblyNode m = assemblyObj as AssemblyNode;
rg.Visit(m);
}
rg.FixNamespaceKeys();
if (Console.Out != null) {
if (outputXml) {
if (outputFileName == null) outputFileName = lastModuleName;
TextWriter tw;
if (outputFileName != null) {
if (!outputLogicalModulesOnly) {
tw = new StreamWriter(outputFileName + ".dependencies.xml");
}
else {
tw = new StreamWriter(outputFileName + ".logical_modules.xml");
}
}
else {
tw = (TextWriter)Console.Out;
}
XmlDocument doc;
doc = rg.DumpAllDependenciesToXml();
assert doc != null;
doc.Save(tw);
if (tw != Console.Out) {
tw.Close();
}
}
else {
rg.Dump(Console.Out);
}
}
return 0;
}
/// <summary>
/// This method is here to avoid referencing assemblies we haven't mentioned on the command line.
/// </summary>
/// <returns>A dummy replacement assembly</returns>
private static AssemblyNode ResolveAssemblyReference( AssemblyReference assemblyReference,
Module fromModule) {
assert assemblyReference != null;
assert fromModule != null;
assert System.Console.Error != null;
//System.Console.Error.WriteLine("Assembly reference resolver called on {0} from {1}.\n",
// assemblyReference.Name,
// fromModule.Location);
assert assemblyReference.Name != null;
string referencedAssemblyName = assemblyReference.Name;
if (referencedAssemblyName.ToLower() == "hal") {
referencedAssemblyName = "Hal.LegacyPC";
}
AssemblyNode assembly = (AssemblyNode) referenceAssemblyCache[referencedAssemblyName];
if (assembly != null) {
return assembly;
}
//foreach(object key in referenceAssemblyCache.Keys) {
//
// AssemblyNode val = (AssemblyNode) referenceAssemblyCache[key];
//
// assert val != null;
//
// System.Console.Error.WriteLine("Key: " + key);
// System.Console.Error.WriteLine("Val: " + val.Location);
//}
// HACK until we provide renaming of references on command line
referencedAssemblyName = referencedAssemblyName.ToLower();
if (referencedAssemblyName == "kernel" ||
referencedAssemblyName == "mscorlib" ||
referencedAssemblyName == "corlib" ||
referencedAssemblyName == "basetypes" ||
referencedAssemblyName == "baseattrs" ||
referencedAssemblyName == "ioconfig" ||
referencedAssemblyName == "console"
)
{
return SystemTypes.SystemAssembly;
}
assembly = new AssemblyNode();
assembly.Culture = assemblyReference.Culture;
assembly.Name = assemblyReference.Name;
assembly.PublicKeyOrToken = assemblyReference.PublicKeyOrToken;
assembly.Version = assemblyReference.Version;
assembly.Location = "unknown:location";
//System.Diagnostics.Debugger.Break();
System.Console.Error.WriteLine("Failed to resolve assembly reference '" +
assemblyReference.Name + "' from module '" + fromModule.Location + "'.");
return assembly;
}
public static void Usage()
{
Console.Write(
"Usage:\n" +
" refgraph [options] <assemblies>\n" +
"Options:\n" +
" /b -- Break into the debugger on startup.\n" +
" /l -- Format one-line output for findstr or grep.\n" +
" /m -- Output template for assigning logical modules to\n" +
" types and members.\n" +
" /n -- Uses the first assembly as the standard library\n" +
" instead of mscorlib.dll.\n" +
" /o:name -- use name as the base for the output files (/m or /x\n" +
" options).\n" +
" /s -- Only consider static references (non instance based).\n" +
" /t -- Only output types.\n" +
" /v -- Output diagnostic messages.\n" +
" /x -- Output xml.\n" +
" /? -- Display this help screen.\n" +
"Summary:\n" +
" Dumps the graph of cross references for each type.\n"
);
}
}
interface IDump {
void Dump(TextWriter! tr);
}
enum DeclKind
{
Assembly,
Namespace,
Type,
Method,
Field,
Enum,
Delegate
}
[Flags]
enum DepKind
{
baseClass = 1,
iface = 2,
sig = 4,
code = 8,
attr = 16,
};
class Dep
{
public Decl! decl;
public DepKind kind;
public Dep(Decl! decl, DepKind kind)
{
this.decl = decl;
this.kind = kind;
}
[Microsoft.Contracts.Confined]
public override string! ToString() {
string blah = decl + " (" + KindString() + ")";
assert blah != null;
return blah;
}
public string! KindString() {
if (kind == DepKind.baseClass)
return "base";
else
return (string!) kind.ToString();
}
public XmlElement! CreateXmlElement(XmlDocument! doc)
{
XmlElement elem = doc.CreateElement("Dep");
assert elem != null;
Decl.DumpXmlRef(decl, "DepDeclId", elem);
elem.SetAttribute("Kind", KindString());
return elem;
}
}
// A decl can be a namespace, type, method, or field
class Decl
{
// Name of the namespace, type, method, or field
string! fullName;
string nameSpace; // optional
string! shortName;
string path = null;
public int key;
public bool hasFullInfo = false;
public bool alreadyOutput = false;
public static int largestKey = 0;
// Only used by members
bool isStatic = false;
bool isOverride = false;
string access = null;
// Only used by methods
bool isConditional = false;
bool isAbstract = false;
// Only used by fields
bool isConst = false;
// Scope of this decl. For example, the scope of a method
// or field decl is the enclosing type. The scope of a class
// decl is a namespace or nested class decl.
public Decl lexicalScope = null;
// Decls this decl depends on. For a method, the decls are
// the return and parameter types. For a field, the decl is
// the field type. For a class, the decl is the base type
// and interface types. A namespace decl has no dependencies.
public ArrayList/*<Dep>*/ dependencies = new ArrayList/*<Dep>*/();
// The kind of decl this is: namespace, type, method, or field
public DeclKind kind;
static char[]! refDesignators = new char[] { '*', '@', '[' };
public Decl(string! fullName, string nameSpace, string! shortName, int key, DeclKind kind)
{
this.fullName = fullName;
this.shortName = shortName;
this.nameSpace = nameSpace;
this.key = key;
this.kind = kind;
if (key > largestKey)
largestKey = key;
}
[Microsoft.Contracts.Confined]
public override bool Equals(object rhs) {
Decl declRhs = rhs as Decl;
if (declRhs == null)
return false;
return Equals(declRhs);
}
[Microsoft.Contracts.Confined]
public bool Equals(Decl rhs) {
if (rhs == null)
return false;
return this.key == rhs.key;
}
[Microsoft.Contracts.Confined]
public override string! ToString()
{
string blah = shortName + " (" + kind.ToString() + ")" + (hasFullInfo ? " FULL" : "");
assert blah != null;
return blah;
}
public void Dump(TextWriter! o, int indent)
{
Indent(o, indent);
o.WriteLine(ToString());
Indent(o, indent+1);
o.Write("Scope: ");
if (lexicalScope == null)
o.WriteLine("(null)");
else {
assert lexicalScope != null;
o.WriteLine(lexicalScope);
}
assert dependencies != null;
for (int i = 0; i < dependencies.Count; ++i) {
Dep dep = dependencies[i] as Dep;
assert dep != null;
Indent(o, indent+1);
o.WriteLine("Dependency: " + dep);
}
}
public static void Indent(TextWriter! o, int indent)
{
for (int i = 0; i < indent; ++i) {
o.Write(" ");
}
}
public XmlElement! CreateXmlElement(XmlDocument! doc)
{
XmlElement elem = doc.CreateElement("Decl");
assert elem != null;
elem.SetAttribute("FullName", fullName);
if (nameSpace != null) elem.SetAttribute("Namespace", nameSpace);
elem.SetAttribute("Name", shortName);
elem.SetAttribute("Kind", kind.ToString());
elem.SetAttribute("Id", key.ToString());
if (Test.outputLogicalModulesOnly) {
elem.SetAttribute("LogicalModule", "");
return elem;
}
elem.SetAttribute("HasFullInfo", hasFullInfo.ToString());
DumpXmlRef(lexicalScope, "ScopeDeclId", elem);
if (access != null) {
elem.SetAttribute("IsStatic", isStatic.ToString());
elem.SetAttribute("Access", access);
}
if (isOverride) {
elem.SetAttribute("IsOverride", "True");
}
if (isConditional) {
elem.SetAttribute("IsConditional", "True");
}
if (isConst) {
elem.SetAttribute("IsConst", "True");
}
if (isAbstract) {
elem.SetAttribute("IsAbstract", "True");
}
if (path != null) {
elem.SetAttribute("Path", path);
}
assert dependencies != null;
for (int i = 0; i < dependencies.Count; ++i) {
Dep dep = dependencies[i] as Dep;
assert dep != null;
XmlElement depElem = dep.CreateXmlElement(doc);
elem.AppendChild(depElem);
}
return elem;
}
public static void DumpXmlRef(Decl decl, string! name, XmlElement! element)
{
if (decl == null)
element.SetAttribute(name, "");
else
element.SetAttribute(name, decl.key.ToString());
}
public void AddDependency(Decl! decl, DepKind depKind) {
assert dependencies != null;
for (int i = 0; i < dependencies.Count; ++i) {
Dep dep = dependencies[i] as Dep;
assert dep != null;
if (dep.decl.Equals(decl)) {
dep.kind |= depKind;
return;
}
}
dependencies.Add(new Dep(decl, depKind));
}
public static Decl GetOrCreateAssemblyDecl( AssemblyNode! assembly,
Hashtable! decls,
bool hasFullInfo)
{
Decl declAssembly = decls[assembly.UniqueKey] as Decl;
if (declAssembly != null) {
assert declAssembly.kind == DeclKind.Assembly;
if (!declAssembly.hasFullInfo && hasFullInfo)
declAssembly.hasFullInfo = true;
return declAssembly;
}
assert assembly.Name != null;
declAssembly = new Decl(assembly.Name, null, assembly.Name, assembly.UniqueKey, DeclKind.Assembly);
declAssembly.path = assembly.Location;
declAssembly.hasFullInfo = hasFullInfo;
decls[assembly.UniqueKey] = declAssembly;
return declAssembly;
}
[Pure]
public static bool IsType(DeclKind kind) {
switch (kind) {
case DeclKind.Type:
case DeclKind.Enum:
case DeclKind.Delegate:
return true;
default:
return false;
}
}
/// <summary>
/// Lookup or create a Decl node for this type.
/// Don't traverse anything. That will be done in the context of the corresponding
/// definition.
/// </summary>
public static Decl! GetOrCreateTypeDecl(TypeNode! typeNode,
Hashtable! decls,
Hashtable! ns_decls,
bool hasFullInfo)
{
// Should only get here for type definitions, not constructed types,
// no generic instances
assert typeNode.Template == null;
assert typeNode.IsPointerType == false;
assert typeNode.IsStructural == false;
assert !(typeNode is ArrayType);
assert !(typeNode is Reference);
assert typeNode.FullName != null;
Decl declType = decls[typeNode.UniqueKey] as Decl;
if (declType != null) {
assert IsType(declType.kind);
if (!declType.hasFullInfo && hasFullInfo) {
declType.hasFullInfo = true;
}
}
else {
// Create the node initially
string shortName = typeNode.Name.Name;
assert shortName != null;
DeclKind kind;
switch (typeNode.NodeType) {
case NodeType.DelegateNode:
kind = DeclKind.Delegate;
break;
case NodeType.EnumNode:
kind = DeclKind.Enum;
break;
default:
kind = DeclKind.Type;
break;
}
declType = new Decl(typeNode.FullName, GetMemberNamespace(typeNode), shortName, typeNode.UniqueKey, kind);
decls[typeNode.UniqueKey] = declType;
// initialize some other aspects of this Decl
declType.hasFullInfo = hasFullInfo;
// Set the scope to be the nesting class
if (typeNode.DeclaringType != null) {
declType.lexicalScope = GetDeclaringTypeDecl(typeNode.DeclaringType, decls, ns_decls);
}
else if (typeNode.DeclaringModule != null) {
assert typeNode.DeclaringModule.ContainingAssembly != null;
// Set the assembly
declType.lexicalScope = GetOrCreateAssemblyDecl(typeNode.DeclaringModule.ContainingAssembly, decls, false);
}
}
return declType;
}
private static string GetMemberNamespace(Member! m) {
return GetMemberNamespace(m.DeclaringType);
}
private static string GetMemberNamespace(TypeNode t) {
if (t == null) return null;
if (t.Namespace != null && t.Namespace.Name != null) return t.Namespace.Name;
return GetMemberNamespace(t.DeclaringType);
}
public static Decl! GetOrCreateMethodDecl(Method! method, Hashtable! decls, Hashtable! ns_decls)
{
Decl declMethod = decls[method.UniqueKey] as Decl;
if (declMethod != null) {
assert declMethod.kind == DeclKind.Method;
return declMethod;
}
string shortMethodName = method.GetUnmangledNameWithoutTypeParameters(true);
assert shortMethodName != null;
assert method.DeclaringType != null;
assert method.ReturnType != null;
assert method.ReturnType.FullName != null;
TypeNode! returnType = method.ReturnType;
if (returnType is TypeModifier)
returnType = (!) TypeNode.StripModifiers(returnType);
string fullName =
returnType.FullName + " " +
method.DeclaringType.Name.Name + "." +
method.GetUnmangledNameWithoutTypeParameters(false);
assert fullName != null;
string nameSpace = GetMemberNamespace(method);
if (!fullName.EndsWith(")"))
fullName += "()";
assert fullName != null;
declMethod = new Decl(fullName, nameSpace, shortMethodName, method.UniqueKey, DeclKind.Method);
decls[method.UniqueKey] = declMethod;
declMethod.isStatic = method.IsStatic;
declMethod.isAbstract = method.IsAbstract;
bool isConstructor = shortMethodName == "#ctor";
if ((declMethod.isStatic || isConstructor) && method.DeclaringType != null) {
// If the method is static (including static ctors) or a
// constructor, add a dependency to the static ctor
MemberList cctors = method.DeclaringType.GetMembersNamed(StandardIds.CCtor);
if (cctors != null && cctors.Count > 0) {
// Assume we can only have one static constructor
assert cctors.Count == 1;
Method cctor = cctors[0] as Method;
assert cctor != null;
Decl cctorDecl = Decl.GetOrCreateMethodDecl(cctor, decls, ns_decls);
assert cctorDecl != null;
declMethod.AddDependency(cctorDecl, DepKind.code);
}
}
if (isConstructor && method.DeclaringType != null) {
// Add a dependency from the constructor to the destructor (e.g., Finalize)
MemberList finalizers = method.DeclaringType.GetMembersNamed(StandardIds.Finalize);
if (finalizers != null && finalizers.Count > 0) {
// Asseme we can only have one Finalize method
assert finalizers.Count == 1;
Method finalizer = finalizers[0] as Method;
if (finalizer != null) {
Decl finalizerDecl = Decl.GetOrCreateMethodDecl(finalizer, decls, ns_decls);
assert finalizerDecl != null;
declMethod.AddDependency(finalizerDecl, DepKind.code);
}
}
}
if (method.IsPrivate) {
declMethod.access = "private";
}
else if (method.IsFamily ||
method.IsFamilyAndAssembly) {
declMethod.access = "protected";
}
else if (method.IsPublic ||
method.IsAssembly ||
method.IsFamilyOrAssembly ||
method.IsVisibleOutsideAssembly) {
declMethod.access = "public";
}
else if (method.IsCompilerControlled) {
// For some reason, a method like
//
// public struct DebugService {
// [CLSCompliant(false)]
// public static unsafe void PrintBegin(out char * buffer, out int length) { ... }
//
// should have IsPublic set to 'true' but it doesn't. However, it only
// appears to happen with members which are "compiler controlled" (does
// this mean 'unsafe'?)
declMethod.access = "public";
}
else {
assert System.Console.Error != null;
System.Console.Error.WriteLine("Member has unknown access: " + fullName);
declMethod.access = "public";
}
if ((method.ImplementedInterfaceMethods != null &&
method.ImplementedInterfaceMethods.Count > 0) ||
(method.ImplicitlyImplementedInterfaceMethods != null &&
method.ImplicitlyImplementedInterfaceMethods.Count > 0) ||
method.OverriddenMethod != null)
{
assert !declMethod.isStatic;
declMethod.isOverride = true;
}
assert declMethod.dependencies != null;
if (method.DeclaringType != null) {
declMethod.lexicalScope = GetDeclaringTypeDecl(method.DeclaringType, decls, ns_decls);
}
return declMethod;
}
public static Decl! GetDeclaringTypeDecl(TypeNode! declaringType, Hashtable! decls, Hashtable! ns_decls)
{
if (declaringType.Template != null) {
declaringType = declaringType.Template;
}
ArrayType at = declaringType as ArrayType;
if (at != null) {
// Special case. The runtime pretends there are methods on things like String[,] etc.
// Map this to System.Array
declaringType = (!)SystemTypes.Array;
}
return GetOrCreateTypeDecl(declaringType, decls, ns_decls, false);
}
public static Decl! GetOrCreateFieldDecl(Field! field, Hashtable! decls, Hashtable! ns_decls)
{
Decl declField = decls[field.UniqueKey] as Decl;
if (declField != null) {
assert declField.kind == DeclKind.Field;
return declField;
}
assert field.Name != null;
assert field.Name.Name != null;
assert field.DeclaringType != null;
assert field.DeclaringType.FullName != null;
string fullName = field.DeclaringType.Name.Name + "." + field.Name.Name;
assert fullName != null;
declField = new Decl(fullName, GetMemberNamespace(field), field.Name.Name, field.UniqueKey, DeclKind.Field);
decls[field.UniqueKey] = declField;
declField.isStatic = field.IsStatic;
if (field.IsPrivate) {
declField.access = "private";
}
else if (field.IsFamily ||
field.IsFamilyAndAssembly) {
declField.access = "protected";
}
else if (field.IsPublic ||
field.IsAssembly ||
field.IsFamilyOrAssembly) {
declField.access = "public";
}
else if (field.IsCompilerControlled) {
declField.access = "public";
}
else {
assert System.Console.Error != null;
System.Console.Error.WriteLine("Member has unknown access: " + fullName);
declField.access = "public";
}
assert declField.dependencies != null;
if ((field.Flags & FieldFlags.Literal) != 0) {
declField.isConst = true;
}
if (field.DeclaringType != null) {
declField.lexicalScope = GetDeclaringTypeDecl(field.DeclaringType, decls, ns_decls);
}
return declField;
}
}
class RefGraph : StandardVisitor, IDump
{
Hashtable!/*<Decl>*/ decls = new Hashtable();
Hashtable!/*<Decl>*/ ns_decls = new Hashtable();
Set<TypeNode> types = new Set<TypeNode>();
/// types referenced in signatures of the type
TrivialHashtable!/*<Set<TypeNode>>*/ inSignatures = new TrivialHashtable();
/// types referenced in code of the type
TrivialHashtable!/*<Set<TypeNode>>*/ inCode = new TrivialHashtable();
Set<TypeNode> currentSet;
Statement currentStatement;
Method currentMethod = null;
Decl currentDeclaration;
DepKind currentKind;
private void AddDependency(Decl! dep, DepKind kind) {
assert this.currentDeclaration != null;
this.currentDeclaration.AddDependency(dep, kind);
}
public override AssemblyNode VisitAssembly(AssemblyNode assem) {
if (assem == null) return null;
this.currentKind = DepKind.sig;
this.currentDeclaration =
Decl.GetOrCreateAssemblyDecl(assem, this.decls, true);
return base.VisitAssembly(assem);
}
public override Node Visit(Node node) {
Statement stmt = node as Statement;
if (stmt != null && stmt.SourceContext.Document != null) {
this.currentStatement = stmt;
}
return base.Visit(node);
}
public override Expression VisitLiteral(Literal l) {
if (l == null) return null;
TypeNode t = l.Value as TypeNode;
VisitTypeReference(t);
return l;
}
public override AttributeList VisitAttributeList(AttributeList al) {
DepKind savedCurrentKind = this.currentKind;
// switch to attribute kind
this.currentKind = DepKind.attr;
// visit attribute nodes which should result in a member binding visit
// for the constructor, and potential type reference visits for any
// typeof(typenode) arguments
base.VisitAttributeList(al);
this.currentKind = savedCurrentKind;
return al;
}
public override TypeNode VisitTypeNode(TypeNode typeNode) {
if (typeNode == null) return null;
// Add this type (and its namespace, base class, and base ifaces)
// to the the map of decls
//assert this.decls[typeNode.UniqueKey] == null;
Decl savedCurrentDeclaration = this.currentDeclaration;
this.currentDeclaration = Decl.GetOrCreateTypeDecl(typeNode, decls, ns_decls, true);
Set<TypeNode> oldSet = this.currentSet;
Set<TypeNode> inSigSet= new Set<TypeNode>();
this.currentSet = inSigSet;
base.VisitTypeNode(typeNode);
this.inSignatures[typeNode.UniqueKey] = this.currentSet;
types.Add(typeNode);
this.currentSet = oldSet;
this.currentDeclaration = savedCurrentDeclaration;
return typeNode;
}
public override TypeNode VisitTypeReference(TypeNode typeNode) {
if (typeNode == null) return null;
// Need to take the type reference apart here to get down
// to named types.
switch (typeNode.NodeType) {
case NodeType.ArrayType:
ArrayType at = (ArrayType)typeNode;
VisitTypeReference(at.ElementType);
// Add the implicit base class System.Array
VisitTypeReference(SystemTypes.Array);
return typeNode;
case NodeType.Pointer:
Pointer pt = (Pointer)typeNode;
VisitTypeReference(pt.ElementType);
return pt;
case NodeType.Reference:
Reference r = (Reference)typeNode;
VisitTypeReference(r.ElementType);
return r;
case NodeType.OptionalModifier:
case NodeType.RequiredModifier:
TypeModifier tm = (TypeModifier)typeNode;
VisitTypeReference(tm.Modifier);
VisitTypeReference(tm.ModifiedType);
return tm;
}
// type parameters are not interesting
if (typeNode is ITypeParameter) return typeNode;
// Look for generics
if (typeNode.Template != null) {
VisitTypeReference(typeNode.Template);
if (typeNode.TemplateArguments != null) {
for (int i = 0; i < typeNode.TemplateArguments.Count; i++) {
VisitTypeReference(typeNode.TemplateArguments[i]);
}
}
return typeNode;
}
// finally add the dependency to the current decl with current kind
this.AddDependency(
Decl.GetOrCreateTypeDecl(typeNode, decls, ns_decls, false),
this.currentKind
);
this.currentSet.Add(typeNode);
return typeNode;
}
public override Field VisitField(Field field) {
if (field == null) return null;
//assert decls[field.UniqueKey] == null;
Decl declField = Decl.GetOrCreateFieldDecl(field, decls, ns_decls);
declField.hasFullInfo = true;
Decl savedCurrentDeclaration = this.currentDeclaration;
this.currentDeclaration = declField;
// visit for type and attributes
base.VisitField(field);
this.currentDeclaration = savedCurrentDeclaration;
return field;
}
/// <summary>
/// Use this hook to transition into code dependency mode
/// </summary>
public override Block VisitBlock(Block block) {
Set<TypeNode> savedSet = this.currentSet;
DepKind savedKind = this.currentKind;
// set to code kind for nested visit
this.currentKind = DepKind.code;
assert this.currentMethod != null;
TypeNode declType = this.currentMethod.DeclaringType;
if (declType != null) {
this.currentSet = this.InCodeSet(declType);
base.VisitBlock(block);
this.SetInCodeSet(declType, this.currentSet);
}
this.currentKind = savedKind;
this.currentSet = savedSet;
return block;
}
public override Method VisitMethod(Method method) {
if (method == null) return null;
Decl savedCurrentDeclaration = this.currentDeclaration;
Decl declMethod = Decl.GetOrCreateMethodDecl(method, decls, ns_decls);
declMethod.hasFullInfo = true;
this.currentDeclaration = declMethod;
assert this.currentMethod == null;
this.currentMethod = method;
// visit parameters, attributes, return type and body
base.VisitMethod(method);
assert this.currentMethod == method;
this.currentMethod = null;
this.currentDeclaration = savedCurrentDeclaration;
return method;
}
private void WriteSourceContext(Node! node) {
Document d = node.SourceContext.Document;
if (d != null) {
Console.Write("{0}:{1} ", d.Name,
node.SourceContext.StartLine);
}
}
public override Expression VisitMemberBinding(MemberBinding mb) {
if (mb == null) return mb;
base.VisitMemberBinding(mb);
Member bm = mb.BoundMember;
if (bm != null) {
Decl memberDecl = null;
if (bm is Field) {
Field field = bm as Field;
assert field != null;
memberDecl = Decl.GetOrCreateFieldDecl(field, decls, ns_decls);
}
else if (bm is Method) {
Method method = bm as Method;
assert method != null;
memberDecl = Decl.GetOrCreateMethodDecl(method, decls, ns_decls);
}
assert memberDecl != null;
this.AddDependency(memberDecl, this.currentKind);
}
return mb;
}
Set<TypeNode> InSigSet(TypeNode! tn) {
object o = this.inSignatures[tn.UniqueKey];
if (o == null) return new Set<TypeNode>();
return (Set<TypeNode>)o;
}
Set<TypeNode> InCodeSet(TypeNode! tn) {
object o = this.inCode[tn.UniqueKey];
if (o == null) return new Set<TypeNode>();
return (Set<TypeNode>)o;
}
void SetInCodeSet(TypeNode! tn, Set<TypeNode> data) {
this.inCode[tn.UniqueKey] = data;
}
public void FixNamespaceKeys() {
assert this.ns_decls.Values != null;
foreach (object val in this.ns_decls.Values) {
Decl decl = val as Decl;
assert decl != null;
if (decl.kind == DeclKind.Namespace) {
decl.key += Decl.largestKey;
}
}
}
public void Dump(TextWriter! wr) {
assert !Test.outputXml;
foreach (TypeNode! tn in this.types) {
if (Test.oneLine) {
wr.WriteLine();
wr.WriteLine("{0}: Type: {0}", tn.FullName);
TypeNode bt = tn.BaseType;
if (bt != null) {
wr.WriteLine("{0}: Base type: {1}",
tn.FullName,
bt.FullName);
}
InterfaceList il = tn.Interfaces;
if (il != null) {
for (int i = 0; i < il.Count; i++) {
Interface intf = il[i];
if (intf != null) {
Console.WriteLine("{0}: Interface: {1}",
tn.FullName,
intf.FullName);
}
}
}
Set<TypeNode> s = InSigSet(tn);
foreach (TypeNode! stn in s) {
wr.WriteLine("{0}: Referenced from signature: {1}",
tn.FullName,
stn.FullName);
}
Set<TypeNode> cs = InCodeSet(tn);
foreach (TypeNode! stn in cs) {
wr.WriteLine("{0}: Referenced from code: {1}",
tn.FullName,
stn.FullName);
}
}
else {
wr.WriteLine("\n\nType: {0}", tn.FullName);
wr.WriteLine("----------------------");
TypeNode bt = tn.BaseType;
if (bt != null) {
wr.WriteLine("\n Base type: {0}", bt.FullName);
}
InterfaceList il = tn.Interfaces;
if (il != null) {
wr.WriteLine("\n Interfaces");
for (int i = 0; i < il.Count; i++) {
Interface intf = il[i];
if (intf != null) {
Console.WriteLine(" {0}", intf.FullName);
}
}
}
Set<TypeNode> s = InSigSet(tn);
wr.WriteLine("\n Referenced from signatures");
foreach (TypeNode! stn in s) {
wr.WriteLine(" {0}", stn.FullName);
}
Set<TypeNode> cs = InCodeSet(tn);
wr.WriteLine("\n Referenced from code");
foreach (TypeNode! stn in cs) {
wr.WriteLine(" {0}", stn.FullName);
}
}
}
}
public XmlDocument DumpAllDependenciesToXml() {
XmlDocument doc = new XmlDocument();
assert doc != null;
XmlElement rootElement = doc.CreateElement("MemberDependencies");
assert rootElement != null;
doc.AppendChild(rootElement);
assert this.decls.Values != null;
foreach (object val in this.decls.Values) {
Decl decl = val as Decl;
assert decl != null;
Output(doc, rootElement, decl);
}
return doc;
}
public void Output(XmlDocument! doc, XmlElement! parentElement, Decl !decl) {
if (decl.alreadyOutput)
return;
decl.alreadyOutput = true;
if (Test.outputLogicalModulesOnly &&
(decl.kind == DeclKind.Assembly || decl.kind == DeclKind.Namespace)) {
return;
}
if (Test.outputTypesOnly && !Decl.IsType(decl.kind)) {
return;
}
// Then output lexical scope assembly
if (decl.lexicalScope != null)
Output(doc, parentElement, decl.lexicalScope);
#if false
// Then output all the dependencies
for (int i = 0; decl.dependencies != null && i < decl.dependencies.Count; ++i) {
Dep dep = decl.dependencies[i] as Dep;
assert dep != null;
assert dep.decl != null;
Output(doc, parentElement, dep.decl);
}
#endif
// Creating the element will output the dependencies
XmlElement elem = decl.CreateXmlElement(doc);
parentElement.AppendChild(elem);
}
}