Browse Source

Upgrade C# 8.0 nullability support for Roslyn 3.2.0-beta4.

pull/1612/head
Daniel Grunwald 6 years ago
parent
commit
b75c252193
  1. 1
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  2. 4
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 52
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullableRefTypes.cs
  4. 2
      ICSharpCode.Decompiler/CSharp/Resolver/Log.cs
  5. 6
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
  6. 6
      ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs
  7. 12
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  8. 11
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  9. 25
      ICSharpCode.Decompiler/SRMExtensions.cs
  10. 55
      ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
  11. 6
      ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs
  12. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  13. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  14. 6
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataEvent.cs
  15. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs
  16. 20
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  17. 21
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs
  18. 7
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs
  19. 10
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs
  20. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs
  21. 13
      ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs
  22. 4
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs
  23. 7
      ICSharpCode.Decompiler/TypeSystem/Implementation/TypeWithElementType.cs
  24. 10
      ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs
  25. 14
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
  26. 10
      ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

1
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
"System.Runtime.CompilerServices.IsByRefLikeAttribute",
"System.Runtime.CompilerServices.IsUnmanagedAttribute",
"System.Runtime.CompilerServices.NullableAttribute",
"System.Runtime.CompilerServices.NullableContextAttribute",
"Microsoft.CodeAnalysis.EmbeddedAttribute",
};

4
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -42,8 +42,8 @@ @@ -42,8 +42,8 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.0-beta3-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.2.0-beta3-final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.0-beta4-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.2.0-beta4-final" />
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" Version="1.1.0-beta1-63314-01" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />

52
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullableRefTypes.cs

@ -1,15 +1,20 @@ @@ -1,15 +1,20 @@
#nullable enable
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class NullableRefTypes
public class T01_NullableRefTypes
{
private string field_string;
private string? field_nullable_string;
private dynamic? field_nullable_dynamic;
private Dictionary<string?, string> field_generic;
private Dictionary<int, string?[]> field_generic2;
private Dictionary<int?, string?[]> field_generic3;
private KeyValuePair<string?, string> field_generic_value_type;
private KeyValuePair<string?, string>? field_generic_nullable_value_type;
private (string, string?, string) field_tuple;
private string[]?[] field_array;
private Dictionary<(string, string?), (int, string[]?, string?[])> field_complex;
@ -28,5 +33,50 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -28,5 +33,50 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return field_nullable_string?.Length + arr?.Length;
}
public void GenericNullable<T1, T2>((T1?, T1, T2, T2?, T1, T1?) x) where T1 : class where T2 : struct
{
}
public T ByRef<T>(ref T t)
{
return t;
}
public void CallByRef(ref string a, ref string? b)
{
ByRef(ref a).ToString();
ByRef(ref b)!.ToString();
}
}
public class T02_EverythingIsNullableInHere
{
private string? field1;
private object? field2;
// value types are irrelevant for the nullability attributes:
private int field3;
private int? field4;
public string? Property {
get;
set;
}
public event EventHandler? Event;
}
public class T03_EverythingIsNotNullableInHere
{
private string field1;
private object field2;
// value types are irrelevant for the nullability attributes:
private int field3;
private int? field4;
public string Property {
get;
set;
}
public event EventHandler Event;
}
}

