Browse Source

Add support for decoding `NativeIntegerAttribute`.

pull/2063/head
Daniel Grunwald 5 years ago
parent
commit
c9e41d0582
  1. 1
      ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs
  2. 6
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  3. 22
      ICSharpCode.Decompiler/DecompilerSettings.cs
  4. 35
      ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
  5. 7
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  6. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  7. 7
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  8. 21
      ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs
  9. 5
      ILSpy/Languages/CSharpHighlightingTokenWriter.cs
  10. 1
      ILSpy/Languages/CSharpLanguage.cs
  11. 18
      ILSpy/Properties/Resources.Designer.cs
  12. 3
      ILSpy/Properties/Resources.resx

1
ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs

@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.CSharp
CSharp7_2 = 702,
CSharp7_3 = 703,
CSharp8_0 = 800,
CSharp9_0 = 900,
Latest = 0x7FFFFFFF
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -248,6 +248,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -248,6 +248,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
AstType ConvertTypeHelper(IType type)
{
switch (type.Kind) {
case TypeKind.Dynamic:
case TypeKind.NInt:
case TypeKind.NUInt:
return new PrimitiveType(type.Name);
}
if (type is TypeWithElementType typeWithElementType) {
if (typeWithElementType is PointerType) {
return ConvertType(typeWithElementType.ElementType).MakePointerType();

22
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -114,10 +114,15 @@ namespace ICSharpCode.Decompiler @@ -114,10 +114,15 @@ namespace ICSharpCode.Decompiler
staticLocalFunctions = false;
ranges = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp9_0) {
nativeIntegers = false;
}
}
public CSharp.LanguageVersion GetMinimumRequiredVersion()
{
if (nativeIntegers)
return CSharp.LanguageVersion.CSharp9_0;
if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement || staticLocalFunctions || ranges)
return CSharp.LanguageVersion.CSharp8_0;
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers || patternBasedFixedStatement)
@ -141,6 +146,23 @@ namespace ICSharpCode.Decompiler @@ -141,6 +146,23 @@ namespace ICSharpCode.Decompiler
return CSharp.LanguageVersion.CSharp1;
}
bool nativeIntegers = true;
/// <summary>
/// Use C# 9 <c>nint</c>/<c>nuint</c> types.
/// </summary>
[Category("C# 9.0 (experimental)")]
[Description("DecompilerSettings.NativeIntegers")]
public bool NativeIntegers {
get { return nativeIntegers; }
set {
if (nativeIntegers != value) {
nativeIntegers = value;
OnPropertyChanged();
}
}
}
bool anonymousMethods = true;
/// <summary>

35
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

