public void Index(string outputFileName) { // create the Sourcetrail data collector var dataCollector = new DataCollector(outputFileName); var pdbLocator = new PdbLocator(); // set up the type handler var typeHandler = new TypeHandler(assemblies, nameFilter, namespaceFollowFilter, dataCollector, pdbLocator); typeHandler.MethodCollected += (sender, args) => collectedMethods.Add(args.CollectedMethod); foreach (var assembly in assemblies) { Console.WriteLine("Indexing assembly {0}{1}", assembly.Location, Environment.NewLine); pdbLocator.AddAssembly(assembly); try { Console.WriteLine("Collecting types..."); // collect all types first foreach (var type in assembly.GetTypes()) { typeHandler.AddToDbIfValid(type); } } catch (Exception ex) { Console.WriteLine("Exception indexing assemby '{0}'\r\n{1}", assembly.Location, ex); } } Console.WriteLine("{1}Collected {0} types{1}", Cache.CollectedTypes.Count, Environment.NewLine); // set up the visitor for parsed methods var referenceVisitor = new MethodReferenceVisitor(typeHandler, dataCollector, pdbLocator); var ilParser = new ILParser(referenceVisitor); referenceVisitor.ParseMethod += (sender, args) => CollectReferencesFromILCode( ilParser, args.CollectedMethod.Method, args.CollectedMethod.MethodId, args.CollectedMethod.ClassId); // parse IL of colected methods HandleCollectedMethods(ilParser); dataCollector.Dispose(); }
private void CollectTypeMembers(Type type, int typeSymbolId) { // skip, if already collected if (Cache.CollectedTypes.ContainsKey(type)) { return; } if (!Cache.CollectedAssemblies.ContainsKey(type.Assembly)) { Console.WriteLine("Following {0}", type.Assembly.Location); Cache.CollectedAssemblies.Add(type.Assembly, 1); pdbLocator.AddAssembly(type.Assembly); } Cache.CollectedTypes[type] = typeSymbolId; if (type.BaseType != null) { // nearly everything inherits from object, always ignore these if (type.BaseType != typeof(object)) { var baseTypeId = AddToDbIfValid(type.BaseType); if (baseTypeId > 0) { dataCollector.CollectReference(typeSymbolId, baseTypeId, ReferenceKind.REFERENCE_INHERITANCE); } } } // collect interfaces and their implementing classes // when we later parse the IL and a method makes a call to an interface-method, // we also collect a reference from the calling method to every class that implements that interface var ifaces = type.GetInterfaces(); foreach (var iface in ifaces) { var ifaceId = AddToDbIfValid(iface); if (ifaceId > 0) { dataCollector.CollectReference(typeSymbolId, ifaceId, ReferenceKind.REFERENCE_INHERITANCE); if (!Cache.InterfaceImplementations.TryGetValue(iface, out var implementors)) { implementors = new List <Type>(); Cache.InterfaceImplementations[iface] = implementors; } if (!implementors.Contains(type)) { implementors.Add(type); } } } // collect attributes and treat these as annotations foreach (var attribute in type.GetCustomAttributesData()) { var attribId = AddToDbIfValid(attribute.AttributeType); if (attribId > 0) { dataCollector.CollectReference(typeSymbolId, attribId, ReferenceKind.REFERENCE_ANNOTATION_USAGE); } } // collect all members of this type foreach (var member in type.GetMembers(flags)) { var memberId = CollectMember(member, false, out _); if (memberId <= 0) { continue; } if (member is MethodInfo method) { var tid = AddToDbIfValid(method.ReturnType); if (tid > 0) { dataCollector.CollectReference(memberId, tid, ReferenceKind.REFERENCE_TYPE_USAGE); } foreach (var param in method.GetParameters()) { tid = AddToDbIfValid(param.ParameterType); if (tid > 0) { dataCollector.CollectReference(memberId, tid, ReferenceKind.REFERENCE_TYPE_USAGE); } } if (method.IsGenericMethod) { foreach (var genArg in method.GetGenericArguments()) { tid = AddToDbIfValid(genArg); if (tid > 0) { dataCollector.CollectReference(memberId, tid, ReferenceKind.REFERENCE_TYPE_ARGUMENT); } } } CollectMethod(method, memberId, typeSymbolId); } else if (member is ConstructorInfo ctor) { foreach (var param in ctor.GetParameters()) { var tid = AddToDbIfValid(param.ParameterType); if (tid > 0) { dataCollector.CollectReference(memberId, tid, ReferenceKind.REFERENCE_TYPE_USAGE); } } CollectMethod(ctor, memberId, typeSymbolId); } else if (member is TypeInfo nestedType) { if (!nestedType.IsCompilerGenerated()) // ignore compiler-generated classes { AddToDb(nestedType); } } } }