예제 #1
0
        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);
                    }
                }
            }
        }