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
CSharp7_2 = 702, CSharp7_2 = 702,
CSharp7_3 = 703, CSharp7_3 = 703,
CSharp8_0 = 800, CSharp8_0 = 800,
CSharp9_0 = 900,
Latest = 0x7FFFFFFF Latest = 0x7FFFFFFF
} }
} }

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

@ -248,6 +248,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
AstType ConvertTypeHelper(IType type) 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 (type is TypeWithElementType typeWithElementType) {
if (typeWithElementType is PointerType) { if (typeWithElementType is PointerType) {
return ConvertType(typeWithElementType.ElementType).MakePointerType(); return ConvertType(typeWithElementType.ElementType).MakePointerType();

22
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -114,10 +114,15 @@ namespace ICSharpCode.Decompiler
staticLocalFunctions = false; staticLocalFunctions = false;
ranges = false; ranges = false;
} }
if (languageVersion < CSharp.LanguageVersion.CSharp9_0) {
nativeIntegers = false;
}
} }
public CSharp.LanguageVersion GetMinimumRequiredVersion() public CSharp.LanguageVersion GetMinimumRequiredVersion()
{ {
if (nativeIntegers)
return CSharp.LanguageVersion.CSharp9_0;
if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement || staticLocalFunctions || ranges) if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement || staticLocalFunctions || ranges)
return CSharp.LanguageVersion.CSharp8_0; return CSharp.LanguageVersion.CSharp8_0;
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers || patternBasedFixedStatement) if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers || patternBasedFixedStatement)
@ -141,6 +146,23 @@ namespace ICSharpCode.Decompiler
return CSharp.LanguageVersion.CSharp1; 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; bool anonymousMethods = true;
/// <summary> /// <summary>

35
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

