Skip to content

ILens 10

Latest

Choose a tag to compare

@tadis174 tadis174 released this 09 Oct 11:58

ILens 10

  • The CLAUDE.md block the README of ILens 9 and earlier asked for now names tools that no longer exist and can be deleted: Claude Code needs no block, and a client that does not read server instructions takes the README's new paragraph, which names no tool
  • ILens now tells the client when it connects what it is for, which directories it can read and which tool answers what, so Claude Code knows when and how to use it without a block in the project's CLAUDE.md
  • find_types now finds the types an assembly defines by namespace, name_contains, accessibility and include_compiler_generated, and replaces list_types and search_types
  • list_members now opens with the type's declaration, its base types and the number of members, such as 7 members of public class CallShapes.Settings:, and replaces summarize_type
  • decompile now decompiles a type or one of its members, and replaces decompile_type, decompile_method, decompile_property and decompile_event
  • compare now compares two assemblies from the types that differ down to one method's bodies, and replaces list_changed_types, compare_type and compare_method
  • analyze now lists every call to a method with the arguments it passes, with kind call_sites, resolving named, reordered, omitted and params arguments; parameter_name narrows each line to one parameter, and non_default_only keeps only the calls that pass something other than its default
  • Every tool parameter is now snake_case, such as type_name, member_name, parameter_types and assembly_a
  • find_methods now takes namespace, type_name, type_name_contains, return_type and name_contains in place of declaringNamespace, declaringType, declaringTypePattern, returns and namePattern
  • list_members now takes name_contains in place of namePattern, find_types takes name_contains and namespace where search_types took pattern and list_types took namespaceName, and compare takes namespace where list_changed_types took namespaceFilter
  • find_types and compare take include_compiler_generated, off by default, where list_types, search_types and list_changed_types took excludeCompilerGenerated
  • Enum values are now snake_case, such as used_by, public_protected and field, and error messages name them that way; the PascalCase values are still accepted
  • Every tool that lists now takes limit, lists up to 100 results unless limit says otherwise, and ends a cut list with ... (N more; raise limit to see all)
  • A parameter that several tools take is now described alike in each of them, and every tool that takes parameter_types describes the type patterns it accepts
  • find_methods, list_members and analyze no longer list the method Burst adds to start its wrapper, Initialize$...$BurstDirectCall, unless include_compiler_generated is true
  • Generic types now print with their type parameters, in C#'s unbound form such as System.Func<,> or Dictionary<,>.Enumerator, so Task and Task<TResult> no longer print alike; a constructed type prints with its arguments
  • A type name without type parameters now means the non-generic type when one exists, otherwise the only type of that name; a name several generic types share, such as System.Func, is an error listing them instead of an answer for whichever came first
  • Type names accept Func<,>, Func`2 and Func<int, bool>, so every type can be named, including one nested in a generic type
  • Tools that take a type name or a type pattern now accept a nested type written the reflection way, Outer+Inner, as well as Outer.Inner
  • Type patterns now compare argument lists: List<int> matches only List<int>, List<> and List`1 match any List<T>, and a bare List stays as loose as before; this also works for types from referenced assemblies, fully qualified or not
  • A type nested in a generic type now prints with the types enclosing it, Dictionary<TKey, TValue>.Entry instead of Entry<TKey, TValue>, and a type pattern may name a type by the end of its full name, such as Dictionary.Entry
  • Tuple types now print with their element types, as ValueTuple<int, int>, also in assemblies that define System.ValueTuple themselves, such as System.Private.CoreLib, where they printed as a bare ValueTuple; the pattern ValueTuple<int, int> now finds them
  • Function pointers now print as C# writes them, such as delegate* unmanaged<int, void>, instead of a bare delegate*, and the pattern delegate* matches any function pointer
  • Pointers now print with the C# keyword, void* instead of Void*, and type patterns take a trailing * for a pointer
  • list_members, find_methods and compare now write ref, out, in and ref readonly parameters and ref and ref readonly returns as C# does, such as public ref T Item[int index] { get; } on Span<T>, instead of the plain type
  • decompile's first line, analyze and error messages now name a method with its ref, out, in and ref readonly parameters and returns, such as TryGetValue(TKey, out TValue) → bool
  • analyze now writes a by-reference parameter of a method from an assembly it cannot resolve as ref, as in System.Threading.Interlocked.Increment(ref int)
  • list_members and compare now print a volatile field as volatile and an init-only setter as init, and no output shows the compiler's modreq markers for ref readonly, in, volatile or init
  • A parameter type pattern that starts with ref, out, in or ref readonly now matches only a parameter passed by reference, so a signature copied from ILens's output selects its overload
  • Type patterns now find nint and nuint by IntPtr, UIntPtr, System.IntPtr and System.UIntPtr as well as by the keywords, in find_methods, decompile and analyze, instead of answering that nothing matches
  • analyze now prints System.IntPtr and System.UIntPtr in the signature of a member from another assembly as nint and nuint, as it does for the assembly's own members, and nint and nuint select such an overload in parameter_types
  • A type written exactly as ILens prints it now always matches as a type pattern
  • decompile, compare and analyze now find a method a class implements explicitly for an interface by its plain name, such as Equals for IEquatable<T>.Equals, when no ordinary method of that name matches; an ordinary method of the name still wins, as in C#
  • decompile and analyze now find an explicitly implemented property or event by its plain name the same way, and its accessors by get_X or by the full name analyze prints, such as ICollection<T>.get_IsReadOnly
  • A plain name that several explicit implementations share, such as GetEnumerator for IEnumerable and IEnumerable<T>, is now an error that names each in full
  • The "No overload" error now lists the explicit implementations of the name among the available overloads
  • decompile, compare and analyze now select the indexer that parameter_types or parameter_count names on get_Item and set_Item, instead of always the first one
  • get_Item or set_Item without a hint on a type with several indexers is now an error listing them, as for other overloads, and call_sites without a hint covers them all
  • analyze on a property name that several indexers share is now an error listing them and pointing to get_Item and set_Item with parameter_types, instead of an answer for the first indexer alone; decompile's error points there the same way
  • analyze now names an indexer with its index types, such as Matrix3x2.Item[int, int], in its results, headers and errors, so two indexers of one type are two lines instead of one line Item
  • Naming a type the assembly only references no longer answers "Type not found": every tool now says the type is not defined in this assembly and names the assembly it comes from, and compare does the same for a type neither assembly defines
  • analyze now answers for a type from another assembly, from the inspected assembly's own references to it: used_by, instantiated_by, exposed_by, extension_methods, applied_to and implemented_by on the type, and used_by, read_by and assigned_by on its members, with overloads selected by parameter_count or parameter_types as usual
  • analyze's implemented_by on an interface from another assembly adds a line saying that types deriving from another assembly's class may implement it without the inspected assembly showing it
  • analyze on a type nothing in the assembly names returns an explicit empty answer saying so instead of an error, and a member name nothing references lists the members of that type the assembly does reference
  • analyze refuses uses, implements, and overridden_by or implemented_by on a member of a type from another assembly, and says why: the answer is in the other assembly; it answers call_sites there with an error that points to used_by
  • decompile, analyze and compare now answer a member a class inherits from a base class in another assembly with an error naming the member and the file its code is in, instead of saying that neither the class nor its base types declare it
  • decompile, analyze and compare now say, when a name is not found, which base class went unsearched because ILens could not load its assembly, and an unmatched overload hint also lists the overloads of base classes in other assemblies
  • decompile and analyze now find an extension method written for a base class from another assembly when it is asked for on a derived class
  • find_types lists public and protected types unless accessibility says otherwise, sorted by full name and up to limit, and with no filter every type
  • find_types answers a namespace that no type lies in with an error instead of an empty list
  • find_methods now opens with the number of methods, answers No methods when nothing matches, and no longer indents its lines
  • find_methods now writes each method as the other tools name it, without parameter names, such as static CallShapes.Target.Record(string, int) → void, and sorts the list by that name
  • find_methods now lists constructors, as .ctor
  • find_methods now hides what the compiler generated, such as a local function, unless include_compiler_generated is true, and answers a namespace no type lies in with an error
  • find_methods with type_name now lists only that type's methods, not those of every type sharing its name
  • list_members now lists the constructors first among the methods, under the type's name, such as public Settings(int value)
  • list_members now lists nested types in a group of their own, which kinds selects as nested_type
  • list_members now marks an obsolete member with [Obsolete]
  • list_members now hides what the compiler generated, such as an auto-property's backing field, unless include_compiler_generated is true
  • list_members now sorts each group by name, heads it with its count, such as 3 properties:, and answers No members of and the type's declaration when nothing is left
  • list_members now lists every indexer of a type, each with its indices, such as Item[int row] and Item[int row, int column] on Matrix3x2, instead of only the first one as a plain property Item
  • list_members with include_inherited now shows a method overridden from a generic base class once, as the type's own, instead of also listing the base class's declaration of it
  • list_members with include_inherited now lists what a class inherits from base classes in other assemblies, such as Unity's MonoBehaviour, wherever ILens finds those assemblies: beside the inspected one, at the top of an allowed folder, or among the installed .NET libraries
  • list_members with include_inherited now lists the members of core library base classes such as System.Exception, System.Attribute, System.ValueType and System.Enum, instead of none
  • list_members with include_inherited now ends with a Not shown: line naming a base class whose assembly ILens could not load, instead of stopping there without a sign
  • decompile now decompiles a field too, with the initializer the compiler moved into the constructors and only the using declarations the field needs
  • decompile reaches a constructor as .ctor and an accessor by its IL name, such as get_Count
  • decompile now opens a property's or event's code with the name of the member it found, without (property) or (event): an indexer with its index types, such as System.String.Chars[int], and an explicit implementation by its full name
  • decompile on a property or event accessor now shows its keyword with its modifiers, such as get, readonly get, set, init, add or remove, instead of only its attributes and body
  • decompile answers parameter_count or parameter_types without member_name with an error
  • The error for a name several kinds of member share no longer points to a kind-specific tool, and says that the type's decompiled code shows them all
  • decompile and analyze no longer take an extension method written for Task<TResult> as one for Task
  • analyze now opens with a count in the words of the kind asked, such as 3 readers of ExplicitMembers.Circle.Size [declared]:, and an empty answer reads No users of X, followed by the reason where ILens knows one
  • analyze now sorts its results by name and hides what the compiler generated, such as an iterator's state machine, unless include_compiler_generated is true
  • analyze now reports a use made inside a lambda, local function, iterator or async method under the member it is written in, instead of under a compiler-generated name, for used_by, read_by, assigned_by and instantiated_by
  • analyze's uses now includes what a method's lambdas and local functions use, and the whole body of an iterator or async method
  • analyze now answers parameter_count or parameter_types without member_name with an error instead of ignoring them, and does the same for parameter_name or non_default_only with a kind other than call_sites
  • analyze's implemented_by no longer lists an interface among its own implementers, nor the implementers of other interfaces sharing its name, such as IAstVisitor<T> for IAstVisitor
  • analyze's applied_to now finds attributes the compiler stores as flags, such as [Serializable]
  • analyze's used_by on an overriding member now lists only what refers to the override itself, the same at every depth of overriding
  • Every analyze answer about the callers or users of an override now ends with a line naming the method code actually calls
  • analyze's used_by, read_by, assigned_by and call_sites now say, for a member that implements an interface member explicitly, that code reaches it only through that interface member and name it, instead of an answer that read as proof the member is unused
  • assigned_by on a field no longer lists a method that only reads the field through its address, such as one that turns a number or an enum into text, calls a struct method that leaves it unchanged, or passes it to a ref parameter that is only read
  • read_by on a field no longer lists a method that only writes the field through its address, such as one that sets it to null or default, writes one of its members, or passes it as out
  • read_by and assigned_by on a field now mark a method that may read or write it through code they cannot see, such as a call into another assembly, with what received the field's address, as in (may write: calls UnityEngine.Rect.set_x(float) on it)
  • read_by and assigned_by follow the same rules on a field of a type from another assembly
  • read_by and assigned_by on a field now answer about five times faster on a large assembly
  • call_sites reports a call the decompiled C# does not show as a call, rather than leaving it out, so an empty answer means no such call exists
  • call_sites shows the calls to a property, indexer or event accessor that code makes by reading, assigning, incrementing or subscribing, such as gauge.Level += 3 or this[row, column], with the indices and the assigned value as arguments, and passes the value a compound assignment or an increment computes as the setter's value argument, such as gauge.Level + 3
  • call_sites writes a call to an extension method as a static call with the receiver first, such as Stamps.Stamp(box, "stamped", 2)
  • call_sites on a virtual method shows the calls made on an object whose class overrides it, such as dog.Die(3) for Creature.Die, and on an overriding method, such as Animal.Die, the calls made on an object of its class or a class deriving from it
  • compare now marks a changed type as it marks a changed member, with + for what only B has, - for what only A has and ~ for a change, sorts both lists by name and lists up to limit
  • compare takes format as csharp or il, and answers a parameter that does not apply at the level asked with an error instead of ignoring it
  • compare answers a property or event name with the names of its accessors to compare instead, and a namespace neither assembly has with an error
  • compare's headers now name the type found, as ILens prints it, instead of repeating the caller's spelling
  • compare now reports a type whose base class or interfaces moved to a same-named type of another arity or changed their type arguments, as a metadata change
  • compare now reports a type whose only change is inside a property or event accessor, and names the changed accessor on the member's line, such as ~ public int Level { get; set; } [get_Level]
  • compare no longer reports a method as changed when only the numbers the compiler gives the code it generates have shifted, as they do for every method after one that was added: those of lambdas, local functions, iterators, async methods, closure classes, cached delegates and method groups, base calls from generated code, anonymous types and delegates, and Burst wrappers
  • compare now reports a change inside a lambda, a local function, an iterator or an async method as a change of the method it is written in, including the changes it used to miss when the compiler moved that code into a class of its own
  • compare now compares a method Burst compiles together with the copy of its code that Burst keeps, X$BurstManaged, and its C# drill-down shows that copy
  • compare's member list no longer lists compiler-generated members, Burst's included, and now accepts include_compiler_generated to list them under their own names
  • compare now prints an added or removed indexer with its indices, instead of as a plain property Item
  • compare now writes a constructor under its type's name, such as public Foo(int x), instead of public void .ctor(int x)
  • compare now shows an accessor's keyword with its modifiers, as decompile does, when it prints an accessor's C#
  • compare with member_name now says when two bodies decompile alike while their IL differs, and answers such bodies, and identical ones, with the verdict line alone instead of a copy of the code
  • compare with format il now shows a method's IL together with that of the code generated for it
  • compare with member_name now shows the code of a method only one of the two builds has, under a header saying which build has it, such as "only B has it", instead of answering that the method does not exist
  • compare with member_name now answers a type neither build defines with "not found in either assembly", as it does without member_name
  • find_harmony_dependencies now answers in text instead of JSON, one line per dependency sorted by target, such as Prefix HarmonyMod.TargetA.Compute(string) <- HarmonyMod.OverloadPinnedPatch.Prefix [TypedAttribute], and takes limit
  • find_harmony_dependencies now writes types as the other tools do, such as int, List<int> and Outer.Inner, and names a type the patch code writes short by its full name when only one type has that name
  • find_harmony_dependencies now lists a patch method marked [HarmonyPrefix], [HarmonyPostfix], [HarmonyTranspiler] or [HarmonyFinalizer] with its patch type whatever its name, instead of as (none) with only the patched class
  • find_harmony_dependencies now takes each patch method's target from its own [HarmonyPatch] laid over the class's, so a class patching several methods or overloads lists each patched method
  • find_harmony_dependencies now lists reverse patches, and finds TargetMethod and TargetMethods methods by their [HarmonyTargetMethod] and [HarmonyTargetMethods] attributes as well as by their names
  • find_harmony_dependencies now also covers a class that names its targets only on its patch methods, such as one carrying only [HarmonyPatchCategory]
  • find_harmony_dependencies now names a getter or setter patch's target by its accessor, such as get_Prop, and classifies it TypedAttribute when the accessor is public
  • find_harmony_dependencies now lists a getter or setter patch that names no property, which Harmony binds to an indexer, with the indexer's accessor, such as get_Item(int) or set_Item(string, int), instead of the class with its index types; an indexer of a class in another assembly carries C#'s default name, Item, and a setter's value type is written ?
  • find_harmony_dependencies now lists a Harmony 2.4 patch on an event's add or remove accessor, an operator or a finalizer with the method it patches, such as add_Changed, op_Addition or Finalize, instead of a method type printed as Unknown(8) or a similar number, and marks one on a public event's accessor TypedAttribute, as it marks one on a public property's
  • find_harmony_dependencies now lists a constructor patch as .ctor or .cctor even when its attribute also names a method, which Harmony ignores there
  • find_harmony_dependencies now marks a patch on a constructor, finalizer, operator or indexer TypedAttribute wherever the patched class lives, unless a string names the class, since such a patch needs no member name
  • find_harmony_dependencies now lists a patch whose [HarmonyPatch] names its target class by a string, [HarmonyPatch("Namespace.Class", "Method", MethodType.Normal)], with that class and method instead of ?, marked StringTargeted wherever the class lives
  • find_harmony_dependencies' description now says that a target without parameter types names no overload, and that TypedAttribute and StringTargeted are also told apart for a constructor, finalizer, operator or indexer
  • find_harmony_dependencies now lists the target of a TargetMethod that looks it up by reflection with typeof(X).GetMethod("Y"), instead of ?
  • find_harmony_dependencies now lists the method a TargetMethod or TargetMethods finds by searching a type's methods for its name, marked TargetMethodSearch or TargetMethodsSearch because the patch's own tests pick the overload, instead of ?
  • find_harmony_dependencies now lists the target of a TargetMethod or TargetMethods that looks it up with AccessTools.DeclaredMethod, a property getter or setter lookup, a constructor lookup, or Harmony's extension spelling such as typeof(X).Method("Y"), instead of ?
  • find_harmony_dependencies now lists the target of a TargetMethod whose code makes a generic method of the method it looks up with MakeGenericMethod, instead of ?, and reads the same in a Harmony.Patch call
  • find_harmony_dependencies now reads a target that a SymbolExtensions.GetMethodInfo lambda names, pinned to the overload the lambda calls
  • find_harmony_dependencies now also lists a target whose class a lookup names as text, as "Namespace.Type:Method" or through AccessTools.TypeByName, or holds in a local, and one that TargetMethod returns from a field that Prepare or an initializer assigns
  • find_harmony_dependencies now lists a lookup wrapped in AccessTools.EnumeratorMoveNext or AsyncMoveNext with (Enumerator) or (Async) after the method, as for a [HarmonyPatch] with that method type
  • find_harmony_dependencies now adds a ? line beside the targets it reads when a TargetMethod or TargetMethods also looks a target up in a way it cannot read, such as a search for a compiler-generated method, instead of leaving that target out without a sign; a TargetMethod with such a line is DynamicTargetMethod
  • find_harmony_dependencies now writes a constructor patch or lookup without parameter types as .ctor(), the parameterless constructor Harmony binds, and a lookup given an empty parameter-type array with ()
  • find_harmony_dependencies now lists the patches a mod applies by calling Harmony.Patch, each with its target, its patch method and the kind the argument's position or name gives, labeled with the member that writes the values out, such as Prefix HarmonyMod.TargetK.Run <- HarmonyMod.ManualPatches.BeforeRun [PatchCall in HarmonyMod.ManualPatches.Apply]
  • find_harmony_dependencies now prints ? for a target or patch method of a Harmony.Patch call it cannot read, and ? ? <- ? for a call it cannot find in the decompiled code, instead of leaving them out
  • find_harmony_dependencies now gives a target for each "Type:Method" name in a list the mod writes out and loops over, and lists a target found by searching one class's methods for an exact name as PatchCallSearch, naming no overload, such as Postfix HarmonyMod.TargetA.Compute <- HarmonyMod.LoopPatches.AfterAny [PatchCallSearch in HarmonyMod.LoopPatches.Apply]
  • find_harmony_dependencies now follows a target, a patch method, or a looked-up field's class and name through a helper's parameters to each call of the helper, through a patch object's fields to each place that builds it, and through the mod's own methods to what they return
  • find_harmony_dependencies now reads a nested class found through AccessTools.Inner or Type.GetNestedType, a class named as text through Type.GetType or Assembly.GetType, GetType() on the calling object as the class declaring the calling member, and a property accessor taken from its PropertyInfo, in TargetMethod bodies and field lookups as well as in Harmony.Patch calls
  • find_harmony_dependencies now lists as a TargetMethod's targets only the values it returns or yields, so a method it looks up only to test a condition or to compute its targets from is no longer listed as a target, and a target computed at run time prints ?
  • find_harmony_dependencies now lists the fields an assembly looks up by reflection in any class, such as the static holders mods keep their field references in, instead of only in patch classes
  • find_harmony_dependencies now reads Harmony's field lookups in every form that names class and field: Field and DeclaredField by typeof, by "Type:field" text, through AccessTools.TypeByName or a local holding a class, FieldRefAccess, StaticFieldRefAccess and StructFieldRefAccess in all their overloads, and Harmony's extension spelling of each
  • find_harmony_dependencies now lists fields looked up through .NET's Type.GetField
  • find_harmony_dependencies now lists the fields Harmony hands a prefix, postfix or finalizer through a ___name parameter, as fields of the class the patch targets, labeled Injected, for a patch applied by attribute as for one applied by a Harmony.Patch call
  • find_harmony_dependencies now names the class of a Traverse field access from the type of the object it reads, given directly, held in a local or created from a class, also for the generic Field<T>, and prints ? instead of <runtime> where that type is unknown
  • find_harmony_dependencies now lists a Traverse field access whose receiver the decompiler writes with several casts, instead of leaving it out
  • find_harmony_dependencies now lists a field lookup it can read only in part with ? for the class or the field, and an enumeration of a class's fields such as Type.GetFields with ? for the field, instead of leaving them out
  • find_harmony_dependencies now labels each field line with the call that found it: AccessToolsField, DeclaredField, FieldRefAccess, StaticFieldRefAccess, StructFieldRefAccess, TraverseField, GetField, GetFields, GetDeclaredFields, GetFieldNames or Injected
  • find_harmony_dependencies now answers faster on a mod with many patch classes, since it decompiles only the methods that look up a field
  • decompile, analyze's call_sites, compare's C# view and find_harmony_dependencies now find an assembly's references at the top of each allowed directory, after the assembly's own folder, so the code of a mod whose game assemblies sit in another allowed directory shows enum names and properties instead of numbers and "Unknown result type" comments
  • A reference file that cannot be read no longer makes every tool fail on the assembly that references it; the reference is left unresolved
  • A reference file that links to a location outside every allowed directory is no longer opened, beside the inspected assembly as elsewhere
  • The memory budget (--max-total-size, default 200 MB) now bounds ILens's actual memory rather than the sum of the inspected files' sizes: when a call ends with ILens above it, the assemblies used longest ago are closed until it is back under three quarters of the budget, so a session over hundreds of assemblies no longer grows to gigabytes
  • A tool call no longer fails or reads corrupted data when a concurrent call makes ILens unload the assembly it is working on to stay within the memory budget
  • ILens now releases the referenced assemblies it opened beside an assembly as soon as it unloads that assembly, instead of keeping them locked
  • ILens now runs on .NET 10.0.12 instead of 10.0.10, with the .NET security fixes of August and September 2026
  • The user guide and README now describe the eight tools by their current names and parameters, and ask Claude Code users to paste nothing
  • The user guide now describes find_harmony_dependencies' patches from Harmony.Patch calls, its field lookups in every class with their labels, the lookups it reads and what each ? stands for, and names Harmony with a link to its repository
  • The user guide now describes call_sites writing an extension call as a static call, analyze's (may read: ...) and (may write: ...) marks on a field and its answers about overrides, compare's answers for a method only one build has and for two bodies that print alike, and list_members' inherited members from base classes in other assemblies
  • The user guide's security model now describes the memory budget as the process's own memory and names every place outside the allowed folders from which decompilation reads an assembly's references
  • The token-cost table in the README and the user guide is dated 2026-10-09