void ParseEnum(TypeDefinition enumTypeDef)
        {
            // TODO: verify that int32 is the enums storage type for constant read below

            InspectorEnum ienum = new InspectorEnum();

            ienum.Name = metaReader.GetString(enumTypeDef.Name);

            InspectorEnums [ienum.Name] = ienum;

            var fields = enumTypeDef.GetFields();

            foreach (var fieldHandle in fields)
            {
                var inspectorField = new InspectorField();

                var fieldDef = metaReader.GetFieldDefinition(fieldHandle);

                if ((fieldDef.Attributes & FieldAttributes.HasDefault) != 0)
                {
                    var constantHandle = fieldDef.GetDefaultValue();
                    var constant       = metaReader.GetConstant(constantHandle);

                    BlobReader constantReader = metaReader.GetBlobReader(constant.Value);

                    ienum.Values [metaReader.GetString(fieldDef.Name)] = constantReader.ReadInt32();
                }
            }

            return;
        }
        // Inspect a CSComponent derived class
        internal InspectorComponent Inspect()
        {
            var fields = typeDef.GetFields();

            foreach (var fieldHandle in fields)
            {
                var inspectorField = new InspectorField();

                var fieldDef = metaReader.GetFieldDefinition(fieldHandle);

                var customAttr = fieldDef.GetCustomAttributes();

                foreach (var caHandle in customAttr)
                {
                    // Look for InspectorAttribute
                    if (DecodeCustomAttribute(caHandle, inspectorField))
                    {
                        BlobReader      sigReader = metaReader.GetBlobReader(fieldDef.Signature);
                        SignatureHeader header    = sigReader.ReadSignatureHeader();

                        if (header.Kind != SignatureKind.Field)
                        {
                            continue;
                        }

                        var typeCode = sigReader.ReadSignatureTypeCode();

                        string typeName = typeCode.ToString();

                        if (typeCode == SignatureTypeCode.TypeHandle)
                        {
                            EntityHandle token     = sigReader.ReadTypeHandle();
                            HandleKind   tokenType = token.Kind;

                            if (tokenType == HandleKind.TypeDefinition)
                            {
                                // can store local enum typedefs
                                // enum initializers are stored as constant value in the IL

                                var typeDef = metaReader.GetTypeDefinition((TypeDefinitionHandle)token);

                                var baseTypeToken = typeDef.BaseType;

                                if (baseTypeToken.Kind != HandleKind.TypeReference)
                                {
                                    continue;
                                }

                                var baseTypeRef = metaReader.GetTypeReference((TypeReferenceHandle)baseTypeToken);

                                if (metaReader.GetString(baseTypeRef.Name) != "Enum")
                                {
                                    continue;
                                }

                                inspectorField.IsEnum = true;
                                typeName = metaReader.GetString(typeDef.Name);
                            }
                            else if (tokenType == HandleKind.TypeReference)
                            {
                                // TypeReference, ok
                                var typeRef = metaReader.GetTypeReference((TypeReferenceHandle)token);

                                typeName = metaReader.GetString(typeRef.Name);
                            }
                            else
                            {
                                // ???
                                continue;
                            }
                        }

                        inspectorField.TypeName = typeName;
                        inspectorField.Name     = metaReader.GetString(fieldDef.Name);
                        _inspectorComponent.Fields [inspectorField.Name] = inspectorField;

                        break;
                    }
                }
            }

            // There is no way to get the initializer value of a field
            // other than to inspect the IL code of the constructor
            var methods = typeDef.GetMethods();

            foreach (var methodHandle in methods)
            {
                var methodDef = metaReader.GetMethodDefinition(methodHandle);

                if (metaReader.GetString(methodDef.Name) == ".ctor")
                {
                    var body    = peFile.GetMethodBody(methodDef.RelativeVirtualAddress);
                    var ilBytes = body.GetILContent();

                    InspectILBlock(ilBytes, ilBytes.Length);
                }
            }

            //Dump ();

            return(_inspectorComponent);
        }
        private bool DecodeCustomAttribute(CustomAttributeHandle caHandle, InspectorField inspectorField)
        {
            // GetCustomAttribute: https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs#L1370

            // Custom Attribute
            var ca = metaReader.GetCustomAttribute(caHandle);

            // MethodDefinitionHandle or MemberReferenceHandle
            if (ca.Constructor.Kind != HandleKind.MemberReference)
            {
                Console.WriteLine("ca.Constructor.Kind != HandleKind.MemberReference");
                return(false);
            }

            // constructor of the custom attr which contains the signature
            var memberRef = metaReader.GetMemberReference((MemberReferenceHandle)ca.Constructor);

            // parent of the constructor is the TypeReference
            var parent = memberRef.Parent;

            if (parent.Kind != HandleKind.TypeReference)
            {
                Console.WriteLine("parent.Kind != HandleKind.TypeReference");
                return(false);
            }

            var parentTypeRef = metaReader.GetTypeReference((TypeReferenceHandle)parent);

            // check whether we have an InspectorAttribute
            if (metaReader.GetString(parentTypeRef.Name) != "InspectorAttribute")
            {
                Console.WriteLine("parentTypeRef != InspectorAttribute");
                return(false);
            }

            // args
            var argsReader = metaReader.GetBlobReader((BlobHandle)ca.Value);

            uint prolog = argsReader.ReadUInt16();

            if (prolog != 1)
            {
                Console.WriteLine("prolog != 1");
                return(false);
            }

            // sig reader is on constructor
            BlobReader      sigReader = metaReader.GetBlobReader(memberRef.Signature);
            SignatureHeader header    = sigReader.ReadSignatureHeader();

            // Get the type parameter count.
            if (header.IsGeneric && sigReader.ReadCompressedInteger() != 0)
            {
                Console.WriteLine("header.IsGeneric && sigReader.ReadCompressedInteger() != 0");
                return(false);
            }

            // Get the parameter count
            int paramCount = sigReader.ReadCompressedInteger();

            // Get the type return type.
            var returnTypeCode = sigReader.ReadSignatureTypeCode();

            if (returnTypeCode != SignatureTypeCode.Void)
            {
                Console.WriteLine("returnTypeCode != SignatureTypeCode.Void");
                return(false);
            }

            List <SignatureTypeCode> sigTypeCodes = new List <SignatureTypeCode> ();

            // position args
            for (int i = 0; i < paramCount; i++)
            {
                SignatureTypeCode paramTypeCode = sigReader.ReadSignatureTypeCode();

                // support string custom attr for now to simplify things
                if (paramTypeCode != SignatureTypeCode.String)
                {
                    return(false);
                }

                string value;

                if (CrackStringInAttributeValue(out value, ref argsReader))
                {
                    inspectorField.CustomAttrPositionalArgs.Add(value);
                }

                sigTypeCodes.Add(paramTypeCode);
            }

            // named args

            short namedParamCount = argsReader.ReadInt16();

            for (short i = 0; i < namedParamCount; i++)
            {
                // Ecma-335 23.3 - A NamedArg is simply a FixedArg preceded by information to identify which field or
                // property it represents. [Note: Recall that the CLI allows fields and properties to have the same name; so
                // we require a means to disambiguate such situations. end note] FIELD is the single byte 0x53. PROPERTY is
                // the single byte 0x54.

                // https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs#L1305

                var kind = (CustomAttributeNamedArgumentKind)argsReader.ReadCompressedInteger();

                if (kind != CustomAttributeNamedArgumentKind.Field && kind != CustomAttributeNamedArgumentKind.Property)
                {
                    return(false);
                }

                var typeCode = argsReader.ReadSerializationTypeCode();

                // support string custom attr for now to simplify things
                if (typeCode != SerializationTypeCode.String)
                {
                    return(false);
                }

                string name;

                if (!CrackStringInAttributeValue(out name, ref argsReader))
                {
                    return(false);
                }

                string value;

                if (!CrackStringInAttributeValue(out value, ref argsReader))
                {
                    return(false);
                }

                inspectorField.CustomAttrNamedArgs [name] = value;
            }

            return(true);
        }