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 @@ -40,7 +40,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
SRM.MetadataReader metadata,
TypeSystemOptions options,
Nullability nullableContext,
bool typeChildrenOnly = false)
bool typeChildrenOnly = false,
SRM.CustomAttributeHandleCollection? additionalAttributes = null)
{
bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null;
@ -57,73 +58,87 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -57,73 +58,87 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
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);
var attrType = attr.GetAttributeType(metadata);
if ((options & TypeSystemOptions.Dynamic) != 0 && attrType.IsKnownType(metadata, KnownAttribute.Dynamic))
hasDynamicAttribute = true;
var ctor = attr.DecodeValue(Metadata.MetadataExtensions.minimalCorlibTypeProvider);
if (ctor.FixedArguments.Length == 1)
{
hasDynamicAttribute = 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))
{
var arg = ctor.FixedArguments[0];
if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& values.All(v => v.Value is bool))
{
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))
}
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 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))
{
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);
}
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);
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 string || v.Value == null))
{
var arg = ctor.FixedArguments[0];
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);
}
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);
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 byte b && b <= 2))
{
var arg = ctor.FixedArguments[0];
if (arg.Value is ImmutableArray<SRM.CustomAttributeTypedArgument<IType>> values
&& 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)b;
}
nullableAttributeData = values.SelectArray(v => (Nullability)(byte)v.Value);
}
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
|| (options & (TypeSystemOptions.Tuple | TypeSystemOptions.KeepModifiers)) != TypeSystemOptions.KeepModifiers)
{

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

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

Loading…
Cancel
Save