2
ICSharpCode.Decompiler/CSharp/Resolver/Log.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -29,7 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
static class Log
{
const bool logEnabled = false;
const bool logEnabled = true;
#if __MonoCS__
[Conditional("MCS_DEBUG")]
#else

6
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -570,7 +570,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -570,7 +570,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
void MakeExactInference(IType U, IType V)
{
Log.WriteLine("MakeExactInference from " + U + " to " + V);
if (V is NullabilityAnnotatedTypeParameter nullableTP) {
V = nullableTP.OriginalTypeParameter;
}
// If V is one of the unfixed Xi then U is added to the set of bounds for Xi.
TP tp = GetTPForType(V);
if (tp != null && tp.IsFixed == false) {

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

@ -83,6 +83,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -83,6 +83,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
public bool HasOnlyNullableSpecifier {
get {
return HasNullableSpecifier && !HasRefSpecifier && !HasReadOnlySpecifier && PointerRank == 0 && ArraySpecifiers.Count == 0;
}
}
public CSharpTokenNode NullableSpecifierToken {
get {
return GetChildByRole(NullableRole);

12
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -777,8 +777,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -777,8 +777,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
default:
return false;
}
if (!ev.ReturnType.IsMatch(m.Get("type").Single()))
return false; // variable types must match event type
if (!ev.ReturnType.IsMatch(m.Get("type").Single())) {
// Variable types must match event type,
// except that the event type may have an additional nullability annotation
if (ev.ReturnType is ComposedType ct && ct.HasOnlyNullableSpecifier) {
if (!ct.BaseType.IsMatch(m.Get("type").Single()))
return false;
} else {
return false;
}
}
var combineMethod = m.Get<AstNode>("delegateCombine").Single().Parent.GetSymbol() as IMethod;
if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove"))
return false;

11
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -413,8 +413,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -413,8 +413,15 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(this.ILInstructions)
.WithRR(new ConstantResolveResult(targetType, null));
}
if (allowImplicitConversion && conversions.ImplicitConversion(ResolveResult, targetType).IsValid) {
return this;
if (allowImplicitConversion) {
if (conversions.ImplicitConversion(ResolveResult, targetType).IsValid) {
return this;
}
} else {
if (NormalizeTypeVisitor.RemoveModifiersAndNullability.EquivalentTypes(type, targetType)) {
// avoid an explicit cast when types differ only in nullability of reference types
return this;
}
}
var castExpr = new CastExpression(expressionBuilder.ConvertType(targetType), Expression);
bool needsCheckAnnotation = targetUType.GetStackType().IsIntegerType();

25
ICSharpCode.Decompiler/SRMExtensions.cs

@ -1,13 +1,10 @@ @@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using SRM = System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using System.Reflection.Metadata.Ecma335;
@ -371,6 +368,28 @@ namespace ICSharpCode.Decompiler @@ -371,6 +368,28 @@ namespace ICSharpCode.Decompiler
{
return attr.GetAttributeType(metadata).IsKnownType(metadata, attrType);
}
public static Nullability? GetNullableContext(this CustomAttributeHandleCollection customAttributes, MetadataReader metadata)
{
foreach (var handle in customAttributes) {
var customAttribute = metadata.GetCustomAttribute(handle);
if (customAttribute.IsKnownAttribute(metadata, KnownAttribute.NullableContext)) {
// Decode
CustomAttributeValue<IType> value;
try {
value = customAttribute.DecodeValue(Metadata.MetadataExtensions.MinimalAttributeTypeProvider);
} catch (BadImageFormatException) {
continue;
} catch (Metadata.EnumUnderlyingTypeResolveException) {
continue;
}
if (value.FixedArguments.Length == 1 && value.FixedArguments[0].Value is byte b && b <= 2) {
return (Nullability)b;
}
}
}
return null;
}
#endregion
public static unsafe SRM.BlobReader GetInitialValue(this FieldDefinition field, PEReader pefile, ICompilation typeSystem)

55
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

@ -37,14 +37,19 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -37,14 +37,19 @@ namespace ICSharpCode.Decompiler.TypeSystem
SRM.CustomAttributeHandleCollection? attributes,
SRM.MetadataReader metadata,
TypeSystemOptions options,
Nullability nullableContext,
bool typeChildrenOnly = false)
{
bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null;
string[] tupleElementNames = null;
bool hasNullableAttribute = false;
Nullability nullability = Nullability.Oblivious;
Nullability nullability;
Nullability[] nullableAttributeData = null;
if ((options & TypeSystemOptions.NullabilityAnnotations) != 0) {
nullability = nullableContext;
} else {
nullability = Nullability.Oblivious;
}
const TypeSystemOptions relevantOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations;
if (attributes != null && (options & relevantOptions) != 0) {
foreach (var attrHandle in attributes.Value) {
@ -70,7 +75,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -70,7 +75,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
} else if ((options & TypeSystemOptions.NullabilityAnnotations) != 0 && attrType.IsKnownType(metadata, KnownAttribute.Nullable)) {
hasNullableAttribute = true;
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if (ctor.FixedArguments.Length == 1) {
var arg = ctor.FixedArguments[0];
@ -78,13 +82,15 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -78,13 +82,15 @@ namespace ICSharpCode.Decompiler.TypeSystem
&& values.All(v => v.Value is byte b && b <= 2)) {
nullableAttributeData = values.SelectArray(v => (Nullability)(byte)v.Value);
} else if (arg.Value is byte b && b <= 2) {
nullability = (Nullability)(byte)arg.Value;
nullability = (Nullability)b;
}
}
}
}
}
if (hasDynamicAttribute || hasNullableAttribute || (options & (TypeSystemOptions.Tuple | TypeSystemOptions.KeepModifiers)) != TypeSystemOptions.KeepModifiers) {
if (hasDynamicAttribute || nullability != Nullability.Oblivious || nullableAttributeData != null
|| (options & (TypeSystemOptions.Tuple | TypeSystemOptions.KeepModifiers)) != TypeSystemOptions.KeepModifiers)
{
var visitor = new ApplyAttributeTypeVisitor(
compilation, hasDynamicAttribute, dynamicAttributeData,
options, tupleElementNames,
@ -148,16 +154,21 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -148,16 +154,21 @@ namespace ICSharpCode.Decompiler.TypeSystem
Nullability GetNullability()
{
if (nullabilityTypeIndex < nullableAttributeData?.Length)
return nullableAttributeData[nullabilityTypeIndex];
return nullableAttributeData[nullabilityTypeIndex++];
else
return defaultNullability;
}
void ExpectDummyNullabilityForGenericValueType()
{
var n = GetNullability();
Debug.Assert(n == Nullability.Oblivious);
}
public override IType VisitArrayType(ArrayType type)
{
var nullability = GetNullability();
dynamicTypeIndex++;
nullabilityTypeIndex++;
return base.VisitArrayType(type).ChangeNullability(nullability);
}
@ -181,18 +192,18 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -181,18 +192,18 @@ namespace ICSharpCode.Decompiler.TypeSystem
elementNames = ImmutableArray.CreateRange(extractedValues);
}
tupleTypeIndex += tupleCardinality;
ExpectDummyNullabilityForGenericValueType();
var elementTypes = ImmutableArray.CreateBuilder<IType>(tupleCardinality);
do {
int normalArgCount = Math.Min(type.TypeArguments.Count, TupleType.RestPosition - 1);
for (int i = 0; i < normalArgCount; i++) {
dynamicTypeIndex++;
nullabilityTypeIndex++;
elementTypes.Add(type.TypeArguments[i].AcceptVisitor(this));
}
if (type.TypeArguments.Count == TupleType.RestPosition) {
type = type.TypeArguments.Last() as ParameterizedType;
ExpectDummyNullabilityForGenericValueType();
dynamicTypeIndex++;
nullabilityTypeIndex++;
if (type != null && TupleType.IsTupleCompatible(type, out int nestedCardinality)) {
tupleTypeIndex += nestedCardinality;
} else {
@ -218,11 +229,13 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -218,11 +229,13 @@ namespace ICSharpCode.Decompiler.TypeSystem
// Visit generic type and type arguments.
// Like base implementation, except that it increments dynamicTypeIndex.
var genericType = type.GenericType.AcceptVisitor(this);
if (genericType.IsReferenceType != true && !genericType.IsKnownType(KnownTypeCode.NullableOfT)) {
ExpectDummyNullabilityForGenericValueType();
}
bool changed = type.GenericType != genericType;
var arguments = new IType[type.TypeArguments.Count];
for (int i = 0; i < type.TypeArguments.Count; i++) {
dynamicTypeIndex++;
nullabilityTypeIndex++;
arguments[i] = type.TypeArguments[i].AcceptVisitor(this);
changed = changed || arguments[i] != type.TypeArguments[i];
}
@ -240,8 +253,28 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -240,8 +253,28 @@ namespace ICSharpCode.Decompiler.TypeSystem
else if (dynamicAttributeData[dynamicTypeIndex])
newType = SpecialType.Dynamic;
}
if (type.IsReferenceType == true) {
Nullability nullability = GetNullability();
return newType.ChangeNullability(nullability);
} else {
return newType;
}
}
public override IType VisitOtherType(IType type)
{
type = base.VisitOtherType(type);
if (type.Kind == TypeKind.Unknown && type.IsReferenceType == true) {
Nullability nullability = GetNullability();
type = type.ChangeNullability(nullability);
}
return type;
}
public override IType VisitTypeParameter(ITypeParameter type)
{
Nullability nullability = GetNullability();
return newType.ChangeNullability(nullability);
return type.ChangeNullability(nullability);
}
}
}

6
ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs

@ -67,5 +67,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -67,5 +67,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
/// <remarks>This property is used to speed up the search for extension methods.</remarks>
bool HasExtensionMethods { get; }
/// <summary>
/// The nullability specified in the [NullableContext] attribute on the type.
/// This serves as default nullability for members of the type that do not have a [Nullable] attribute.
/// </summary>
Nullability NullableContext { get; }
}
}

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

@ -208,6 +208,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -208,6 +208,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return (options & TypeSystemOptions.UnmanagedConstraints) != 0 && target == SymbolKind.TypeParameter;
case "NullableAttribute":
return (options & TypeSystemOptions.NullabilityAnnotations) != 0;
case "NullableContextAttribute":
return (options & TypeSystemOptions.NullabilityAnnotations) != 0 && (target == SymbolKind.TypeDefinition || target == SymbolKind.Method);
default:
return false;
}

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