@ -42,6 +42,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{ {
bool hasDynamicAttribute = false; bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null; bool[] dynamicAttributeData = null;
bool hasNativeIntegersAttribute = false;
bool[] nativeIntegersAttributeData = null;
string[] tupleElementNames = null; string[] tupleElementNames = null;
Nullability nullability; Nullability nullability;
Nullability[] nullableAttributeData = null; Nullability[] nullableAttributeData = null;
@ -50,7 +52,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
} else { } else {
nullability = Nullability.Oblivious; 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) { if (attributes != null && (options & relevantOptions) != 0) {
foreach (var attrHandle in attributes.Value) { foreach (var attrHandle in attributes.Value) {
var attr = metadata.GetCustomAttribute(attrHandle); var attr = metadata.GetCustomAttribute(attrHandle);
@ -65,6 +67,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
dynamicAttributeData = values.SelectArray(v => (bool)v.Value); 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)) { } else if ((options & TypeSystemOptions.Tuple) != 0 && attrType.IsKnownType(metadata, KnownAttribute.TupleElementNames)) {
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider); var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if (ctor.FixedArguments.Length == 1) { if (ctor.FixedArguments.Length == 1) {
@ -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) || (options & (TypeSystemOptions.Tuple | TypeSystemOptions.KeepModifiers)) != TypeSystemOptions.KeepModifiers)
{ {
var visitor = new ApplyAttributeTypeVisitor( var visitor = new ApplyAttributeTypeVisitor(
compilation, hasDynamicAttribute, dynamicAttributeData, compilation, hasDynamicAttribute, dynamicAttributeData,
hasNativeIntegersAttribute, nativeIntegersAttributeData,
options, tupleElementNames, options, tupleElementNames,
nullability, nullableAttributeData nullability, nullableAttributeData
); );
@ -109,6 +122,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
readonly ICompilation compilation; readonly ICompilation compilation;
readonly bool hasDynamicAttribute; readonly bool hasDynamicAttribute;
readonly bool[] dynamicAttributeData; readonly bool[] dynamicAttributeData;
readonly bool hasNativeIntegersAttribute;
readonly bool[] nativeIntegersAttributeData;
readonly TypeSystemOptions options; readonly TypeSystemOptions options;
readonly string[] tupleElementNames; readonly string[] tupleElementNames;
readonly Nullability defaultNullability; readonly Nullability defaultNullability;
@ -117,12 +132,17 @@ namespace ICSharpCode.Decompiler.TypeSystem
int tupleTypeIndex = 0; int tupleTypeIndex = 0;
int nullabilityTypeIndex = 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) Nullability defaultNullability, Nullability[] nullableAttributeData)
{ {
this.compilation = compilation ?? throw new ArgumentNullException(nameof(compilation)); this.compilation = compilation ?? throw new ArgumentNullException(nameof(compilation));
this.hasDynamicAttribute = hasDynamicAttribute; this.hasDynamicAttribute = hasDynamicAttribute;
this.dynamicAttributeData = dynamicAttributeData; this.dynamicAttributeData = dynamicAttributeData;
this.hasNativeIntegersAttribute = hasNativeIntegersAttribute;
this.nativeIntegersAttributeData = nativeIntegersAttributeData;
this.options = options; this.options = options;
this.tupleElementNames = tupleElementNames; this.tupleElementNames = tupleElementNames;
this.defaultNullability = defaultNullability; this.defaultNullability = defaultNullability;
@ -247,11 +267,18 @@ namespace ICSharpCode.Decompiler.TypeSystem
public override IType VisitTypeDefinition(ITypeDefinition type) public override IType VisitTypeDefinition(ITypeDefinition type)
{ {
IType newType = 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) if (dynamicAttributeData == null || dynamicTypeIndex >= dynamicAttributeData.Length)
newType = SpecialType.Dynamic; newType = SpecialType.Dynamic;
else if (dynamicAttributeData[dynamicTypeIndex]) else if (dynamicAttributeData[dynamicTypeIndex])
newType = SpecialType.Dynamic; 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) { if (type.IsReferenceType == true) {
Nullability nullability = GetNullability(); Nullability nullability = GetNullability();

7
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -110,10 +110,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
ReadOnlyMethods = 0x800, ReadOnlyMethods = 0x800,
/// <summary> /// <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. /// Default settings: typical options for the decompiler, with all C# languages features enabled.
/// </summary> /// </summary>
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters
| RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods | RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods
| NativeIntegers
} }
/// <summary> /// <summary>
@ -145,6 +150,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.NullabilityAnnotations; typeSystemOptions |= TypeSystemOptions.NullabilityAnnotations;
if (settings.ReadOnlyMethods) if (settings.ReadOnlyMethods)
typeSystemOptions |= TypeSystemOptions.ReadOnlyMethods; typeSystemOptions |= TypeSystemOptions.ReadOnlyMethods;
if (settings.NativeIntegers)
typeSystemOptions |= TypeSystemOptions.NativeIntegers;
return typeSystemOptions; return typeSystemOptions;
} }

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

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

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

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

21
ICSharpCode.Decompiler/TypeSystem/TypeUtils.cs

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

5
ILSpy/Languages/CSharpHighlightingTokenWriter.cs

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

1
ILSpy/Languages/CSharpLanguage.cs

@ -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_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.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.CSharp8_0.ToString(), "C# 8.0 / VS 2019"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp9_0.ToString(), "C# 9.0 (experimental)"),
}; };
} }
return versions; return versions;

18
ILSpy/Properties/Resources.Designer.cs generated

@ -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> /// <summary>
/// Looks up a localized string similar to Allow extension &apos;Add&apos; methods in collection initializer expressions. /// Looks up a localized string similar to Allow extension &apos;Add&apos; methods in collection initializer expressions.
/// </summary> /// </summary>
@ -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> /// <summary>
/// Looks up a localized string similar to Nullable reference types. /// Looks up a localized string similar to Nullable reference types.
/// </summary> /// </summary>

3
ILSpy/Properties/Resources.resx

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