Browse Source

Refactor TS representation of ref / readonly structs. Add support for in parameters.

pull/1243/head
Siegfried Pammer 7 years ago
parent
commit
7ef7f1870e
  1. 10
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 3
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  3. 6
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs
  4. 8
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  5. 33
      ICSharpCode.Decompiler/DecompilerSettings.cs
  6. 16
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  7. 7
      ICSharpCode.Decompiler/TypeSystem/IParameter.cs
  8. 6
      ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs
  9. 4
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  10. 9
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs
  11. 23
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs
  12. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs
  13. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/MinimalCorlib.cs
  14. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs

10
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -911,16 +911,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -911,16 +911,10 @@ namespace ICSharpCode.Decompiler.CSharp
// Remove the [DefaultMember] attribute if the class contains indexers
RemoveAttribute(typeDecl, KnownAttribute.DefaultMember);
}
if (settings.IntroduceRefAndReadonlyModifiersOnStructs && typeDecl.ClassType == ClassType.Struct) {
if (RemoveAttribute(typeDecl, KnownAttribute.IsByRefLike)) {
typeDecl.Modifiers |= Modifiers.Ref;
}
if (RemoveAttribute(typeDecl, KnownAttribute.IsReadOnly)) {
typeDecl.Modifiers |= Modifiers.Readonly;
}
if (settings.IntroduceRefModifiersOnStructs) {
if (FindAttribute(typeDecl, KnownAttribute.Obsolete, out var attr)) {
if (obsoleteAttributePattern.IsMatch(attr)) {
if (attr.Parent is Syntax.AttributeSection section && section.Attributes.Count == 1)
if (attr.Parent is AttributeSection section && section.Attributes.Count == 1)
section.Remove();
else
attr.Remove();

3
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -2170,6 +2170,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2170,6 +2170,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
case ParameterModifier.This:
WriteKeyword(ParameterDeclaration.ThisModifierRole);
break;
case ParameterModifier.In:
WriteKeyword(ParameterDeclaration.InModifierRole);
break;
}
parameterDeclaration.Type.AcceptVisitor(this);
if (!parameterDeclaration.Type.IsNull && !string.IsNullOrEmpty(parameterDeclaration.Name)) {

6
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs

@ -32,7 +32,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -32,7 +32,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Ref,
Out,
Params,
This
This,
In
}
public class ParameterDeclaration : AstNode
@ -42,7 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -42,7 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole OutModifierRole = new TokenRole("out");
public static readonly TokenRole ParamsModifierRole = new TokenRole("params");
public static readonly TokenRole ThisModifierRole = new TokenRole("this");
public static readonly TokenRole InModifierRole = new TokenRole("in");
public override NodeType NodeType {
get {
return NodeType.Unknown;

8
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -918,6 +918,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -918,6 +918,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
decl.ParameterModifier = ParameterModifier.Ref;
} else if (parameter.IsOut) {
decl.ParameterModifier = ParameterModifier.Out;
} else if (parameter.IsIn) {
decl.ParameterModifier = ParameterModifier.In;
} else if (parameter.IsParams) {
decl.ParameterModifier = ParameterModifier.Params;
}
@ -1014,6 +1016,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1014,6 +1016,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
case TypeKind.Struct:
classType = ClassType.Struct;
modifiers &= ~Modifiers.Sealed;
if (typeDefinition.IsReadOnly) {
modifiers |= Modifiers.Readonly;
}
if (typeDefinition.IsByRefLike) {
modifiers |= Modifiers.Ref;
}
break;
case TypeKind.Enum:
classType = ClassType.Enum;

33
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -83,7 +83,8 @@ namespace ICSharpCode.Decompiler @@ -83,7 +83,8 @@ namespace ICSharpCode.Decompiler
discards = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_2) {
introduceRefAndReadonlyModifiersOnStructs = false;
introduceReadonlyAndInModifiers = false;
introduceRefModifiersOnStructs = false;
nonTrailingNamedArguments = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_3) {
@ -96,7 +97,7 @@ namespace ICSharpCode.Decompiler @@ -96,7 +97,7 @@ namespace ICSharpCode.Decompiler
{
if (tupleComparisons)
return CSharp.LanguageVersion.CSharp7_3;
if (IntroduceRefAndReadonlyModifiersOnStructs || nonTrailingNamedArguments)
if (introduceRefModifiersOnStructs || introduceReadonlyAndInModifiers || nonTrailingNamedArguments)
return CSharp.LanguageVersion.CSharp7_2;
// C# 7.1 missing
if (outVariables || tupleTypes || tupleConversions || discards)
@ -650,16 +651,32 @@ namespace ICSharpCode.Decompiler @@ -650,16 +651,32 @@ namespace ICSharpCode.Decompiler
}
}
bool introduceRefAndReadonlyModifiersOnStructs = true;
bool introduceRefModifiersOnStructs = true;
/// <summary>
/// Gets/Sets whether IsByRefLikeAttribute and IsReadOnlyAttribute should be replaced with 'ref' and 'readonly' modifiers on structs.
/// Gets/Sets whether IsByRefLikeAttribute should be replaced with 'ref' modifiers on structs.
/// </summary>
public bool IntroduceRefAndReadonlyModifiersOnStructs {
get { return introduceRefAndReadonlyModifiersOnStructs; }
public bool IntroduceRefModifiersOnStructs {
get { return introduceRefModifiersOnStructs; }
set {
if (introduceRefAndReadonlyModifiersOnStructs != value) {
introduceRefAndReadonlyModifiersOnStructs = value;
if (introduceRefModifiersOnStructs != value) {
introduceRefModifiersOnStructs = value;
OnPropertyChanged();
}
}
}
bool introduceReadonlyAndInModifiers = true;
/// <summary>
/// Gets/Sets whether IsReadOnlyAttribute should be replaced with 'readonly' modifiers on structs
/// and with the 'in' modifier on parameters.
/// </summary>
public bool IntroduceReadonlyAndInModifiers {
get { return introduceReadonlyAndInModifiers; }
set {
if (introduceReadonlyAndInModifiers != value) {
introduceReadonlyAndInModifiers = value;
OnPropertyChanged();
}
}

16
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -84,9 +84,19 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -84,9 +84,19 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
KeepModifiers = 0x40,
/// <summary>
/// If this option is active, [IsReadOnlyAttribute] is removed and parameters are marked as in, structs as readonly.
/// Otherwise, the attribute is preserved but the parameters and structs are not marked.
/// </summary>
ReadOnlyStructsAndParameters = 0x80,
/// <summary>
/// If this option is active, [IsByRefLikeAttribute] is removed and structs are marked as ref.
/// Otherwise, the attribute is preserved but the structs are not marked.
/// </summary>
RefStructs = 0x100,
/// <summary>
/// Default settings: typical options for the decompiler, with all C# languages features enabled.
/// </summary>
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters | RefStructs
}
/// <summary>
@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.ExtensionMethods;
if (settings.DecimalConstants)
typeSystemOptions |= TypeSystemOptions.DecimalConstants;
if (settings.IntroduceRefModifiersOnStructs)
typeSystemOptions |= TypeSystemOptions.RefStructs;
if (settings.IntroduceReadonlyAndInModifiers)
typeSystemOptions |= TypeSystemOptions.ReadOnlyStructsAndParameters;
return typeSystemOptions;
}

7
ICSharpCode.Decompiler/TypeSystem/IParameter.cs

@ -37,7 +37,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -37,7 +37,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Gets whether this parameter is a C# 'out' parameter.
/// </summary>
bool IsOut { get; }
/// <summary>
/// Gets whether this parameter is a C# 'in' parameter.
/// </summary>
bool IsIn { get; }
/// <summary>
/// Gets whether this parameter is a C# 'params' parameter.
/// </summary>

6
ICSharpCode.Decompiler/TypeSystem/ITypeDefinition.cs

@ -44,6 +44,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -44,6 +44,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// For all other types: returns <see cref="SpecialType.UnknownType"/>.
/// </summary>
IType EnumUnderlyingType { get; }
/// <summary>
/// For structs: returns whether this is a readonly struct.
/// For all other types: returns false.
/// </summary>
bool IsReadOnly { get; }
/// <summary>
/// Gets the full name of this type.

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

@ -200,6 +200,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -200,6 +200,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
return (options & TypeSystemOptions.ExtensionMethods) != 0;
case "DecimalConstantAttribute":
return (options & TypeSystemOptions.DecimalConstants) != 0;
case "IsReadOnlyAttribute":
return (options & TypeSystemOptions.ReadOnlyStructsAndParameters) != 0;
case "IsByRefLikeAttribute":
return (options & TypeSystemOptions.RefStructs) != 0;
default:
return false;
}

9
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly IType type;
readonly string name;
readonly IReadOnlyList<IAttribute> attributes;
readonly bool isRef, isOut, isParams, isOptional;
readonly bool isRef, isOut, isIn, isParams, isOptional;
readonly object defaultValue;
readonly IParameterizedMember owner;
@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
public DefaultParameter(IType type, string name, IParameterizedMember owner = null, IReadOnlyList<IAttribute> attributes = null,
bool isRef = false, bool isOut = false, bool isParams = false, bool isOptional = false, object defaultValue = null)
bool isRef = false, bool isOut = false, bool isIn = false, bool isParams = false, bool isOptional = false, object defaultValue = null)
{
if (type == null)
throw new ArgumentNullException("type");
@ -59,6 +59,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -59,6 +59,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.attributes = attributes ?? EmptyList<IAttribute>.Instance;
this.isRef = isRef;
this.isOut = isOut;
this.isIn = isIn;
this.isParams = isParams;
this.isOptional = isOptional;
this.defaultValue = defaultValue;
@ -81,6 +82,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -81,6 +82,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public bool IsOut {
get { return isOut; }
}
public bool IsIn {
get { return IsIn; }
}
public bool IsParams {
get { return isParams; }

23
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs

@ -66,7 +66,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -66,7 +66,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (IsOptional && !HasConstantValueInSignature)
b.Add(KnownAttribute.Optional);
if (!IsOut) {
if (!IsOut && !IsIn) {
if ((attributes & ParameterAttributes.In) == ParameterAttributes.In)
b.Add(KnownAttribute.In);
if ((attributes & ParameterAttributes.Out) == ParameterAttributes.Out)
@ -80,17 +80,28 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -80,17 +80,28 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
#endregion
const ParameterAttributes inOut = ParameterAttributes.In | ParameterAttributes.Out;
public bool IsRef => Type.Kind == TypeKind.ByReference && (attributes & inOut) != ParameterAttributes.Out;
public bool IsRef => Type.Kind == TypeKind.ByReference && (attributes & inOut) == 0;
public bool IsOut => Type.Kind == TypeKind.ByReference && (attributes & inOut) == ParameterAttributes.Out;
public bool IsOptional => (attributes & ParameterAttributes.Optional) != 0;
public bool IsIn {
get {
if ((module.TypeSystemOptions & TypeSystemOptions.ReadOnlyStructsAndParameters) == 0 ||
Type.Kind != TypeKind.ByReference || (attributes & inOut) != ParameterAttributes.In)
return false;
var metadata = module.metadata;
var parameterDef = metadata.GetParameter(handle);
return parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.IsReadOnly);
}
}
public bool IsParams {
get {
if (Type.Kind != TypeKind.Array)
return false;
var metadata = module.metadata;
var propertyDef = metadata.GetParameter(handle);
return propertyDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ParamArray);
var parameterDef = metadata.GetParameter(handle);
return parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ParamArray);
}
}
@ -100,8 +111,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -100,8 +111,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
if (name != null)
return name;
var metadata = module.metadata;
var propertyDef = metadata.GetParameter(handle);
return LazyInit.GetOrSet(ref this.name, metadata.GetString(propertyDef.Name));
var parameterDef = metadata.GetParameter(handle);
return LazyInit.GetOrSet(ref this.name, metadata.GetString(parameterDef.Name));
}
}

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

@ -45,6 +45,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -45,6 +45,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly TypeAttributes attributes;
public TypeKind Kind { get; }
public bool IsByRefLike { get; }
public bool IsReadOnly { get; }
public ITypeDefinition DeclaringTypeDefinition { get; }
public IReadOnlyList<ITypeParameter> TypeParameters { get; }
public KnownTypeCode KnownTypeCode { get; }
@ -101,12 +102,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -101,12 +102,14 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
} else {
this.Kind = TypeKind.Struct;
this.IsByRefLike = td.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.IsByRefLike);
this.IsReadOnly = td.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.IsReadOnly);
}
} else if (td.IsDelegate(metadata)) {
this.Kind = TypeKind.Delegate;
} else {
this.Kind = TypeKind.Class;
this.HasExtensionMethods = this.IsStatic
&& (module.TypeSystemOptions & TypeSystemOptions.ExtensionMethods) == TypeSystemOptions.ExtensionMethods
&& td.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.Extension);
}
}

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

@ -156,6 +156,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -156,6 +156,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
IType IEntity.DeclaringType => null;
bool ITypeDefinition.HasExtensionMethods => false;
bool ITypeDefinition.IsReadOnly => false;
TypeKind IType.Kind => typeKind;

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

@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -38,6 +38,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
IEnumerable<IAttribute> IParameter.GetAttributes() => baseParameter.GetAttributes();
bool IParameter.IsRef => baseParameter.IsRef;
bool IParameter.IsOut => baseParameter.IsOut;
bool IParameter.IsIn => baseParameter.IsIn;
bool IParameter.IsParams => baseParameter.IsParams;
bool IParameter.IsOptional => baseParameter.IsOptional;
bool IParameter.HasConstantValueInSignature => baseParameter.HasConstantValueInSignature;

Loading…
Cancel
Save