@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
Dynamic,
TupleElementNames,
Nullable,
NullableContext,
Conditional,
Obsolete,
IsReadOnly,
@ -107,6 +108,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -107,6 +108,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(DynamicAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(TupleElementNamesAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", "NullableAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", "NullableContextAttribute"),
new TopLevelTypeName("System.Diagnostics", nameof(ConditionalAttribute)),
new TopLevelTypeName("System", nameof(ObsoleteAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", "IsReadOnlyAttribute"),

6
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataEvent.cs

@ -79,8 +79,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -79,8 +79,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return returnType;
var metadata = module.metadata;
var ev = metadata.GetEventDefinition(handle);
var context = new GenericContext(DeclaringTypeDefinition?.TypeParameters);
returnType = module.ResolveType(ev.Type, context, ev.GetCustomAttributes());
var declaringTypeDef = DeclaringTypeDefinition;
var context = new GenericContext(declaringTypeDef?.TypeParameters);
var nullableContext = declaringTypeDef?.NullableContext ?? Nullability.Oblivious;
returnType = module.ResolveType(ev.Type, context, ev.GetCustomAttributes(), nullableContext);
return LazyInit.GetOrSet(ref this.returnType, returnType);
}
}

3
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs

@ -186,7 +186,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -186,7 +186,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
ty = mod.ElementType;
}
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation,
fieldDef.GetCustomAttributes(), metadata, module.TypeSystemOptions);
fieldDef.GetCustomAttributes(), metadata, module.TypeSystemOptions,
DeclaringTypeDefinition?.NullableContext ?? Nullability.Oblivious);
} catch (BadImageFormatException) {
ty = SpecialType.UnknownType;
}

20
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -149,6 +149,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -149,6 +149,13 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
internal Nullability NullableContext {
get {
var methodDef = module.metadata.GetMethodDefinition(handle);
return methodDef.GetCustomAttributes().GetNullableContext(module.metadata) ?? DeclaringTypeDefinition.NullableContext;
}
}
private void DecodeSignature()
{
var methodDef = module.metadata.GetMethodDefinition(handle);
@ -156,8 +163,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -156,8 +163,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
IType returnType;
IParameter[] parameters;
try {
var nullableContext = methodDef.GetCustomAttributes().GetNullableContext(module.metadata) ?? DeclaringTypeDefinition.NullableContext;
var signature = methodDef.DecodeSignature(module.TypeProvider, genericContext);
(returnType, parameters) = DecodeSignature(module, this, signature, methodDef.GetParameters());
(returnType, parameters) = DecodeSignature(module, this, signature, methodDef.GetParameters(), nullableContext);
} catch (BadImageFormatException) {
returnType = SpecialType.UnknownType;
parameters = Empty<IParameter>.Array;
@ -166,7 +174,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -166,7 +174,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
LazyInit.GetOrSet(ref this.parameters, parameters);
}
internal static (IType, IParameter[]) DecodeSignature(MetadataModule module, IParameterizedMember owner, MethodSignature<IType> signature, ParameterHandleCollection? parameterHandles)
internal static (IType, IParameter[]) DecodeSignature(MetadataModule module, IParameterizedMember owner, MethodSignature<IType> signature, ParameterHandleCollection? parameterHandles, Nullability nullableContext)
{
var metadata = module.metadata;
int i = 0;
@ -187,14 +195,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -187,14 +195,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
// Fill gaps in the sequence with non-metadata parameters:
while (i < par.SequenceNumber - 1) {
parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], module.Compilation, null, metadata, module.TypeSystemOptions);
signature.ParameterTypes[i], module.Compilation, null, metadata, module.TypeSystemOptions, nullableContext);
parameters[i] = new DefaultParameter(parameterType, name: string.Empty, owner,
isRef: parameterType.Kind == TypeKind.ByReference);
i++;
}
parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], module.Compilation,
par.GetCustomAttributes(), metadata, module.TypeSystemOptions);
par.GetCustomAttributes(), metadata, module.TypeSystemOptions, nullableContext);
parameters[i] = new MetadataParameter(module, owner, parameterType, parameterHandle);
i++;
}
@ -202,7 +210,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -202,7 +210,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
while (i < signature.RequiredParameterCount) {
parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], module.Compilation, null, metadata, module.TypeSystemOptions);
signature.ParameterTypes[i], module.Compilation, null, metadata, module.TypeSystemOptions, nullableContext);
parameters[i] = new DefaultParameter(parameterType, name: string.Empty, owner,
isRef: parameterType.Kind == TypeKind.ByReference);
i++;
@ -213,7 +221,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -213,7 +221,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
Debug.Assert(i == parameters.Length);
var returnType = ApplyAttributeTypeVisitor.ApplyAttributesToType(signature.ReturnType,
module.Compilation, returnTypeAttributes, metadata, module.TypeSystemOptions);
module.Compilation, returnTypeAttributes, metadata, module.TypeSystemOptions, nullableContext);
return (returnType, parameters);
}
#endregion

