Browse Source

Fix #3094: look for `[NullableAttribute]` both on the property getter and property itself

pull/3111/head
Daniel Grunwald 2 years ago
parent
commit
a14cc0234e
  1. 111
      ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
  2. 16
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  3. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs

111
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

@ -40,7 +40,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
SRM.MetadataReader metadata, SRM.MetadataReader metadata,
TypeSystemOptions options, TypeSystemOptions options,
Nullability nullableContext, Nullability nullableContext,
bool typeChildrenOnly = false) bool typeChildrenOnly = false,
SRM.CustomAttributeHandleCollection? additionalAttributes = null)
{ {
bool hasDynamicAttribute = false; bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null; bool[] dynamicAttributeData = null;
@ -57,73 +58,87 @@ namespace ICSharpCode.Decompiler.TypeSystem
{ {
nullability = Nullability.Oblivious; nullability = Nullability.Oblivious;
} }
const TypeSystemOptions relevantOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers;
if (attributes != null && (options & relevantOptions) != 0) void ProcessAttribute(SRM.CustomAttributeHandle attrHandle)
{ {
foreach (var attrHandle in attributes.Value) var attr = metadata.GetCustomAttribute(attrHandle);
var attrType = attr.GetAttributeType(metadata);
if ((options & TypeSystemOptions.Dynamic) != 0 && attrType.IsKnownType(metadata, KnownAttribute.Dynamic))
{ {
var attr = metadata.GetCustomAttribute(attrHandle); hasDynamicAttribute = true;
var attrType = attr.GetAttributeType(metadata); var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if ((options & TypeSystemOptions.Dynamic) != 0 && attrType.IsKnownType(metadata, KnownAttribute.Dynamic)) if (ctor.FixedArguments.Length == 1)
{ {
hasDynamicAttribute = true; var arg = ctor.FixedArguments[0];
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider); if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
if (ctor.FixedArguments.Length == 1) && values.All(v => v.Value is bool))
{ {
var arg = ctor.FixedArguments[0]; dynamicAttributeData = values.SelectArray(v => (bool)v.Value);
if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& values.All(v => v.Value is bool))
{
dynamicAttributeData = values.SelectArray(v => (bool)v.Value);
}
} }
} }
else if ((options & TypeSystemOptions.NativeIntegers) != 0 && attrType.IsKnownType(metadata, KnownAttribute.NativeInteger)) }
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)
{ {
hasNativeIntegersAttribute = true; var arg = ctor.FixedArguments[0];
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider); if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
if (ctor.FixedArguments.Length == 1) && values.All(v => v.Value is bool))
{ {
var arg = ctor.FixedArguments[0]; nativeIntegersAttributeData = values.SelectArray(v => (bool)v.Value);
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);
if (ctor.FixedArguments.Length == 1)
{ {
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider); var arg = ctor.FixedArguments[0];
if (ctor.FixedArguments.Length == 1) if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& values.All(v => v.Value is string || v.Value == null))
{ {
var arg = ctor.FixedArguments[0]; tupleElementNames = values.SelectArray(v => (string)v.Value);
if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& values.All(v => v.Value is string || v.Value == null))
{
tupleElementNames = values.SelectArray(v => (string)v.Value);
}
} }
} }
else if ((options & TypeSystemOptions.NullabilityAnnotations) != 0 && attrType.IsKnownType(metadata, KnownAttribute.Nullable)) }
else if ((options & TypeSystemOptions.NullabilityAnnotations) != 0 && attrType.IsKnownType(metadata, KnownAttribute.Nullable))
{
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if (ctor.FixedArguments.Length == 1)
{ {
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider); var arg = ctor.FixedArguments[0];
if (ctor.FixedArguments.Length == 1) if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& values.All(v => v.Value is byte b && b <= 2))
{ {
var arg = ctor.FixedArguments[0]; nullableAttributeData = values.SelectArray(v => (Nullability)(byte)v.Value);
if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values }
&& values.All(v => v.Value is byte b && b <= 2)) else if (arg.Value is byte b && b <= 2)
{ {
nullableAttributeData = values.SelectArray(v => (Nullability)(byte)v.Value); nullability = (Nullability)b;
}
else if (arg.Value is byte b && b <= 2)
{
nullability = (Nullability)b;
}
} }
} }
} }
} }
const TypeSystemOptions relevantOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers;
if (attributes != null && (options & relevantOptions) != 0)
{
foreach (var attrHandle in attributes.Value)
{
ProcessAttribute(attrHandle);
}
}
if (additionalAttributes != null && (options & relevantOptions) != 0)
{
// Note: additional attributes will override the values from the normal attributes.
foreach (var attrHandle in additionalAttributes.Value)
{
ProcessAttribute(attrHandle);
}
}
if (hasDynamicAttribute || hasNativeIntegersAttribute || 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)
{ {

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

@ -209,13 +209,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
MetadataModule module, IParameterizedMember owner, MetadataModule module, IParameterizedMember owner,
MethodSignature<IType> signature, ParameterHandleCollection? parameterHandles, MethodSignature<IType> signature, ParameterHandleCollection? parameterHandles,
Nullability nullableContext, TypeSystemOptions typeSystemOptions, Nullability nullableContext, TypeSystemOptions typeSystemOptions,
CustomAttributeHandleCollection? returnTypeAttributes = null) CustomAttributeHandleCollection? additionalReturnTypeAttributes = null)
{ {
var metadata = module.metadata; var metadata = module.metadata;
int i = 0; int i = 0;
IParameter[] parameters = new IParameter[signature.RequiredParameterCount IParameter[] parameters = new IParameter[signature.RequiredParameterCount
+ (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs ? 1 : 0)]; + (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs ? 1 : 0)];
IType parameterType; IType parameterType;
CustomAttributeHandleCollection? returnTypeAttributes = null;
if (parameterHandles != null) if (parameterHandles != null)
{ {
foreach (var parameterHandle in parameterHandles) foreach (var parameterHandle in parameterHandles)
@ -225,13 +226,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{ {
// "parameter" holds return type attributes. // "parameter" holds return type attributes.
// Note: for properties, the attributes normally stored on a method's return type // Note: for properties, the attributes normally stored on a method's return type
// are instead stored as normal attributes on the property. // are instead typically stored as normal attributes on the property.
// So MetadataProperty provides a non-null value for returnTypeAttributes, // So MetadataProperty provides a non-null value for additionalReturnTypeAttributes,
// which then should be preferred over the attributes on the accessor's parameters. // which then will be preferred over the attributes on the accessor's parameters.
if (returnTypeAttributes == null) // However if an attribute only exists on the accessor's parameters, we still want
{ // to process it here.
returnTypeAttributes = par.GetCustomAttributes(); returnTypeAttributes = par.GetCustomAttributes();
}
} }
else if (i < par.SequenceNumber && par.SequenceNumber <= signature.RequiredParameterCount) else if (i < par.SequenceNumber && par.SequenceNumber <= signature.RequiredParameterCount)
{ {

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

@ -169,7 +169,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
(returnType, parameters, _) = MetadataMethod.DecodeSignature( (returnType, parameters, _) = MetadataMethod.DecodeSignature(
module, this, signature, module, this, signature,
parameterHandles, nullableContext, typeOptions, parameterHandles, nullableContext, typeOptions,
returnTypeAttributes: propertyDef.GetCustomAttributes()); additionalReturnTypeAttributes: propertyDef.GetCustomAttributes());
} }
catch (BadImageFormatException) catch (BadImageFormatException)
{ {

Loading…
Cancel
Save