Output: Handle scoped type name resolution conflicts (CS0104)
This commit is contained in:
@@ -22,7 +22,7 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
public override string ToString() => DeclaringType.Name + "(" + string.Join(", ", DeclaredParameters.Select(x => x.ParameterType.Name)) + ")";
|
||||
|
||||
public override string GetSignatureString() => Name + GetTypeParametersString()
|
||||
public override string GetSignatureString(Scope usingScope) => Name + GetTypeParametersString(usingScope)
|
||||
+ "(" + string.Join(",", DeclaredParameters.Select(x => x.GetSignatureString())) + ")";
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace Il2CppInspector.Reflection
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(EventInfo evt) => getCustomAttributes(evt.Assembly, evt.Definition.token, evt.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(FieldInfo field) => getCustomAttributes(field.Assembly, field.Definition.token, field.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(MethodBase method) => getCustomAttributes(method.Assembly, method.Definition.token, method.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo param) => getCustomAttributes(param.Member.Assembly, param.Definition.token, param.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo param) => getCustomAttributes(param.DeclaringMethod.Assembly, param.Definition.token, param.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(PropertyInfo prop) => getCustomAttributes(prop.Assembly, prop.Definition.token, prop.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(TypeInfo type) => getCustomAttributes(type.Assembly, type.Definition.token, type.Definition.customAttributeIndex);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using System;
|
||||
/*
|
||||
Copyright 2017-2019 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -8,8 +14,8 @@ namespace Il2CppInspector.Reflection
|
||||
public static class Extensions
|
||||
{
|
||||
// Convert a list of CustomAttributeData objects into C#-friendly attribute usages
|
||||
public static string ToString(this IEnumerable<CustomAttributeData> attributes, string linePrefix = "", string attributePrefix = "",
|
||||
bool inline = false, bool emitPointer = false, bool mustCompile = false) {
|
||||
public static string ToString(this IEnumerable<CustomAttributeData> attributes, Scope scope = null,
|
||||
string linePrefix = "", string attributePrefix = "", bool inline = false, bool emitPointer = false, bool mustCompile = false) {
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var cad in attributes) {
|
||||
@@ -20,7 +26,7 @@ namespace Il2CppInspector.Reflection
|
||||
var commentStart = mustCompile && !parameterlessConstructor? inline? "/* " : "// " : "";
|
||||
var commentEnd = commentStart.Length > 0 && inline? " */" : "";
|
||||
|
||||
var name = cad.AttributeType.CSharpName;
|
||||
var name = cad.AttributeType.GetScopedCSharpName(scope);
|
||||
var suffix = name.LastIndexOf("Attribute", StringComparison.Ordinal);
|
||||
if (suffix != -1)
|
||||
name = name[..suffix];
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace Il2CppInspector.Reflection
|
||||
_ => ""
|
||||
};
|
||||
|
||||
public string GetModifierString() {
|
||||
public string GetModifierString(Scope usingScope) {
|
||||
// Interface methods and properties have no visible modifiers (they are always declared 'public abstract')
|
||||
if (DeclaringType.IsInterface)
|
||||
return string.Empty;
|
||||
@@ -151,7 +151,7 @@ namespace Il2CppInspector.Reflection
|
||||
modifiers.Append("extern ");
|
||||
|
||||
// Method hiding
|
||||
if ((DeclaringType.BaseType?.GetAllMethods().Any(m => m.GetSignatureString() == GetSignatureString() && m.IsHideBySig) ?? false)
|
||||
if ((DeclaringType.BaseType?.GetAllMethods().Any(m => m.GetSignatureString(usingScope) == GetSignatureString(usingScope) && m.IsHideBySig) ?? false)
|
||||
&& (((Attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.ReuseSlot && !IsVirtual)
|
||||
|| (Attributes & MethodAttributes.VtableLayoutMask) == MethodAttributes.NewSlot))
|
||||
modifiers.Append($"new ");
|
||||
@@ -166,13 +166,13 @@ namespace Il2CppInspector.Reflection
|
||||
}
|
||||
|
||||
// Get C# syntax-friendly list of parameters
|
||||
public string GetParametersString(bool emitPointer = false, bool commentAttributes = false)
|
||||
=> string.Join(", ", DeclaredParameters.Select(p => p.GetParameterString(emitPointer, commentAttributes)));
|
||||
public string GetParametersString(Scope usingScope, bool emitPointer = false, bool commentAttributes = false)
|
||||
=> string.Join(", ", DeclaredParameters.Select(p => p.GetParameterString(usingScope, emitPointer, commentAttributes)));
|
||||
|
||||
public string GetTypeParametersString() => GenericTypeParameters == null? "" :
|
||||
"<" + string.Join(", ", GenericTypeParameters.Select(p => p.CSharpName)) + ">";
|
||||
public string GetTypeParametersString(Scope usingScope) => GenericTypeParameters == null? "" :
|
||||
"<" + string.Join(", ", GenericTypeParameters.Select(p => p.GetScopedCSharpName(usingScope))) + ">";
|
||||
|
||||
public abstract string GetSignatureString();
|
||||
public abstract string GetSignatureString(Scope usingScope);
|
||||
|
||||
// List of operator overload metadata names
|
||||
// https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/operator-overloads
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Il2CppInspector.Reflection
|
||||
// TODO: Generic arguments (and on ConstructorInfo)
|
||||
public override string ToString() => ReturnType.Name + " " + Name + "(" + string.Join(", ", DeclaredParameters.Select(x => x.ParameterType.Name)) + ")";
|
||||
|
||||
public override string GetSignatureString() => ReturnParameter.GetSignatureString() + " " + Name + GetTypeParametersString()
|
||||
public override string GetSignatureString(Scope usingScope) => ReturnParameter.GetSignatureString() + " " + Name + GetTypeParametersString(usingScope)
|
||||
+ "(" + string.Join(",", DeclaredParameters.Select(x => x.GetSignatureString())) + ")";
|
||||
}
|
||||
}
|
||||
@@ -37,15 +37,15 @@ namespace Il2CppInspector.Reflection
|
||||
public bool IsOut => (Attributes & ParameterAttributes.Out) != 0;
|
||||
public bool IsRetval => (Attributes & ParameterAttributes.Retval) != 0;
|
||||
|
||||
// The member in which the parameter is defined
|
||||
public MemberInfo Member { get; }
|
||||
// The method in which the parameter is defined
|
||||
public MethodBase DeclaringMethod { get; }
|
||||
|
||||
// Name of parameter
|
||||
public string Name { get; }
|
||||
|
||||
// Type of this parameter
|
||||
private readonly int paramTypeUsage;
|
||||
public TypeInfo ParameterType => Member.Assembly.Model.GetTypeFromUsage(paramTypeUsage, MemberTypes.TypeInfo);
|
||||
public TypeInfo ParameterType => DeclaringMethod.Assembly.Model.GetTypeFromUsage(paramTypeUsage, MemberTypes.TypeInfo);
|
||||
|
||||
// Zero-indexed position of the parameter in parameter list
|
||||
public int Position { get; }
|
||||
@@ -53,7 +53,7 @@ namespace Il2CppInspector.Reflection
|
||||
// Create a parameter. Specify paramIndex == -1 for a return type parameter
|
||||
public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodBase declaringMethod) {
|
||||
Index = paramIndex;
|
||||
Member = declaringMethod;
|
||||
DeclaringMethod = declaringMethod;
|
||||
|
||||
if (paramIndex == -1) {
|
||||
Position = -1;
|
||||
@@ -96,15 +96,15 @@ namespace Il2CppInspector.Reflection
|
||||
+ (IsByRef? "ref " : "")
|
||||
+ (IsOut? "out " : "");
|
||||
|
||||
private string getCSharpSignatureString() => $"{GetModifierString()}{ParameterType.CSharpName}";
|
||||
private string getCSharpSignatureString(Scope scope) => $"{GetModifierString()}{ParameterType.GetScopedCSharpName(scope)}";
|
||||
public string GetSignatureString() => $"{GetModifierString()}{ParameterType.FullName}";
|
||||
|
||||
public string GetParameterString(bool emitPointer = false, bool compileAttributes = false) => IsRetval? null :
|
||||
(Position == 0 && Member.GetCustomAttributes("System.Runtime.CompilerServices.ExtensionAttribute").Any()? "this ":"")
|
||||
+ $"{CustomAttributes.ToString(inline: true, emitPointer: emitPointer, mustCompile: compileAttributes).Replace("[ParamArray]", "params")}"
|
||||
+ $"{getCSharpSignatureString()} {Name}"
|
||||
public string GetParameterString(Scope usingScope, bool emitPointer = false, bool compileAttributes = false) => IsRetval? null :
|
||||
(Position == 0 && DeclaringMethod.GetCustomAttributes("System.Runtime.CompilerServices.ExtensionAttribute").Any()? "this ":"")
|
||||
+ $"{CustomAttributes.ToString(usingScope, inline: true, emitPointer: emitPointer, mustCompile: compileAttributes).Replace("[ParamArray]", "params")}"
|
||||
+ $"{getCSharpSignatureString(usingScope)} {Name}"
|
||||
+ (HasDefaultValue ? " = " + DefaultValue.ToCSharpValue() + (emitPointer && !(DefaultValue is null)? $" /* Metadata: 0x{(uint) DefaultValueMetadataAddress:X8} */" : "") : "");
|
||||
|
||||
public string GetReturnParameterString() => !IsRetval? null : getCSharpSignatureString();
|
||||
public string GetReturnParameterString(Scope scope) => !IsRetval? null : getCSharpSignatureString(scope);
|
||||
}
|
||||
}
|
||||
20
Il2CppInspector/Reflection/Scope.cs
Normal file
20
Il2CppInspector/Reflection/Scope.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2017-2019 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Il2CppInspector.Reflection
|
||||
{
|
||||
// A code scope with which to evaluate how to output type references
|
||||
public class Scope
|
||||
{
|
||||
// The scope we are currently in
|
||||
public TypeInfo Current;
|
||||
|
||||
// The list of namespace using directives in the file
|
||||
public IEnumerable<string> Namespaces;
|
||||
}
|
||||
}
|
||||
@@ -143,6 +143,103 @@ namespace Il2CppInspector.Reflection {
|
||||
+ (IsArray? "[" + new string(',', GetArrayRank() - 1) + "]" : "")
|
||||
+ (IsPointer? "*" : "");
|
||||
|
||||
// Returns the minimally qualified type name required to refer to this type within the specified scope
|
||||
public string GetScopedFullName(Scope scope) {
|
||||
// This is the scope in which this type is currently being used
|
||||
// If Scope.Current is null, our scope is at the assembly level
|
||||
var usingScope = scope.Current?.FullName ?? "";
|
||||
|
||||
// This is the scope in which this type's definition is located
|
||||
var declaringScope = DeclaringType?.FullName ?? Namespace;
|
||||
|
||||
// If the scope of usage is inside the scope in which the type is declared, no additional scope is needed
|
||||
if ((usingScope + ".").StartsWith(declaringScope + ".") || (usingScope + "+").StartsWith(declaringScope + "+"))
|
||||
return base.Name;
|
||||
|
||||
// Global (unnamed) namespace?
|
||||
string scopedName;
|
||||
if (string.IsNullOrEmpty(declaringScope))
|
||||
scopedName = base.Name;
|
||||
|
||||
// Find first difference in the declaring scope from the using scope, moving one namespace/type name at a time
|
||||
else {
|
||||
var diff = 0;
|
||||
|
||||
usingScope += ".";
|
||||
while (usingScope.IndexOf(".", diff) == declaringScope.IndexOf(".", diff)
|
||||
&& usingScope.IndexOf(".", diff) != -1
|
||||
&& usingScope.Substring(0, usingScope.IndexOf(".", diff))
|
||||
== declaringScope.Substring(0, declaringScope.IndexOf(".", diff)))
|
||||
diff = usingScope.IndexOf(".", diff) + 1;
|
||||
|
||||
usingScope = usingScope.Substring(0, usingScope.Length -1) + "+";
|
||||
while (usingScope.IndexOf("+", diff) == declaringScope.IndexOf("+", diff)
|
||||
&& usingScope.IndexOf("+", diff) != -1
|
||||
&& usingScope.Substring(0, usingScope.IndexOf("+", diff))
|
||||
== declaringScope.Substring(0, declaringScope.IndexOf("+", diff)))
|
||||
diff = usingScope.IndexOf("+", diff) + 1;
|
||||
|
||||
scopedName = declaringScope.Substring(diff) + (DeclaringType != null? "+" : ".") + base.Name;
|
||||
}
|
||||
|
||||
// At this point, scopedName contains the minimum required scope, discounting any using directives
|
||||
// or whether there are conflicts with any ancestor scope
|
||||
|
||||
// Check to see if there is a namespace in our using directives which brings this type into scope
|
||||
var usingRef = scope.Namespaces.OrderByDescending(n => n.Length).FirstOrDefault(n => scopedName.StartsWith(n + "."));
|
||||
var minimallyScopedName = usingRef == null ? scopedName : scopedName.Substring(usingRef.Length + 1);
|
||||
|
||||
// minimallyScopedName now contains the minimum required scope, taking using directives into account
|
||||
|
||||
// Are there any ancestors in the using scope with the same type name as the first part of the minimally scoped name?
|
||||
// If so, the ancestor type name will hide the type we are trying to reference,
|
||||
// so we need to provide the scope ignoring any using directives
|
||||
var firstPart = minimallyScopedName.Split('.')[0].Split('+')[0];
|
||||
for (var d = scope.Current; d != null; d = d.DeclaringType)
|
||||
if (d.BaseName == firstPart)
|
||||
return scopedName.Replace('+', '.');
|
||||
|
||||
// If there are multiple using directives that would allow the same minimally scoped name to be used,
|
||||
// then the minimally scoped name is ambiguous and we can't use it
|
||||
// NOTE: We should check all the parts, not just the first part, but this works in the vast majority of cases
|
||||
if (scope.Namespaces.Count(n => Assembly.Model.TypesByFullName.ContainsKey(n + "." + firstPart)) > 1)
|
||||
return scopedName.Replace('+', '.');
|
||||
|
||||
return minimallyScopedName.Replace('+', '.');
|
||||
}
|
||||
|
||||
// C#-friendly type name as it should be used in the scope of a given type
|
||||
public string GetScopedCSharpName(Scope usingScope = null) {
|
||||
// Unscoped name if no using scope specified
|
||||
if (usingScope == null)
|
||||
return CSharpName;
|
||||
|
||||
var s = Namespace + "." + base.Name;
|
||||
|
||||
// Built-in keyword type names do not require a scope
|
||||
var i = Il2CppConstants.FullNameTypeString.IndexOf(s);
|
||||
var n = i != -1 ? Il2CppConstants.CSharpTypeString[i] : GetScopedFullName(usingScope);
|
||||
|
||||
// Unmangle generic type names
|
||||
if (n?.IndexOf("`", StringComparison.Ordinal) != -1)
|
||||
n = n?.Remove(n.IndexOf("`", StringComparison.Ordinal));
|
||||
|
||||
// Generic type parameters and type arguments
|
||||
var g = (GenericTypeParameters != null ? "<" + string.Join(", ", GenericTypeParameters.Select(x => x.GetScopedCSharpName(usingScope))) + ">" : "");
|
||||
g = (GenericTypeArguments != null ? "<" + string.Join(", ", GenericTypeArguments.Select(x => x.GetScopedCSharpName(usingScope))) + ">" : g);
|
||||
n += g;
|
||||
|
||||
// Nullable types
|
||||
if (s == "System.Nullable`1" && GenericTypeArguments.Any())
|
||||
n = GenericTypeArguments[0].GetScopedCSharpName(usingScope) + "?";
|
||||
|
||||
// Arrays, pointers, references
|
||||
if (HasElementType)
|
||||
n = ElementType.GetScopedCSharpName(usingScope);
|
||||
|
||||
return n + (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "") + (IsPointer ? "*" : "");
|
||||
}
|
||||
|
||||
public GenericParameterAttributes GenericParameterAttributes { get; }
|
||||
|
||||
public int GenericParameterPosition { get; }
|
||||
@@ -607,7 +704,7 @@ namespace Il2CppInspector.Reflection {
|
||||
return modifiers.ToString();
|
||||
}
|
||||
|
||||
public string GetTypeConstraintsString() {
|
||||
public string GetTypeConstraintsString(Scope scope) {
|
||||
if (!IsGenericParameter)
|
||||
return string.Empty;
|
||||
|
||||
@@ -620,7 +717,7 @@ namespace Il2CppInspector.Reflection {
|
||||
if (DeclaringMethod == null && DeclaringType.IsNested && (DeclaringType.DeclaringType.GenericTypeParameters?.Any(p => p.Name == Name) ?? false))
|
||||
return string.Empty;
|
||||
|
||||
var constraintList = typeConstraints.Where(c => c.FullName != "System.ValueType").Select(c => c.CSharpTypeDeclarationName).ToList();
|
||||
var constraintList = typeConstraints.Where(c => c.FullName != "System.ValueType").Select(c => c.GetScopedCSharpName(scope)).ToList();
|
||||
|
||||
if ((GenericParameterAttributes & GenericParameterAttributes.NotNullableValueTypeConstraint) == GenericParameterAttributes.NotNullableValueTypeConstraint)
|
||||
constraintList.Add("struct");
|
||||
|
||||
Reference in New Issue
Block a user