21
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs

@ -123,13 +123,22 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -123,13 +123,22 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
var signature = propertyDef.DecodeSignature(module.TypeProvider, genericContext);
var accessors = propertyDef.GetAccessors();
ParameterHandleCollection? parameterHandles;
if (!accessors.Getter.IsNil)
parameterHandles = module.metadata.GetMethodDefinition(accessors.Getter).GetParameters();
else if (!accessors.Setter.IsNil)
parameterHandles = module.metadata.GetMethodDefinition(accessors.Setter).GetParameters();
else
Nullability nullableContext;
if (!accessors.Getter.IsNil) {
var getter = module.metadata.GetMethodDefinition(accessors.Getter);
parameterHandles = getter.GetParameters();
nullableContext = getter.GetCustomAttributes().GetNullableContext(module.metadata)
?? DeclaringTypeDefinition?.NullableContext ?? Nullability.Oblivious;
} else if (!accessors.Setter.IsNil) {
var setter = module.metadata.GetMethodDefinition(accessors.Setter);
parameterHandles = setter.GetParameters();
nullableContext = setter.GetCustomAttributes().GetNullableContext(module.metadata)
?? DeclaringTypeDefinition?.NullableContext ?? Nullability.Oblivious;
} else {
parameterHandles = null;
(returnType, parameters) = MetadataMethod.DecodeSignature(module, this, signature, parameterHandles);
nullableContext = DeclaringTypeDefinition?.NullableContext ?? Nullability.Oblivious;
}
(returnType, parameters) = MetadataMethod.DecodeSignature(module, this, signature, parameterHandles, nullableContext);
} catch (BadImageFormatException) {
returnType = SpecialType.UnknownType;
parameters = Empty<IParameter>.Array;

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

@ -51,6 +51,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -51,6 +51,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public KnownTypeCode KnownTypeCode { get; }
public IType EnumUnderlyingType { get; }
public bool HasExtensionMethods { get; }
public Nullability NullableContext { get; }
// lazy-loaded:
IMember[] members;
@ -77,10 +78,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -77,10 +78,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
// Create type parameters:
this.TypeParameters = MetadataTypeParameter.Create(module, this.DeclaringTypeDefinition, this, td.GetGenericParameters());
this.NullableContext = td.GetCustomAttributes().GetNullableContext(metadata) ?? this.DeclaringTypeDefinition.NullableContext;
} else {
// Create type parameters:
this.TypeParameters = MetadataTypeParameter.Create(module, this, td.GetGenericParameters());
this.NullableContext = td.GetCustomAttributes().GetNullableContext(metadata) ?? module.NullableContext;
var topLevelTypeName = fullTypeName.TopLevelTypeName;
for (int i = 0; i < KnownTypeReference.KnownTypeCodeCount; i++) {
var ktr = KnownTypeReference.Get((KnownTypeCode)i);
@ -301,7 +306,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -301,7 +306,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
foreach (var h in interfaceImplCollection) {
var iface = metadata.GetInterfaceImplementation(h);
baseTypes.Add(module.ResolveType(iface.Interface, context, iface.GetCustomAttributes()));
baseTypes.Add(module.ResolveType(iface.Interface, context, iface.GetCustomAttributes(), Nullability.Oblivious));
}
return LazyInit.GetOrSet(ref this.directBaseTypes, baseTypes);
}

10
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs

@ -177,13 +177,21 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -177,13 +177,21 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
var metadata = module.metadata;
var gp = metadata.GetGenericParameter(handle);
Nullability nullableContext;
if (Owner is ITypeDefinition typeDef) {
nullableContext = typeDef.NullableContext;
} else if (Owner is MetadataMethod method) {
nullableContext = method.NullableContext;
} else {
nullableContext = Nullability.Oblivious;
}
var constraintHandleCollection = gp.GetConstraints();
List<IType> result = new List<IType>(constraintHandleCollection.Count + 1);
bool hasNonInterfaceConstraint = false;
foreach (var constraintHandle in constraintHandleCollection) {
var constraint = metadata.GetGenericParameterConstraint(constraintHandle);
var ty = module.ResolveType(constraint.Type, new GenericContext(Owner), constraint.GetCustomAttributes());
var ty = module.ResolveType(constraint.Type, new GenericContext(Owner), constraint.GetCustomAttributes(), nullableContext);
result.Add(ty);
hasNonInterfaceConstraint |= (ty.Kind != TypeKind.Interface);
}

1
ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs

@ -177,6 +177,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -177,6 +177,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
bool IType.IsByRefLike => false;
Nullability IType.Nullability => Nullability.Oblivious;
Nullability ITypeDefinition.NullableContext => Nullability.Oblivious;
IType IType.ChangeNullability(Nullability nullability)
{

13
ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs

@ -19,6 +19,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -19,6 +19,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
// the NullabilityAnnotatedType wrapper only in some limited places.
Debug.Assert(type is ITypeDefinition
|| type.Kind == TypeKind.Dynamic
|| type.Kind == TypeKind.Unknown
|| (type is ITypeParameter && this is ITypeParameter));
this.nullability = nullability;
}
@ -50,10 +51,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -50,10 +51,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override IType VisitChildren(TypeVisitor visitor)
{
IType newBase = baseType.AcceptVisitor(visitor);
if (newBase != baseType)
if (newBase != baseType) {
if (newBase.Nullability == Nullability.Nullable) {
// T?! -> T?
// This happens during type substitution for generic methods.
return newBase;
}
return newBase.ChangeNullability(nullability);
else
} else {
return this;
}
}
public override string ToString()
@ -80,6 +87,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -80,6 +87,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.baseType = type;
}
public ITypeParameter OriginalTypeParameter => baseType;
SymbolKind ITypeParameter.OwnerType => baseType.OwnerType;
IEntity ITypeParameter.Owner => baseType.Owner;
int ITypeParameter.Index => baseType.Index;

