• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 15052278841

15 May 2025 06:16PM UTC coverage: 34.038% (-0.4%) from 34.453%
15052278841

push

github

SamboyCoding
Support injecting anything
* Nested types
* Events
* Properties
* Assemblies

Support additional metadata in injected assemblies

Make setter for TypeAnalysisContext::OverrideBaseType public

TypeAnalysisContext::InterfaceContexts as list rather than array

Fix sign bug

Support generic parameters on type contexts and method contexts

Make GenericParameterTypeAnalysisContext instances unique

Revert change to Il2CppGenericParameter::Index

Use attributes to determine if injected methods are static
* Also add hide by sig attribute for injected constructors

Support overrides on injected methods

In ControlFlowGraphOutputFormat, exclude injected assemblies

Ensure injected assemblies can't delete existing assemblies

Backing field on .NET Standard for injected method overrides

Implement requested change

1774 of 6622 branches covered (26.79%)

Branch coverage included in aggregate %.

147 of 196 new or added lines in 27 files covered. (75.0%)

53 existing lines in 2 files now uncovered.

4155 of 10797 relevant lines covered (38.48%)

188267.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.89
/Cpp2IL.Core/OutputFormats/IsilDumpOutputFormat.cs
1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Linq;
5
using System.Text;
6
using Cpp2IL.Core.Api;
7
using Cpp2IL.Core.Extensions;
8
using Cpp2IL.Core.Logging;
9
using Cpp2IL.Core.Model.Contexts;
10
using Cpp2IL.Core.Utils;
11

12
namespace Cpp2IL.Core.OutputFormats;
13

14
public class IsilDumpOutputFormat : Cpp2IlOutputFormat
15
{
16
    public override string OutputFormatId => "isil";
1✔
17
    public override string OutputFormatName => "ISIL Dump";
×
18

19
    public override void DoOutput(ApplicationAnalysisContext context, string outputRoot)
20
    {
21
        outputRoot = Path.Combine(outputRoot, "IsilDump");
×
22

23
        var numAssemblies = context.Assemblies.Count;
×
24
        var i = 1;
×
25
        foreach (var assembly in context.Assemblies)
×
26
        {
NEW
27
            Logger.InfoNewline($"Processing assembly {i++} of {numAssemblies}: {assembly.Name}", "IsilOutputFormat");
×
28

29
            var assemblyNameClean = assembly.CleanAssemblyName;
×
30

31
            MiscUtils.ExecuteParallel(assembly.Types, type =>
×
32
            {
×
33
                if (type is InjectedTypeAnalysisContext)
×
34
                    return;
×
35

×
36
                if (type.Methods.Count == 0)
×
37
                    return;
×
38

×
39
                var typeDump = new StringBuilder();
×
40

×
41
                typeDump.Append("Type: ").AppendLine(type.Definition!.FullName).AppendLine();
×
42

×
43
                foreach (var method in type.Methods)
×
44
                {
×
45
                    if (method is InjectedMethodAnalysisContext)
×
46
                        continue;
×
47

×
48
                    typeDump.Append("Method: ").AppendLine(method.Definition!.HumanReadableSignature).AppendLine();
×
49

×
50
                    try
×
51
                    {
×
52
                        typeDump.AppendLine("Disassembly:");
×
53
                        typeDump.Append('\t').AppendLine(context.InstructionSet.PrintAssembly(method).Replace("\n", "\n\t"));
×
54

×
55
                        typeDump.AppendLine().AppendLine("ISIL:");
×
56

×
57
                        method.Analyze();
×
58

×
59
                        if (method.ConvertedIsil == null || method.ConvertedIsil.Count == 0)
×
60
                        {
×
61
                            typeDump.AppendLine("No ISIL was generated");
×
62
                            continue;
×
63
                        }
×
64

×
65
                        foreach (var isilInsn in method.ConvertedIsil)
×
66
                        {
×
67
                            typeDump.Append('\t').Append(isilInsn).AppendLine();
×
68
                        }
×
69

×
70
                        method.ReleaseAnalysisData();
×
71

×
72
                        typeDump.AppendLine();
×
73
                    }
×
74
                    catch (Exception e)
×
75
                    {
×
76
                        typeDump.Append("Method threw an exception while analyzing - ").AppendLine(e.ToString()).AppendLine();
×
77
                    }
×
78
                }
×
79

×
80
                WriteTypeDump(outputRoot, type, typeDump.ToString(), assemblyNameClean);
×
81
            });
×
82
        }
83
    }
×
84

85
    private static string GetFilePathForType(string outputRoot, TypeAnalysisContext type, string assemblyNameClean)
86
    {
87
        //Get root assembly directory
88
        var assemblyDir = Path.Combine(outputRoot, assemblyNameClean);
×
89

90
        //If type is nested, we should use namespace of ultimate declaring type, which could be an arbitrary depth
91
        //E.g. rewired has a type Rewired.Data.Mapping.HardwareJoystickMap, which contains a nested class Platform_Linux_Base, which contains MatchingCriteria, which contains ElementCount.
92
        var ultimateDeclaringType = type;
×
93
        while (ultimateDeclaringType.DeclaringType != null)
×
94
            ultimateDeclaringType = ultimateDeclaringType.DeclaringType;
×
95

96
        var namespaceSplit = ultimateDeclaringType.Namespace!.Split('.');
×
97
        namespaceSplit = namespaceSplit
×
98
            .Peek(n => MiscUtils.InvalidPathChars.ForEach(c => n = n.Replace(c, '_')))
×
99
            .Select(n => MiscUtils.InvalidPathElements.Contains(n) ? $"__illegalwin32name_{n}__" : n)
×
100
            .ToArray();
×
101

102
        //Ok so we have the namespace directory. Now we need to join all the declaring type hierarchy together for a filename.
103
        var declaringTypeHierarchy = new List<string>();
×
104
        var declaringType = type.DeclaringType;
×
105
        while (declaringType != null)
×
106
        {
107
            declaringTypeHierarchy.Add(declaringType.Name!);
×
108
            declaringType = declaringType.DeclaringType;
×
109
        }
110

111
        //Reverse so we have top-level type first.
112
        declaringTypeHierarchy.Reverse();
×
113

114
        //Join the hierarchy together with _NestedType_ separators
115
        string filename;
116
        if (declaringTypeHierarchy.Count > 0)
×
117
            filename = $"{string.Join("_NestedType_", declaringTypeHierarchy)}_NestedType_{type.Name}.txt";
×
118
        else
119
            filename = $"{type.Name}.txt";
×
120

121
        //Get directory from assembly root + namespace
122
        var directory = Path.Combine(namespaceSplit.Prepend(assemblyDir).ToArray());
×
123
        if (!Directory.Exists(directory))
×
124
            Directory.CreateDirectory(directory);
×
125

126
        //Clean up the filename
127
        MiscUtils.InvalidPathChars.ForEach(c => filename = filename.Replace(c, '_'));
×
128

129
        //Combine the directory and filename
130
        return Path.Combine(directory, filename);
×
131
    }
132

133
    private static void WriteTypeDump(string outputRoot, TypeAnalysisContext type, string typeDump, string assemblyNameClean)
134
    {
135
        var file = GetFilePathForType(outputRoot, type, assemblyNameClean);
×
136
        File.WriteAllText(file, typeDump);
×
137
    }
×
138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc