Skip to content

Commit

Permalink
Update getScopedFullName for generic params + update README
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeFZ committed Feb 25, 2024
1 parent 0f7cd02 commit 2a492e0
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 14 deletions.
33 changes: 19 additions & 14 deletions Il2CppInspector.Common/Reflection/TypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,14 @@ public string FullName {
}

// Returns the minimally qualified type name required to refer to this type within the specified scope
private string getScopedFullName(Scope scope) {
private string getScopedFullName(Scope scope)
{
// Generic type parameters take precedence over all other names, so if FullName is null (== generic) we can just return the name itself
if (IsGenericParameter)
return this.Name;

// This is the type to be used (generic type parameters have a null FullName)
var usedType = FullName?.Replace('+', '.') ?? Name;
var usedType = FullName.Replace('+', '.');

// This is the scope in which this type is currently being used
// If Scope.Current is null, our scope is at the assembly level
Expand All @@ -439,14 +444,14 @@ private string getScopedFullName(Scope scope) {
declaringScope += ".";
while (usingScope.IndexOf('.', diff) == declaringScope.IndexOf('.', diff)
&& usingScope.IndexOf('.', diff) != -1
&& usingScope.Substring(0, usingScope.IndexOf('.', diff))
== declaringScope.Substring(0, declaringScope.IndexOf('.', diff)))
&& usingScope[..usingScope.IndexOf('.', diff)]
== declaringScope[..declaringScope.IndexOf('.', diff)])
diff = usingScope.IndexOf('.', diff) + 1;
usingScope = usingScope.Remove(usingScope.Length - 1);
declaringScope = declaringScope.Remove(declaringScope.Length - 1);

// This is the mutual root namespace and optionally nested types that the two scopes share
var mutualRootScope = usingScope.Substring(0, diff - 1);
var mutualRootScope = usingScope[..(diff - 1)];

// Determine if the using scope is a child of the declaring scope (always a child if declaring scope is empty)
var usingScopeIsChildOfDeclaringScope = string.IsNullOrEmpty(declaringScope) || (usingScope + ".").StartsWith(declaringScope + ".");
Expand All @@ -472,7 +477,7 @@ private string getScopedFullName(Scope scope) {
var minimallyScopedName =
declaringScope == mutualRootScope ? base.Name :
string.IsNullOrEmpty(mutualRootScope) ? declaringScope + '.' + base.Name :
declaringScope.Substring(mutualRootScope.Length + 1) + '.' + base.Name;
string.Concat(declaringScope.AsSpan(mutualRootScope.Length + 1), ".", base.Name);

// Find the outermost type name if the wanted type is a nested type (if we need it below)
string outerTypeName = "";
Expand All @@ -487,7 +492,7 @@ private string getScopedFullName(Scope scope) {
// Otherwise, we just try the unqualified outer (least nested) type name to make sure it's accessible
// and revert to the fully qualified name if it's hidden
var nsAndTypeHierarchy = usingScopeIsChildOfDeclaringScope ?
usingDirective.Split('.').Append(minimallyScopedName).ToArray()
[.. usingDirective.Split('.'), minimallyScopedName]
: new[] { outerTypeName };

var hidden = true;
Expand Down Expand Up @@ -548,24 +553,24 @@ private string getScopedFullName(Scope scope) {
.Select(ns => (!string.IsNullOrEmpty(ns)? ns + "." : "") + minimallyScopedName).ToList() ?? new List<string>();

if (Assembly.Model.Namespaces.Intersect(checkNamespaces).Any())
minimallyScopedName = mutualRootScope.Length > 0 ? usedType.Substring(mutualRootScope.Length + 1) : usedType;
minimallyScopedName = mutualRootScope.Length > 0 ? usedType[(mutualRootScope.Length + 1)..] : usedType;

// Check current namespace and all ancestors too
else {
checkNamespaces.Clear();
var ancestorUsingScope = "." + usingScope;
while (ancestorUsingScope.IndexOf(".", StringComparison.Ordinal) != -1) {
ancestorUsingScope = ancestorUsingScope.Substring(0, ancestorUsingScope.LastIndexOf(".", StringComparison.Ordinal));
checkNamespaces.Add((ancestorUsingScope.Length > 0 ? ancestorUsingScope.Substring(1) + "." : "") + minimallyScopedName);
while (ancestorUsingScope.Contains('.')) {
ancestorUsingScope = ancestorUsingScope[..ancestorUsingScope.LastIndexOf('.')];
checkNamespaces.Add((ancestorUsingScope.Length > 0 ? ancestorUsingScope[1..] + "." : "") + minimallyScopedName);
}

if (Assembly.Model.Namespaces.Intersect(checkNamespaces).Any())
minimallyScopedName = mutualRootScope.Length > 0 ? usedType.Substring(mutualRootScope.Length + 1) : "global::" + usedType;
minimallyScopedName = mutualRootScope.Length > 0 ? usedType[(mutualRootScope.Length + 1)..] : "global::" + usedType;
}

// If the final name starts with ".", it's a reference to the global namespace (ie. unnamed root namespace)
if (minimallyScopedName.StartsWith("."))
minimallyScopedName = "global::" + minimallyScopedName.Substring(1);
if (minimallyScopedName.StartsWith('.'))
minimallyScopedName = "global::" + minimallyScopedName[1..];

return minimallyScopedName;
}
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ This is a continuation of [Il2CppInspector, by djkaty](https://github.com/djkaty
- Made ValueTypes use their non-boxed variants when used as the this parameter
- Added labeling of FieldInfo/FieldRva MetadataUsages and their respective values as comments
- Implemented name mangling to properly display generics and other normally-replaced characters
* Overhauled IDA script:
- Added a progress indicator box with the current step, progress, and elapsed time
- Much faster processing compared to the old version
- Automatic disabling and re-enabling of autoanalysis
- Automatic unloading of conflicting type libraries
- Addition of custom fake string segment to show string literal contents in decompiler
- A fake xref between MethodInfo instances and their corresponding method to quickly get the correct function

### Main features

Expand Down

0 comments on commit 2a492e0

Please sign in to comment.