4
ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs

@ -203,7 +203,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -203,7 +203,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
b.Append('[');
for (int i = 0; i < this.TypeArguments.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(this.TypeArguments[i].ReflectionName);
b.Append(this.TypeArguments[i].ToString());
}
b.Append(']');
} else if (this.TypeParameters.Count > 0) {
@ -216,7 +216,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -216,7 +216,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
b.Append(this.Parameters[i].ToString());
}
b.Append("):");
b.Append(this.ReturnType.ReflectionName);
b.Append(this.ReturnType.ToString());
b.Append(']');
return b.ToString();
}

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

@ -46,7 +46,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -46,7 +46,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override string ReflectionName {
get { return elementType.ReflectionName + NameSuffix; }
}
public override string ToString()
{
return elementType.ToString() + NameSuffix;
}
public abstract string NameSuffix { get; }
public IType ElementType {

10
ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs

@ -94,7 +94,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -94,7 +94,15 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override bool? IsReferenceType {
get { return isReferenceType; }
}
public override IType ChangeNullability(Nullability nullability)
{
if (nullability == Nullability.Oblivious)
return this;
else
return new NullabilityAnnotatedType(this, nullability);
}
public override int GetHashCode()
{
return (namespaceKnown ? 812571 : 12651) ^ fullTypeName.GetHashCode();

14
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
internal readonly MetadataReader metadata;
readonly TypeSystemOptions options;
internal readonly TypeProvider TypeProvider;
internal readonly Nullability NullableContext;
readonly MetadataNamespace rootNamespace;
readonly MetadataTypeDefinition[] typeDefs;
@ -66,6 +67,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -66,6 +67,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
this.AssemblyName = metadata.GetString(moddef.Name);
this.FullAssemblyName = this.AssemblyName;
}
this.NullableContext = metadata.GetModuleDefinition().GetCustomAttributes().GetNullableContext(metadata) ?? Nullability.Oblivious;
this.rootNamespace = new MetadataNamespace(this, null, string.Empty, metadata.GetNamespaceDefinitionRoot());
if (!options.HasFlag(TypeSystemOptions.Uncached)) {
@ -267,12 +269,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -267,12 +269,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
#endregion
#region Resolve Type
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, CustomAttributeHandleCollection? typeAttributes = null)
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, CustomAttributeHandleCollection? typeAttributes = null, Nullability nullableContext = Nullability.Oblivious)
{
return ResolveType(typeRefDefSpec, context, options, typeAttributes);
return ResolveType(typeRefDefSpec, context, options, typeAttributes, nullableContext);
}
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, TypeSystemOptions customOptions, CustomAttributeHandleCollection? typeAttributes = null)
public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, TypeSystemOptions customOptions, CustomAttributeHandleCollection? typeAttributes = null, Nullability nullableContext = Nullability.Oblivious)
{
if (typeRefDefSpec.IsNil)
return SpecialType.UnknownType;
@ -293,7 +295,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -293,7 +295,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
default:
throw new BadImageFormatException("Not a type handle");
}
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, typeAttributes, metadata, customOptions);
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, typeAttributes, metadata, customOptions, nullableContext);
return ty;
}
@ -303,14 +305,14 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -303,14 +305,14 @@ namespace ICSharpCode.Decompiler.TypeSystem
var ty = ResolveType(declaringTypeReference, context,
options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations));
// but substitute tuple types in type arguments:
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, typeChildrenOnly: true);
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true);
return ty;
}
IType IntroduceTupleTypes(IType ty)
{
// run ApplyAttributeTypeVisitor without attributes, in order to introduce tuple types
return ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options);
return ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious);
}
#endregion

10
ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

@ -21,6 +21,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -21,6 +21,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
RemoveNullability = true,
};
internal static readonly NormalizeTypeVisitor RemoveModifiersAndNullability = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = false,
ReplaceMethodTypeParametersWithDummy = false,
DynamicAndObject = false,
TupleToUnderlyingType = false,
RemoveModOpt = true,
RemoveModReq = true,
RemoveNullability = true,
};
public bool EquivalentTypes(IType a, IType b)
{
a = a.AcceptVisitor(this);

Loading…
Cancel
Save