public static AnalyserTestData create(AnalyzerData data)
 {
     return new AnalyserTestData(
     data,
     data.usedTypes.Select(t => t.name).ToImmutableSortedSet(),
     data.analyzedMethods.Select(t => t.name).ToImmutableSortedSet()
       );
 }
 public AnalyserTestData(
     AnalyzerData data,
     ImmutableSortedSet<string> usedTypes, ImmutableSortedSet<string> analyzedMethods
     )
 {
     this.data = data;
       this.usedTypes = usedTypes;
       this.analyzedMethods = analyzedMethods;
 }
        static AnalyzerData analyze(
            AnalyzerData data, ExpandedMethod method, AnalyserLogger log
            )
        {
            if (data.hasMethod(method)) return data;
              log.log("method", method);
              log.incIndent();

              data = data.addMethod(method);

              if (method.definition.IsConstructor) data = data.addType(method.declaringType);
              data = data.addType(method.returnType);
              data = method.parameters.Aggregate(data, (current, parameter) => current.addType(parameter));

              if (method.definition.IsVirtual && method.definition.Body == null) {
            // Because we don't know with what concrete types the implementation classes
            // of virtual methods will be instantiated, we will need to do a separate
            // analyzing stage once we know all the concrete types.
            data = data.addType(method.declaringType);
            data = data.addVirtualMethod(new VirtualMethod(method));
              }
              else if (method.definition.Body != null) {
            var body = method.definition.Body;
            foreach (var varDef in body.Variables) {
              var exVar = ExpandedType.create(varDef.VariableType, method.genericParameterToExType);
              data = data.addType(exVar);
            }
            foreach (var instruction in body.Instructions) {
              if (
            instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld
            || instruction.OpCode == OpCodes.Ldsfld
              ) {
            var fieldDef = (FieldReference) instruction.Operand;
            var fieldGenerics = method.genericParameterToExType;
            var gFieldType = fieldDef.FieldType as GenericInstanceType;

            if (fieldDef.FieldType.DeclaringType != null /*fieldDef.FieldType.IsNested*/) {
              if (fieldDef.FieldType.IsGenericParameter) {
                var generics = ExpandedMethod.genericArgumentsDict(
                  ((GenericInstanceType) fieldDef.DeclaringType).GenericArguments,
                  fieldDef.FieldType.DeclaringType.GenericParameters,
                  fieldGenerics
                );
                fieldGenerics = fieldGenerics.AddRange(generics);
              }
              if (gFieldType != null) {
                var tpl =
                  gFieldType.GenericArguments.SequenceEqual(gFieldType.ElementType.GenericParameters)
                  ? F.t(
                    (IList<TypeReference>)gFieldType.ElementType.DeclaringType.GenericParameters.Cast<TypeReference>().ToList(),
                    (IList<GenericParameter>)gFieldType.GenericArguments.Cast<GenericParameter>().ToList()
                  )
                  : gFieldType.ElementType.DeclaringType.HasGenericParameters
                    ? F.t(
                      (IList<TypeReference>) gFieldType.GenericArguments,
                      (IList<GenericParameter>) gFieldType.ElementType.DeclaringType.GenericParameters
                    )
                    : F.t(
                      (IList<TypeReference>)new TypeReference[0],
                      (IList<GenericParameter>)new GenericParameter[0]
                    );

                var generics =
                  ExpandedMethod.genericArgumentsDict(tpl._1, tpl._2, fieldGenerics);
                fieldGenerics = fieldGenerics.AddRange(generics);
              }
            }
            var exFieldDef = ExpandedType.create(fieldDef.FieldType, fieldGenerics);
            var exDeclaringType = ExpandedType.create(fieldDef.DeclaringType, method.genericParameterToExType);
            data = data.addType(exFieldDef).addType(exDeclaringType);
              }
              else if (
            instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Calli
            || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj
              ) {
            var methodRef = (MethodReference)instruction.Operand;
            if (instruction.OpCode == OpCodes.Newobj && methodRef.DeclaringType.Resolve().isDelegate()) {
              methodRef = (MethodReference) instruction.Previous.Operand;
            }
            var expanded = ExpandedMethod.create(methodRef, method.genericParameterToExType);
            data = analyze(data, expanded, log);
              }
            }
              }
              else if (! (method.definition.IsInternalCall || method.definition.IsPInvokeImpl)) {
            throw new Exception("Method body null when not expected: " + method);
              }
              log.decIndent();
              return data;
        }
        public static AnalyzerData analyze(
            IEnumerable<MethodDefinition> entryPoints,
            AnalyserLogger log
            )
        {
            var data = new AnalyzerData(
            ImmutableHashSet<ExpandedType>.Empty, ImmutableHashSet<ExpandedMethod>.Empty,
            ImmutableHashSet<VirtualMethod>.Empty, ImmutableHashSet<VirtualMethod>.Empty
              );
              foreach (var entryMethod in entryPoints) {
            var exEntryMethod = ExpandedMethod.create(
              entryMethod, ExpandedType.EMPTY_GENERIC_LOOKUP
            );
            data = data.addType(exEntryMethod.declaringType);
            if (!data.hasMethod(exEntryMethod)) {
              log.log("Entry", exEntryMethod);
              data = analyze(data, exEntryMethod, log);
            }
              }

              // Once we know all used types, resolve the called virtual methods.
              // Iterate in a loop because expanding virtual method bodies might invoke additional
              // virtual methods.
              while (!data.virtualMethodsToAnalyze.IsEmpty) {
            foreach (var virtualMethod in data.virtualMethodsToAnalyze) {
              var declaring = virtualMethod.method.declaringType;
              foreach (var _usedType in data.usedTypes.Where(et => et.implements(declaring))) {
            var usedType = _usedType;
            MethodDefinition matching = null;
            while (matching == null) {
              matching = VirtualMethods.GetMethod(
                usedType.definition.Methods, virtualMethod.method.definition
              );
              if (matching == null) {
                if (usedType.definition.BaseType == null) throw new Exception(
                  "Can't find implementation for [" + virtualMethod + "] in [" + _usedType + "]!"
                );
                usedType = ExpandedType.create(
                  usedType.definition.BaseType,
                  usedType.genericParametersToArguments
                );
              }
            }

            var generics = usedType.genericParametersToArguments.AddRange(
              ExpandedMethod.genericArgumentsDict(
                virtualMethod.method.genericArguments.Select(t => (TypeReference)t.definition).ToList(),
                matching.GenericParameters,
                usedType.genericParametersToArguments
              )
            );
            var exMatching = new ExpandedMethod(
              virtualMethod.method.returnType, usedType, matching,
              virtualMethod.method.genericArguments,
              virtualMethod.method.parameters, generics
            );
            data = analyze(data, exMatching, log);
              }
              data = data.analyzedVirtualMethod(virtualMethod);
            }
              }
              return data;
        }
        public static AnalyzerData analyze(
            IEnumerable <MethodDefinition> entryPoints,
            AnalyserLogger log
            )
        {
            var data = new AnalyzerData(
                ImmutableHashSet <ExpandedType> .Empty, ImmutableHashSet <ExpandedMethod> .Empty,
                ImmutableHashSet <VirtualMethod> .Empty, ImmutableHashSet <VirtualMethod> .Empty
                );

            foreach (var entryMethod in entryPoints)
            {
                var exEntryMethod = ExpandedMethod.create(
                    entryMethod, ExpandedType.EMPTY_GENERIC_LOOKUP
                    );
                data = data.addType(exEntryMethod.declaringType);
                if (!data.hasMethod(exEntryMethod))
                {
                    log.log("Entry", exEntryMethod);
                    data = analyze(data, exEntryMethod, log);
                }
            }

            // Once we know all used types, resolve the called virtual methods.
            // Iterate in a loop because expanding virtual method bodies might invoke additional
            // virtual methods.
            while (!data.virtualMethodsToAnalyze.IsEmpty)
            {
                foreach (var virtualMethod in data.virtualMethodsToAnalyze)
                {
                    var declaring = virtualMethod.method.declaringType;
                    foreach (var _usedType in data.usedTypes.Where(et => et.implements(declaring)))
                    {
                        var usedType = _usedType;
                        MethodDefinition matching = null;
                        while (matching == null)
                        {
                            matching = VirtualMethods.GetMethod(
                                usedType.definition.Methods, virtualMethod.method.definition
                                );
                            if (matching == null)
                            {
                                if (usedType.definition.BaseType == null)
                                {
                                    throw new Exception(
                                              "Can't find implementation for [" + virtualMethod + "] in [" + _usedType + "]!"
                                              );
                                }
                                usedType = ExpandedType.create(
                                    usedType.definition.BaseType,
                                    usedType.genericParametersToArguments
                                    );
                            }
                        }

                        var generics = usedType.genericParametersToArguments.AddRange(
                            ExpandedMethod.genericArgumentsDict(
                                virtualMethod.method.genericArguments.Select(t => (TypeReference)t.definition).ToList(),
                                matching.GenericParameters,
                                usedType.genericParametersToArguments
                                )
                            );
                        var exMatching = new ExpandedMethod(
                            virtualMethod.method.returnType, usedType, matching,
                            virtualMethod.method.genericArguments,
                            virtualMethod.method.parameters, generics
                            );
                        data = analyze(data, exMatching, log);
                    }
                    data = data.analyzedVirtualMethod(virtualMethod);
                }
            }
            return(data);
        }
        static AnalyzerData analyze(
            AnalyzerData data, ExpandedMethod method, AnalyserLogger log
            )
        {
            if (data.hasMethod(method))
            {
                return(data);
            }
            log.log("method", method);
            log.incIndent();

            data = data.addMethod(method);

            if (method.definition.IsConstructor)
            {
                data = data.addType(method.declaringType);
            }
            data = data.addType(method.returnType);
            data = method.parameters.Aggregate(data, (current, parameter) => current.addType(parameter));

            if (method.definition.IsVirtual && method.definition.Body == null)
            {
                // Because we don't know with what concrete types the implementation classes
                // of virtual methods will be instantiated, we will need to do a separate
                // analyzing stage once we know all the concrete types.
                data = data.addType(method.declaringType);
                data = data.addVirtualMethod(new VirtualMethod(method));
            }
            else if (method.definition.Body != null)
            {
                var body = method.definition.Body;
                foreach (var varDef in body.Variables)
                {
                    var exVar = ExpandedType.create(varDef.VariableType, method.genericParameterToExType);
                    data = data.addType(exVar);
                }
                foreach (var instruction in body.Instructions)
                {
                    if (
                        instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld ||
                        instruction.OpCode == OpCodes.Ldsfld
                        )
                    {
                        var fieldDef      = (FieldReference)instruction.Operand;
                        var fieldGenerics = method.genericParameterToExType;
                        var gFieldType    = fieldDef.FieldType as GenericInstanceType;

                        if (fieldDef.FieldType.DeclaringType != null /*fieldDef.FieldType.IsNested*/)
                        {
                            if (fieldDef.FieldType.IsGenericParameter)
                            {
                                var generics = ExpandedMethod.genericArgumentsDict(
                                    ((GenericInstanceType)fieldDef.DeclaringType).GenericArguments,
                                    fieldDef.FieldType.DeclaringType.GenericParameters,
                                    fieldGenerics
                                    );
                                fieldGenerics = fieldGenerics.AddRange(generics);
                            }
                            if (gFieldType != null)
                            {
                                var tpl =
                                    gFieldType.GenericArguments.SequenceEqual(gFieldType.ElementType.GenericParameters)
                  ? F.t(
                                        (IList <TypeReference>)gFieldType.ElementType.DeclaringType.GenericParameters.Cast <TypeReference>().ToList(),
                                        (IList <GenericParameter>)gFieldType.GenericArguments.Cast <GenericParameter>().ToList()
                                        )
                  : gFieldType.ElementType.DeclaringType.HasGenericParameters
                    ? F.t(
                                        (IList <TypeReference>)gFieldType.GenericArguments,
                                        (IList <GenericParameter>)gFieldType.ElementType.DeclaringType.GenericParameters
                                        )
                    : F.t(
                                        (IList <TypeReference>) new TypeReference[0],
                                        (IList <GenericParameter>) new GenericParameter[0]
                                        );

                                var generics =
                                    ExpandedMethod.genericArgumentsDict(tpl._1, tpl._2, fieldGenerics);
                                fieldGenerics = fieldGenerics.AddRange(generics);
                            }
                        }
                        var exFieldDef      = ExpandedType.create(fieldDef.FieldType, fieldGenerics);
                        var exDeclaringType = ExpandedType.create(fieldDef.DeclaringType, method.genericParameterToExType);
                        data = data.addType(exFieldDef).addType(exDeclaringType);
                    }
                    else if (
                        instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Calli ||
                        instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj
                        )
                    {
                        var methodRef = (MethodReference)instruction.Operand;
                        if (instruction.OpCode == OpCodes.Newobj && methodRef.DeclaringType.Resolve().isDelegate())
                        {
                            methodRef = (MethodReference)instruction.Previous.Operand;
                        }
                        var expanded = ExpandedMethod.create(methodRef, method.genericParameterToExType);
                        data = analyze(data, expanded, log);
                    }
                }
            }
            else if (!(method.definition.IsInternalCall || method.definition.IsPInvokeImpl))
            {
                throw new Exception("Method body null when not expected: " + method);
            }
            log.decIndent();
            return(data);
        }