diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index f0eca9c7f..b6de25849 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -1491,7 +1491,7 @@ namespace ICSharpCode.Decompiler.CSharp EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, PEFile module) { - if (typeDef.HasAttribute(KnownAttribute.Flags, inherit: false)) + if (typeDef.HasAttribute(KnownAttribute.Flags)) return EnumValueDisplayMode.AllHex; bool first = true; long firstValue = 0, previousValue = 0; @@ -1917,7 +1917,7 @@ namespace ICSharpCode.Decompiler.CSharp { type = null; elementCount = 0; - IAttribute attr = field.GetAttribute(KnownAttribute.FixedBuffer, inherit: false); + IAttribute attr = field.GetAttribute(KnownAttribute.FixedBuffer); if (attr != null && attr.FixedArguments.Length == 2) { if (attr.FixedArguments[0].Value is IType trr && attr.FixedArguments[1].Value is int length) diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs index 868f7fe59..b3f453157 100644 --- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs +++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs @@ -156,10 +156,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver get { return SymbolKind.Operator; } } - IEnumerable IEntity.GetAttributes() - { - return EmptyList.Instance; - } + IEnumerable IEntity.GetAttributes() => EmptyList.Instance; + bool IEntity.HasAttribute(KnownAttribute attribute) => false; + IAttribute? IEntity.GetAttribute(KnownAttribute attribute) => null; Accessibility IEntity.Accessibility { get { return Accessibility.Public; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index dc2dd2aee..995164b3f 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -1154,7 +1154,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return true; } - Dictionary specialConstants = new Dictionary() { + static readonly Dictionary specialConstants = new Dictionary() { // byte: { byte.MaxValue, (KnownTypeCode.Byte, "MaxValue") }, // sbyte: @@ -1196,7 +1196,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax bool IsFlagsEnum(ITypeDefinition type) { - return type.HasAttribute(KnownAttribute.Flags, inherit: false); + return type.HasAttribute(KnownAttribute.Flags); } Expression ConvertEnumValue(IType type, long val) diff --git a/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs b/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs index 3ef59ecac..7b638419c 100644 --- a/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs +++ b/ICSharpCode.Decompiler/TypeSystem/ComHelper.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.TypeSystem { return typeDefinition != null && typeDefinition.Kind == TypeKind.Interface - && typeDefinition.HasAttribute(KnownAttribute.ComImport, inherit: false); + && typeDefinition.HasAttribute(KnownAttribute.ComImport); } /// @@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.TypeSystem { if (typeDefinition == null) return SpecialType.UnknownType; - var coClassAttribute = typeDefinition.GetAttribute(KnownAttribute.CoClass, inherit: false); + var coClassAttribute = typeDefinition.GetAttribute(KnownAttribute.CoClass); if (coClassAttribute != null && coClassAttribute.FixedArguments.Length == 1) { if (coClassAttribute.FixedArguments[0].Value is IType ty) diff --git a/ICSharpCode.Decompiler/TypeSystem/IEntity.cs b/ICSharpCode.Decompiler/TypeSystem/IEntity.cs index c6c9c9f3a..7ad7f9c0c 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IEntity.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IEntity.cs @@ -68,6 +68,10 @@ namespace ICSharpCode.Decompiler.TypeSystem /// IEnumerable GetAttributes(); + bool HasAttribute(KnownAttribute attribute); + + IAttribute? GetAttribute(KnownAttribute attribute); + /// /// Gets the accessibility of this entity. /// diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs index e5b62ad9b..d6b786201 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs @@ -190,7 +190,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation foreach (var handle in attributes) { var attribute = metadata.GetCustomAttribute(handle); - // Attribute types shouldn't be generic (and certainly not open), so we don't need a generic context. + // Attribute types shouldn't be open generic, so we don't need a generic context. var ctor = module.ResolveMethod(attribute.Constructor, new GenericContext()); var type = ctor.DeclaringType; if (IgnoreAttribute(type, target)) @@ -205,6 +205,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation { if (attributeType.DeclaringType != null || attributeType.TypeParameterCount != 0) return false; + return IgnoreAttribute(new TopLevelTypeName(attributeType.Namespace, attributeType.Name), target); + } + + internal bool IgnoreAttribute(TopLevelTypeName attributeType, SymbolKind target) + { switch (attributeType.Namespace) { case "System.Runtime.CompilerServices": @@ -259,6 +264,39 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } } + internal bool HasAttribute(MetadataReader metadata, CustomAttributeHandleCollection customAttributes, KnownAttribute attribute, SymbolKind symbolKind) + { + Debug.Assert(attribute.IsCustomAttribute()); + foreach (var h in customAttributes) + { + var attr = metadata.GetCustomAttribute(h); + if (attr.IsKnownAttribute(metadata, attribute)) + { + return !IgnoreAttribute(attribute.GetTypeName(), symbolKind); + } + } + + return false; + } + + internal IAttribute GetAttribute(MetadataReader metadata, CustomAttributeHandleCollection customAttributes, KnownAttribute attribute, SymbolKind symbolKind) + { + Debug.Assert(attribute.IsCustomAttribute()); + foreach (var h in customAttributes) + { + var attr = metadata.GetCustomAttribute(h); + if (attr.IsKnownAttribute(metadata, attribute) + && !IgnoreAttribute(attribute.GetTypeName(), symbolKind)) + { + // Attribute types shouldn't be open generic, so we don't need a generic context. + var ctor = module.ResolveMethod(attr.Constructor, new GenericContext()); + return new CustomAttribute(module, ctor, h); + } + } + + return null; + } + static bool IsMethodLike(SymbolKind kind) { return kind switch { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs index e77aeaeb9..43549b6c6 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/FakeMember.cs @@ -61,6 +61,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation IModule IEntity.ParentModule => DeclaringType?.GetDefinition()?.ParentModule; IEnumerable IEntity.GetAttributes() => EmptyList.Instance; + bool IEntity.HasAttribute(KnownAttribute attribute) => false; + IAttribute IEntity.GetAttribute(KnownAttribute attribute) => null; public Accessibility Accessibility { get; set; } = Accessibility.Public; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs index 21f805500..6f6dcacaf 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs @@ -107,7 +107,7 @@ namespace ICSharpCode.Decompiler.TypeSystem PreserveBaseOverrides, } - static class KnownAttributes + public static class KnownAttributes { internal const int Count = (int)KnownAttribute.PreserveBaseOverrides + 1; @@ -197,5 +197,30 @@ namespace ICSharpCode.Decompiler.TypeSystem } return KnownAttribute.None; } + + public static bool IsCustomAttribute(this KnownAttribute knownAttribute) + { + switch (knownAttribute) + { + case KnownAttribute.Serializable: + case KnownAttribute.ComImport: + case KnownAttribute.StructLayout: + case KnownAttribute.DllImport: + case KnownAttribute.PreserveSig: + case KnownAttribute.MethodImpl: + case KnownAttribute.FieldOffset: + case KnownAttribute.NonSerialized: + case KnownAttribute.MarshalAs: + case KnownAttribute.PermissionSet: + case KnownAttribute.Optional: + case KnownAttribute.In: + case KnownAttribute.Out: + case KnownAttribute.IndexerName: + case KnownAttribute.SpecialName: + return false; + default: + return true; + } + } } } diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs index 240ccaed8..30d7aa60b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/LocalFunctionMethod.cs @@ -145,6 +145,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public IType DeclaringType => baseMethod.DeclaringType; public IModule ParentModule => baseMethod.ParentModule; IEnumerable IEntity.GetAttributes() => baseMethod.GetAttributes(); + bool IEntity.HasAttribute(KnownAttribute attribute) => baseMethod.HasAttribute(attribute); + IAttribute IEntity.GetAttribute(KnownAttribute attribute) => baseMethod.GetAttribute(attribute); IEnumerable IMethod.GetReturnTypeAttributes() => baseMethod.GetReturnTypeAttributes(); bool IMethod.ReturnTypeIsRefReadOnly => baseMethod.ReturnTypeIsRefReadOnly; bool IMethod.ThisIsRefReadOnly => baseMethod.ThisIsRefReadOnly; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataEvent.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataEvent.cs index bd4815687..ee86a531d 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataEvent.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataEvent.cs @@ -123,6 +123,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation b.Add(eventDef.GetCustomAttributes(), SymbolKind.Event); return b.Build(); } + + public bool HasAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().Any(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetEventDefinition(handle); + return b.HasAttribute(metadata, def.GetCustomAttributes(), attribute, SymbolKind.Event); + } + + public IAttribute GetAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().FirstOrDefault(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetEventDefinition(handle); + return b.GetAttribute(metadata, def.GetCustomAttributes(), attribute, SymbolKind.Event); + } #endregion public Accessibility Accessibility => AnyAccessor?.Accessibility ?? Accessibility.None; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs index 1095f0469..f6a23d073 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataField.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -164,6 +165,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation return b.Build(); } + public bool HasAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().Any(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetFieldDefinition(handle); + return b.HasAttribute(metadata, def.GetCustomAttributes(), attribute, SymbolKind.Field); + } + + public IAttribute GetAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().FirstOrDefault(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetFieldDefinition(handle); + return b.GetAttribute(metadata, def.GetCustomAttributes(), attribute, SymbolKind.Field); + } + public string FullName => $"{DeclaringType?.FullName}.{Name}"; public string ReflectionName => $"{DeclaringType?.ReflectionName}.{Name}"; public string Namespace => DeclaringType?.Namespace ?? string.Empty; diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs index 282740f92..abc4252ea 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs @@ -463,6 +463,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation return b.Build(); } + + public bool HasAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().Any(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetMethodDefinition(handle); + return b.HasAttribute(metadata, def.GetCustomAttributes(), attribute, symbolKind); + } + + public IAttribute GetAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().FirstOrDefault(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetMethodDefinition(handle); + return b.GetAttribute(metadata, def.GetCustomAttributes(), attribute, symbolKind); + } #endregion #region Return type attributes diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs index d76019722..9269bead9 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataProperty.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation const Accessibility InvalidAccessibility = (Accessibility)0xff; readonly MetadataModule module; - readonly PropertyDefinitionHandle propertyHandle; + readonly PropertyDefinitionHandle handle; readonly IMethod getter; readonly IMethod setter; readonly string name; @@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation Debug.Assert(module != null); Debug.Assert(!handle.IsNil); this.module = module; - this.propertyHandle = handle; + this.handle = handle; var metadata = module.metadata; var prop = metadata.GetPropertyDefinition(handle); @@ -83,10 +83,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public override string ToString() { - return $"{MetadataTokens.GetToken(propertyHandle):X8} {DeclaringType?.ReflectionName}.{Name}"; + return $"{MetadataTokens.GetToken(handle):X8} {DeclaringType?.ReflectionName}.{Name}"; } - public EntityHandle MetadataToken => propertyHandle; + public EntityHandle MetadataToken => handle; public string Name => name; public bool CanGet => getter != null; @@ -122,14 +122,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation public bool ReturnTypeIsRefReadOnly { get { - var propertyDef = module.metadata.GetPropertyDefinition(propertyHandle); + var propertyDef = module.metadata.GetPropertyDefinition(handle); return propertyDef.GetCustomAttributes().HasKnownAttribute(module.metadata, KnownAttribute.IsReadOnly); } } private void DecodeSignature() { - var propertyDef = module.metadata.GetPropertyDefinition(propertyHandle); + var propertyDef = module.metadata.GetPropertyDefinition(handle); var genericContext = new GenericContext(DeclaringType.TypeParameters); IType returnType; IParameter[] parameters; @@ -201,7 +201,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation { var b = new AttributeListBuilder(module); var metadata = module.metadata; - var propertyDef = metadata.GetPropertyDefinition(propertyHandle); + var propertyDef = metadata.GetPropertyDefinition(handle); if (IsIndexer && Name != "Item" && !IsExplicitInterfaceImplementation) { b.Add(KnownAttribute.IndexerName, KnownTypeCode.String, Name); @@ -216,6 +216,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation b.Add(propertyDef.GetCustomAttributes(), symbolKind); return b.Build(); } + + public bool HasAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().Any(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetPropertyDefinition(handle); + return b.HasAttribute(metadata, def.GetCustomAttributes(), attribute, symbolKind); + } + + public IAttribute GetAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().FirstOrDefault(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetPropertyDefinition(handle); + return b.GetAttribute(metadata, def.GetCustomAttributes(), attribute, symbolKind); + } #endregion #region Accessibility @@ -278,14 +302,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation { if (obj is MetadataProperty p) { - return propertyHandle == p.propertyHandle && module.PEFile == p.module.PEFile; + return handle == p.handle && module.PEFile == p.module.PEFile; } return false; } public override int GetHashCode() { - return 0x32b6a76c ^ module.PEFile.GetHashCode() ^ propertyHandle.GetHashCode(); + return 0x32b6a76c ^ module.PEFile.GetHashCode() ^ handle.GetHashCode(); } bool IMember.Equals(IMember obj, TypeVisitor typeNormalization) diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs index 0a826bafa..1f58efc4c 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs @@ -432,6 +432,30 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation return b.Build(); } + public bool HasAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().Any(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetTypeDefinition(handle); + return b.HasAttribute(metadata, def.GetCustomAttributes(), attribute, SymbolKind.TypeDefinition); + } + + public IAttribute GetAttribute(KnownAttribute attribute) + { + if (!attribute.IsCustomAttribute()) + { + return GetAttributes().FirstOrDefault(attr => attr.AttributeType.IsKnownType(attribute)); + } + var b = new AttributeListBuilder(module); + var metadata = module.metadata; + var def = metadata.GetTypeDefinition(handle); + return b.GetAttribute(metadata, def.GetCustomAttributes(), attribute, SymbolKind.TypeDefinition); + } + public string DefaultMemberName { get { string defaultMemberName = LazyInit.VolatileRead(ref this.defaultMemberName); diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs index e70e3abbc..348d05169 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs @@ -258,10 +258,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation return EmptyList.Instance; } - IEnumerable IEntity.GetAttributes() - { - return EmptyList.Instance; - } + IEnumerable IEntity.GetAttributes() => EmptyList.Instance; + bool IEntity.HasAttribute(KnownAttribute attribute) => false; + IAttribute IEntity.GetAttribute(KnownAttribute attribute) => null; IEnumerable IType.GetConstructors(Predicate filter, GetMemberOptions options) { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs index 50a2405d8..42954b151 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMember.cs @@ -162,6 +162,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } IEnumerable IEntity.GetAttributes() => baseMember.GetAttributes(); + bool IEntity.HasAttribute(KnownAttribute attribute) => baseMember.HasAttribute(attribute); + IAttribute IEntity.GetAttribute(KnownAttribute attribute) => baseMember.GetAttribute(attribute); + public IEnumerable ExplicitlyImplementedInterfaceMembers { get { diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/SyntheticRangeIndexer.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/SyntheticRangeIndexer.cs index 85d6018e9..2bc60031e 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/SyntheticRangeIndexer.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/SyntheticRangeIndexer.cs @@ -126,6 +126,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation } IEnumerable IEntity.GetAttributes() => underlyingMethod.GetAttributes(); + bool IEntity.HasAttribute(KnownAttribute attribute) => underlyingMethod.HasAttribute(attribute); + IAttribute IEntity.GetAttribute(KnownAttribute attribute) => underlyingMethod.GetAttribute(attribute); IEnumerable IMethod.GetReturnTypeAttributes() => underlyingMethod.GetReturnTypeAttributes(); diff --git a/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs b/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs index 365d2f900..f9b976fe1 100644 --- a/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs +++ b/ICSharpCode.Decompiler/TypeSystem/InheritanceHelper.cs @@ -185,6 +185,20 @@ namespace ICSharpCode.Decompiler.TypeSystem } } + internal static IAttribute GetAttribute(ITypeDefinition typeDef, KnownAttribute attributeType) + { + foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse()) + { + ITypeDefinition baseTypeDef = baseType.GetDefinition(); + if (baseTypeDef == null) + continue; + var attr = baseTypeDef.GetAttribute(attributeType); + if (attr != null) + return attr; + } + return null; + } + internal static IEnumerable GetAttributes(IMember member) { HashSet visitedMembers = new HashSet(); @@ -202,6 +216,24 @@ namespace ICSharpCode.Decompiler.TypeSystem } } while (member.IsOverride && (member = InheritanceHelper.GetBaseMember(member)) != null); } + + internal static IAttribute GetAttribute(IMember member, KnownAttribute attributeType) + { + HashSet visitedMembers = new HashSet(); + do + { + member = member.MemberDefinition; // it's sufficient to look at the definitions + if (!visitedMembers.Add(member)) + { + // abort if we seem to be in an infinite loop (cyclic inheritance) + break; + } + var attr = member.GetAttribute(attributeType); + if (attr != null) + return attr; + } while (member.IsOverride && (member = InheritanceHelper.GetBaseMember(member)) != null); + return null; + } #endregion } } diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs index 122f794e6..7115696d1 100644 --- a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs +++ b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs @@ -485,7 +485,7 @@ namespace ICSharpCode.Decompiler.TypeSystem #region IEntity.GetAttribute /// - /// Gets whether the entity has an attribute of the specified attribute type (or derived attribute types). + /// Gets whether the entity has an attribute of the specified attribute type. /// /// The entity on which the attributes are declared. /// The attribute type to look for. @@ -494,13 +494,16 @@ namespace ICSharpCode.Decompiler.TypeSystem /// (if the given in an override) /// should be returned. /// - public static bool HasAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit = false) + public static bool HasAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit) { + if (!inherit) + return entity.HasAttribute(attributeType); + return GetAttribute(entity, attributeType, inherit) != null; } /// - /// Gets the attribute of the specified attribute type (or derived attribute types). + /// Gets the attribute of the specified attribute type. /// /// The entity on which the attributes are declared. /// The attribute type to look for. @@ -514,9 +517,27 @@ namespace ICSharpCode.Decompiler.TypeSystem /// If inherit is true, an from the entity itself will be returned if possible; /// and the base entity will only be searched if none exists. /// - public static IAttribute GetAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit = false) + public static IAttribute GetAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit) { - return GetAttributes(entity, inherit).FirstOrDefault(a => a.AttributeType.IsKnownType(attributeType)); + if (inherit) + { + if (entity is ITypeDefinition td) + { + return InheritanceHelper.GetAttribute(td, attributeType); + } + else if (entity is IMember m) + { + return InheritanceHelper.GetAttribute(m, attributeType); + } + else + { + throw new NotSupportedException("Unknown entity type"); + } + } + else + { + return entity.GetAttribute(attributeType); + } } /// @@ -559,7 +580,7 @@ namespace ICSharpCode.Decompiler.TypeSystem #region IParameter.GetAttribute /// - /// Gets whether the parameter has an attribute of the specified attribute type (or derived attribute types). + /// Gets whether the parameter has an attribute of the specified attribute type. /// /// The parameter on which the attributes are declared. /// The attribute type to look for. @@ -569,7 +590,7 @@ namespace ICSharpCode.Decompiler.TypeSystem } /// - /// Gets the attribute of the specified attribute type (or derived attribute types). + /// Gets the attribute of the specified attribute type. /// /// The parameter on which the attributes are declared. /// The attribute type to look for. diff --git a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs index eee269c66..07175fc03 100644 --- a/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs +++ b/ICSharpCode.Decompiler/TypeSystem/VarArgInstanceMethod.cs @@ -118,6 +118,9 @@ namespace ICSharpCode.Decompiler.TypeSystem } IEnumerable IEntity.GetAttributes() => baseMethod.GetAttributes(); + bool IEntity.HasAttribute(KnownAttribute attribute) => baseMethod.HasAttribute(attribute); + IAttribute IEntity.GetAttribute(KnownAttribute attribute) => baseMethod.GetAttribute(attribute); + IEnumerable IMethod.GetReturnTypeAttributes() => baseMethod.GetReturnTypeAttributes(); bool IMethod.ReturnTypeIsRefReadOnly => baseMethod.ReturnTypeIsRefReadOnly; bool IMethod.ThisIsRefReadOnly => baseMethod.ThisIsRefReadOnly; diff --git a/ILSpy/Analyzers/Builtin/AttributeAppliedToAnalyzer.cs b/ILSpy/Analyzers/Builtin/AttributeAppliedToAnalyzer.cs index c5318cc72..6007253a6 100644 --- a/ILSpy/Analyzers/Builtin/AttributeAppliedToAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/AttributeAppliedToAnalyzer.cs @@ -51,26 +51,7 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin bool IsBuiltinAttribute(ITypeDefinition attributeType, out KnownAttribute knownAttribute) { knownAttribute = attributeType.IsBuiltinAttribute(); - switch (knownAttribute) - { - case KnownAttribute.Serializable: - case KnownAttribute.ComImport: - case KnownAttribute.StructLayout: - case KnownAttribute.DllImport: - case KnownAttribute.PreserveSig: - case KnownAttribute.MethodImpl: - case KnownAttribute.FieldOffset: - case KnownAttribute.NonSerialized: - case KnownAttribute.MarshalAs: - case KnownAttribute.PermissionSet: - case KnownAttribute.Optional: - case KnownAttribute.In: - case KnownAttribute.Out: - case KnownAttribute.IndexerName: - return true; - default: - return false; - } + return !knownAttribute.IsCustomAttribute(); } IEnumerable> HandleBuiltinAttribute(KnownAttribute attribute, AnalyzerScope scope, CancellationToken ct)