diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 94355e7e2e..0ce4e3426b 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -33,6 +33,7 @@ using ICSharpCode.Decompiler.Semantics; using ICSharpCode.Decompiler.Util; using System.IO; +using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; namespace ICSharpCode.Decompiler.CSharp { @@ -667,20 +668,35 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, ITypeResolveContext decom } if (typeDecl.Members.OfType().Any(idx => idx.PrivateImplementationType.IsNull)) { // Remove the [DefaultMember] attribute if the class contains indexers - foreach (AttributeSection section in typeDecl.Attributes) { - foreach (var attr in section.Attributes) { - var tr = attr.Type.GetResolveResult().Type; - if (tr.Name == "DefaultMemberAttribute" && tr.Namespace == "System.Reflection") { + RemoveAttribute(typeDecl, new TopLevelTypeName("System.Reflection", "DefaultMemberAttribute")); + } + if (settings.IntroduceRefAndReadonlyModifiersOnStructs && typeDecl.ClassType == ClassType.Struct) { + if (RemoveAttribute(typeDecl, new TopLevelTypeName("System.Runtime.CompilerServices", "IsByRefLikeAttribute"))) { + typeDecl.Modifiers |= Modifiers.Ref; + } + if (RemoveAttribute(typeDecl, new TopLevelTypeName("System.Runtime.CompilerServices", "IsReadOnlyAttribute"))) { + typeDecl.Modifiers |= Modifiers.Readonly; + } + if (FindAttribute(typeDecl, new TopLevelTypeName("System", "ObsoleteAttribute"), out var attr)) { + if (obsoleteAttributePattern.IsMatch(attr)) { + if (attr.Parent is Syntax.AttributeSection section && section.Attributes.Count == 1) + section.Remove(); + else attr.Remove(); - } } - if (section.Attributes.Count == 0) - section.Remove(); } } return typeDecl; } + static readonly Syntax.Attribute obsoleteAttributePattern = new Syntax.Attribute() { + Type = new TypePattern(typeof(ObsoleteAttribute)), + Arguments = { + new PrimitiveExpression("Types with embedded references are not supported in this version of your compiler."), + new Choice() { new PrimitiveExpression(true), new PrimitiveExpression(false) } + } + }; + MethodDeclaration GenerateConvHelper(string name, KnownTypeCode source, KnownTypeCode target, TypeSystemAstBuilder typeSystemAstBuilder, Expression intermediate32, Expression intermediate64) { @@ -806,19 +822,37 @@ void DecompileBody(MethodDefinition methodDefinition, IMethod method, EntityDecl } } - void RemoveAttribute(EntityDeclaration entityDecl, FullTypeName attrName) + bool RemoveAttribute(EntityDeclaration entityDecl, FullTypeName attrName) { + bool found = false; foreach (var section in entityDecl.Attributes) { foreach (var attr in section.Attributes) { var symbol = attr.Type.GetSymbol(); if (symbol is ITypeDefinition td && td.FullTypeName == attrName) { attr.Remove(); + found = true; } } if (section.Attributes.Count == 0) { section.Remove(); } } + return found; + } + + bool FindAttribute(EntityDeclaration entityDecl, FullTypeName attrName, out Syntax.Attribute attribute) + { + attribute = null; + foreach (var section in entityDecl.Attributes) { + foreach (var attr in section.Attributes) { + var symbol = attr.Type.GetSymbol(); + if (symbol is ITypeDefinition td && td.FullTypeName == attrName) { + attribute = attr; + return true; + } + } + } + return false; } HashSet definedSymbols; diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index da8622abbd..b5678c46d0 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -75,6 +75,9 @@ public DecompilerSettings(CSharp.LanguageVersion languageVersion) if (languageVersion < CSharp.LanguageVersion.CSharp7) { outVariables = false; } + if (languageVersion < CSharp.LanguageVersion.CSharp7_2) { + introduceRefAndReadonlyModifiersOnStructs = false; + } } bool anonymousMethods = true; @@ -520,7 +523,7 @@ public bool UseExpressionBodyForCalculatedGetterOnlyProperties { bool outVariables = true; /// - /// Gets/Sets whether simple calculated getter-only property declarations should use expression body syntax. + /// Gets/Sets whether out variable declarations should be used when possible. /// public bool OutVariables { get { return outVariables; } @@ -532,6 +535,21 @@ public bool OutVariables { } } + bool introduceRefAndReadonlyModifiersOnStructs = true; + + /// + /// Gets/Sets whether IsByRefLikeAttribute and IsReadOnlyAttribute should be replaced with 'ref' and 'readonly' modifiers on structs. + /// + public bool IntroduceRefAndReadonlyModifiersOnStructs { + get { return introduceRefAndReadonlyModifiersOnStructs; } + set { + if (introduceRefAndReadonlyModifiersOnStructs != value) { + introduceRefAndReadonlyModifiersOnStructs = value; + OnPropertyChanged(); + } + } + } + #region Options to aid VB decompilation bool introduceIncrementAndDecrement = true;