@ -42,6 +42,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -42,6 +42,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null;
bool hasNativeIntegersAttribute = false;
bool[] nativeIntegersAttributeData = null;
string[] tupleElementNames = null;
Nullability nullability;
Nullability[] nullableAttributeData = null;
@ -50,7 +52,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -50,7 +52,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
} else {
nullability = Nullability.Oblivious;
}
const TypeSystemOptions relevantOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations;
const TypeSystemOptions relevantOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers;
if (attributes != null && (options & relevantOptions) != 0) {
foreach (var attrHandle in attributes.Value) {
var attr = metadata.GetCustomAttribute(attrHandle);
@ -65,6 +67,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -65,6 +67,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
dynamicAttributeData = values.SelectArray(v => (bool)v.Value);
}
}
} else if ((options & TypeSystemOptions.NativeIntegers) != 0 && attrType.IsKnownType(metadata, KnownAttribute.NativeInteger)) {
hasNativeIntegersAttribute = true;
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if (ctor.FixedArguments.Length == 1) {
var arg = ctor.FixedArguments[0];
if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& values.All(v => v.Value is bool)) {
nativeIntegersAttributeData = values.SelectArray(v => (bool)v.Value);
}
}
} else if ((options & TypeSystemOptions.Tuple) != 0 && attrType.IsKnownType(metadata, KnownAttribute.TupleElementNames)) {
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if (ctor.FixedArguments.Length == 1) {
@ -88,11 +100,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -88,11 +100,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
}
if (hasDynamicAttribute || nullability != Nullability.Oblivious || nullableAttributeData != null
if (hasDynamicAttribute || hasNativeIntegersAttribute || nullability != Nullability.Oblivious || nullableAttributeData != null
|| (options & (TypeSystemOptions.Tuple | TypeSystemOptions.KeepModifiers)) != TypeSystemOptions.KeepModifiers)
{
var visitor = new ApplyAttributeTypeVisitor(
compilation, hasDynamicAttribute, dynamicAttributeData,
hasNativeIntegersAttribute, nativeIntegersAttributeData,
options, tupleElementNames,
nullability, nullableAttributeData
);
@ -109,6 +122,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -109,6 +122,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
readonly ICompilation compilation;
readonly bool hasDynamicAttribute;
readonly bool[] dynamicAttributeData;
readonly bool hasNativeIntegersAttribute;
readonly bool[] nativeIntegersAttributeData;
readonly TypeSystemOptions options;
readonly string[] tupleElementNames;
readonly Nullability defaultNullability;
@ -117,12 +132,17 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -117,12 +132,17 @@ namespace ICSharpCode.Decompiler.TypeSystem
int tupleTypeIndex = 0;
int nullabilityTypeIndex = 0;
private ApplyAttributeTypeVisitor(ICompilation compilation, bool hasDynamicAttribute, bool[] dynamicAttributeData, TypeSystemOptions options, string[] tupleElementNames,
private ApplyAttributeTypeVisitor(ICompilation compilation,
bool hasDynamicAttribute, bool[] dynamicAttributeData,
bool hasNativeIntegersAttribute, bool[] nativeIntegersAttributeData,
TypeSystemOptions options, string[] tupleElementNames,
Nullability defaultNullability, Nullability[] nullableAttributeData)
{
this.compilation = compilation ?? throw new ArgumentNullException(nameof(compilation));
this.hasDynamicAttribute = hasDynamicAttribute;
this.dynamicAttributeData = dynamicAttributeData;
this.hasNativeIntegersAttribute = hasNativeIntegersAttribute;
this.nativeIntegersAttributeData = nativeIntegersAttributeData;
this.options = options;
this.tupleElementNames = tupleElementNames;
this.defaultNullability = defaultNullability;
@ -247,11 +267,18 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -247,11 +267,18 @@ namespace ICSharpCode.Decompiler.TypeSystem
public override IType VisitTypeDefinition(ITypeDefinition type)
{
IType newType = type;
if (type.KnownTypeCode == KnownTypeCode.Object && hasDynamicAttribute) {
var ktc = type.KnownTypeCode;
if (ktc == KnownTypeCode.Object && hasDynamicAttribute) {
if (dynamicAttributeData == null || dynamicTypeIndex >= dynamicAttributeData.Length)
newType = SpecialType.Dynamic;
else if (dynamicAttributeData[dynamicTypeIndex])
newType = SpecialType.Dynamic;
} else if ((ktc == KnownTypeCode.IntPtr || ktc == KnownTypeCode.UIntPtr) && hasNativeIntegersAttribute) {
// native integers use the same indexing logic as 'dynamic'
if (nativeIntegersAttributeData == null || dynamicTypeIndex > nativeIntegersAttributeData.Length)
newType = (ktc == KnownTypeCode.IntPtr ? SpecialType.NInt : SpecialType.NUInt);
else if (nativeIntegersAttributeData[dynamicTypeIndex])
newType = (ktc == KnownTypeCode.IntPtr ? SpecialType.NInt : SpecialType.NUInt);
}
if (type.IsReferenceType == true) {
Nullability nullability = GetNullability();

7
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -110,10 +110,15 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -110,10 +110,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
ReadOnlyMethods = 0x800,
/// <summary>
/// [NativeIntegerAttribute] is used to replace 'IntPtr' types with the 'nint' type.
/// </summary>
NativeIntegers = 0x1000,
/// <summary>
/// Default settings: typical options for the decompiler, with all C# languages features enabled.
/// </summary>
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters
| RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods
| NativeIntegers
}
/// <summary>
@ -145,6 +150,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -145,6 +150,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.NullabilityAnnotations;
if (settings.ReadOnlyMethods)
typeSystemOptions |= TypeSystemOptions.ReadOnlyMethods;
if (settings.NativeIntegers)
typeSystemOptions |= TypeSystemOptions.NativeIntegers;
return typeSystemOptions;
}

2
ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs

@ -194,6 +194,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -194,6 +194,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
switch (attributeType.Name) {
case "DynamicAttribute":
return (options & TypeSystemOptions.Dynamic) != 0;
case "NativeIntegerAttribute":
return (options & TypeSystemOptions.NativeIntegers) != 0;
case "TupleElementNamesAttribute":
return (options & TypeSystemOptions.Tuple) != 0;
case "ExtensionAttribute":

7
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -98,11 +98,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -98,11 +98,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
// Security attributes:
PermissionSet,
// C# 9 attributes:
NativeInteger,
}
static class KnownAttributes
{
internal const int Count = (int)KnownAttribute.PermissionSet + 1;
internal const int Count = (int)KnownAttribute.NativeInteger + 1;
static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{
default,
@ -160,6 +163,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -160,6 +163,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.InteropServices", nameof(MarshalAsAttribute)),
// Security attributes:
new TopLevelTypeName("System.Security.Permissions", "PermissionSetAttribute"),
// C# 9 attributes:
new TopLevelTypeName("System.Runtime.CompilerServices", "NativeIntegerAttribute"),
};
public static ref readonly TopLevelTypeName GetTypeName(this KnownAttribute attr)

21
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

@ -36,6 +36,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -36,6 +36,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
case TypeKind.Pointer:
case TypeKind.ByReference:
case TypeKind.Class:
case TypeKind.NInt:
case TypeKind.NUInt:
return NativeIntSize;
case TypeKind.Enum:
type = type.GetEnumUnderlyingType();
@ -243,6 +245,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -243,6 +245,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
case TypeKind.ByReference:
return StackType.Ref;
case TypeKind.Pointer:
case TypeKind.NInt:
case TypeKind.NUInt:
return StackType.I;
case TypeKind.TypeParameter:
// Type parameters are always considered StackType.O, even
@ -305,8 +309,13 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -305,8 +309,13 @@ namespace ICSharpCode.Decompiler.TypeSystem
public static Sign GetSign(this IType type)
{
type = type.SkipModifiers();
if (type.Kind == TypeKind.Pointer)
return Sign.Unsigned;
switch (type.Kind) {
case TypeKind.Pointer:
case TypeKind.NUInt:
return Sign.Unsigned;
case TypeKind.NInt:
return Sign.Signed;
}
var typeDef = type.GetEnumUnderlyingType().GetDefinition();
if (typeDef == null)
return Sign.None;
@ -375,8 +384,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -375,8 +384,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
public static PrimitiveType ToPrimitiveType(this IType type)
{
type = type.SkipModifiers();
if (type.Kind == TypeKind.Unknown) return PrimitiveType.Unknown;
if (type.Kind == TypeKind.ByReference) return PrimitiveType.Ref;
switch (type.Kind) {
case TypeKind.Unknown: return PrimitiveType.Unknown;
case TypeKind.ByReference: return PrimitiveType.Ref;
case TypeKind.NInt: return PrimitiveType.I;
case TypeKind.NUInt: return PrimitiveType.U;
}
var def = type.GetEnumUnderlyingType().GetDefinition();
return def != null ? def.KnownTypeCode.ToPrimitiveType() : PrimitiveType.None;
}

5
ILSpy/Languages/CSharpHighlightingTokenWriter.cs

@ -298,12 +298,15 @@ namespace ICSharpCode.ILSpy @@ -298,12 +298,15 @@ namespace ICSharpCode.ILSpy
case "ushort":
case "ulong":
case "unmanaged":
case "nint":
case "nuint":
color = valueTypeKeywordsColor;
break;
case "class":
case "object":
case "string":
case "void":
case "dynamic":
color = referenceTypeKeywordsColor;
break;
}
@ -327,7 +330,7 @@ namespace ICSharpCode.ILSpy @@ -327,7 +330,7 @@ namespace ICSharpCode.ILSpy
{
color = valueKeywordColor;
}
if ((identifier.Name == "dynamic" || identifier.Name == "var") && identifier.Parent is AstType)
if (identifier.Name == "var" && identifier.Parent is AstType)
color = queryKeywordsColor;
switch (GetCurrentDefinition()) {
case ITypeDefinition t:

1
ILSpy/Languages/CSharpLanguage.cs

@ -107,6 +107,7 @@ namespace ICSharpCode.ILSpy @@ -107,6 +107,7 @@ namespace ICSharpCode.ILSpy
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7_2.ToString(), "C# 7.2 / VS 2017.4"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7_3.ToString(), "C# 7.3 / VS 2017.7"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp8_0.ToString(), "C# 8.0 / VS 2019"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp9_0.ToString(), "C# 9.0 (experimental)"),
};
}
return versions;

18
ILSpy/Properties/Resources.Designer.cs generated

@ -576,15 +576,6 @@ namespace ICSharpCode.ILSpy.Properties { @@ -576,15 +576,6 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Aggressively perform Scalar Replacement Of Aggregates (SROA).
/// </summary>
public static string DecompilerSettings_AggressiveScalarReplacementOfAggregates {
get {
return ResourceManager.GetString("DecompilerSettings.AggressiveScalarReplacementOfAggregates", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Allow extension &apos;Add&apos; methods in collection initializer expressions.
/// </summary>
@ -920,6 +911,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -920,6 +911,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Use nint/nuint types.
/// </summary>
public static string DecompilerSettings_NativeIntegers {
get {
return ResourceManager.GetString("DecompilerSettings.NativeIntegers", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Nullable reference types.
/// </summary>

3
ILSpy/Properties/Resources.resx

@ -873,4 +873,7 @@ Do you want to continue?</value> @@ -873,4 +873,7 @@ Do you want to continue?</value>
<data name="DecompilerSettings.UseSdkStyleProjectFormat" xml:space="preserve">
<value>Use new SDK style format for generated project files (*.csproj)</value>
</data>
<data name="DecompilerSettings.NativeIntegers" xml:space="preserve">
<value>Use nint/nuint types</value>
</data>
</root>
Loading…
Cancel
Save