Browse Source

Show attributes on type parameter constraints in C# decompilation.

pull/1641/head
Daniel Grunwald 6 years ago
parent
commit
c1510027df
  1. 18
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs
  3. 4
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/Constraint.cs
  4. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs
  5. 16
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  6. 4
      ICSharpCode.Decompiler/TypeSystem/ISymbol.cs
  7. 17
      ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs
  8. 6
      ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs
  9. 28
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs
  10. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/DummyTypeParameter.cs
  11. 31
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs
  12. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/NullabilityAnnotatedType.cs
  13. 11
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs

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

@ -1313,10 +1313,15 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1313,10 +1313,15 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
WriteCommaSeparatedList(attributeSection.Attributes);
WriteToken(Roles.RBracket);
if (attributeSection.Parent is ParameterDeclaration || attributeSection.Parent is TypeParameterDeclaration) {
Space();
} else {
NewLine();
switch (attributeSection.Parent) {
case ParameterDeclaration _:
case TypeParameterDeclaration _:
case ComposedType _:
Space();
break;
default:
NewLine();
break;
}
EndNode(attributeSection);
}
@ -2349,6 +2354,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2349,6 +2354,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitComposedType(ComposedType composedType)
{
StartNode(composedType);
if (composedType.Attributes.Any()) {
foreach (var attr in composedType.Attributes) {
attr.AcceptVisitor(this);
}
}
if (composedType.HasRefSpecifier) {
WriteKeyword(ComposedType.RefRole);
}

4
ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs

@ -35,11 +35,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,11 +35,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public class ComposedType : AstType
{
public static readonly Role<AttributeSection> AttributeRole = EntityDeclaration.AttributeRole;
public static readonly TokenRole RefRole = new TokenRole("ref");
public static readonly TokenRole ReadonlyRole = new TokenRole("readonly");
public static readonly TokenRole NullableRole = new TokenRole("?");
public static readonly TokenRole PointerRole = new TokenRole("*");
public static readonly Role<ArraySpecifier> ArraySpecifierRole = new Role<ArraySpecifier>("ArraySpecifier");
public AstNodeCollection<AttributeSection> Attributes {
get { return base.GetChildrenByRole(AttributeRole); }
}
/// <summary>
/// Gets/sets whether this type has a 'ref' specifier.

4
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/Constraint.cs

@ -36,9 +36,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -36,9 +36,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class Constraint : AstNode
{
public override NodeType NodeType {
get {
return NodeType.Unknown;
}
get { return NodeType.Unknown; }
}
public CSharpTokenNode WhereKeyword {

1
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs

@ -25,7 +25,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -25,7 +25,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public abstract class EntityDeclaration : AstNode
{
public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute");
public static readonly Role<AttributeSection> UnattachedAttributeRole = new Role<AttributeSection>("UnattachedAttribute");
public static readonly Role<CSharpModifierToken> ModifierRole = new Role<CSharpModifierToken>("Modifier");
public static readonly Role<AstType> PrivateImplementationTypeRole = new Role<AstType>("PrivateImplementationType", AstType.Null);

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

@ -1805,9 +1805,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1805,9 +1805,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} else if (tp.NullabilityConstraint == Nullability.NotNullable) {
c.BaseTypes.Add(new PrimitiveType("notnull"));
}
foreach (IType t in tp.DirectBaseTypes) {
if (!IsObjectOrValueType(t))
c.BaseTypes.Add(ConvertType(t));
foreach (TypeConstraint t in tp.TypeConstraints) {
if (!IsObjectOrValueType(t.Type) || t.Attributes.Count > 0) {
AstType astType = ConvertType(t.Type);
if (t.Attributes.Count > 0) {
var attrSection = new AttributeSection();
attrSection.Attributes.AddRange(t.Attributes.Select(ConvertAttribute));
astType = new ComposedType {
Attributes = { attrSection },
BaseType = astType
};
}
c.BaseTypes.Add(astType);
}
}
if (tp.HasDefaultConstructorConstraint && !tp.HasValueTypeConstraint) {
c.BaseTypes.Add(new PrimitiveType("new"));

4
ICSharpCode.Decompiler/TypeSystem/ISymbol.cs

@ -69,6 +69,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -69,6 +69,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
Parameter,
/// <seealso cref="ITypeParameter"/>
TypeParameter,
/// <summary>
/// Constraint on a type parameter.
/// </summary>
Constraint,
}
/// <summary>

17
ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs

@ -16,7 +16,9 @@ @@ -16,7 +16,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem
{
@ -99,6 +101,21 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -99,6 +101,21 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// E.g. "T? GetNull&lt;T&gt;() where T : class => null;"
/// </summary>
Nullability NullabilityConstraint { get; }
IReadOnlyList<TypeConstraint> TypeConstraints { get; }
}
public readonly struct TypeConstraint
{
public SymbolKind SymbolKind => SymbolKind.Constraint;
public IType Type { get; }
public IReadOnlyList<IAttribute> Attributes { get; }
public TypeConstraint(IType type, IReadOnlyList<IAttribute> attributes = null)
{
this.Type = type ?? throw new ArgumentNullException(nameof(type));
this.Attributes = attributes ?? EmptyList<IAttribute>.Instance;
}
}
/// <summary>

6
ICSharpCode.Decompiler/TypeSystem/Implementation/AbstractTypeParameter.cs

@ -220,7 +220,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -220,7 +220,11 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
get { return EmptyList<IType>.Instance; }
}
public abstract IEnumerable<IType> DirectBaseTypes { get; }
public IEnumerable<IType> DirectBaseTypes {
get { return TypeConstraints.Select(t => t.Type); }
}
public abstract IReadOnlyList<TypeConstraint> TypeConstraints { get; }
public string Name {
get { return name; }

28
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultTypeParameter.cs

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler.Util;
@ -43,10 +44,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -43,10 +44,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.hasReferenceTypeConstraint = hasReferenceTypeConstraint;
this.hasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
this.nullabilityConstraint = nullabilityConstraint;
this.constraints = constraints ?? EmptyList<IType>.Instance;
this.TypeConstraints = MakeConstraints(constraints);
this.attributes = attributes ?? EmptyList<IAttribute>.Instance;
}
public DefaultTypeParameter(
ICompilation compilation, SymbolKind ownerType,
int index, string name = null,
@ -60,7 +61,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -60,7 +61,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.hasReferenceTypeConstraint = hasReferenceTypeConstraint;
this.hasDefaultConstructorConstraint = hasDefaultConstructorConstraint;
this.nullabilityConstraint = nullabilityConstraint;
this.constraints = constraints ?? EmptyList<IType>.Instance;
this.TypeConstraints = MakeConstraints(constraints);
this.attributes = attributes ?? EmptyList<IAttribute>.Instance;
}
@ -72,19 +73,24 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -72,19 +73,24 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override bool HasUnmanagedConstraint => false;
public override Nullability NullabilityConstraint => nullabilityConstraint;
public override IEnumerable<IType> DirectBaseTypes {
get {
bool hasNonInterfaceConstraint = false;
public override IReadOnlyList<TypeConstraint> TypeConstraints { get; }
IReadOnlyList<TypeConstraint> MakeConstraints(IReadOnlyList<IType> constraints)
{
var result = new List<TypeConstraint>();
bool hasNonInterfaceConstraint = false;
if (constraints != null) {
foreach (IType c in constraints) {
yield return c;
result.Add(new TypeConstraint(c));
if (c.Kind != TypeKind.Interface)
hasNonInterfaceConstraint = true;
}
// Do not add the 'System.Object' constraint if there is another constraint with a base class.
if (this.HasValueTypeConstraint || !hasNonInterfaceConstraint) {
yield return this.Compilation.FindType(this.HasValueTypeConstraint ? KnownTypeCode.ValueType : KnownTypeCode.Object);
}
}
// Do not add the 'System.Object' constraint if there is another constraint with a base class.
if (this.HasValueTypeConstraint || !hasNonInterfaceConstraint) {
result.Add(new TypeConstraint(this.Compilation.FindType(this.HasValueTypeConstraint ? KnownTypeCode.ValueType : KnownTypeCode.Object)));
}
return result;
}
}
}

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

@ -169,6 +169,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -169,6 +169,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
bool ITypeParameter.HasUnmanagedConstraint => false;
Nullability ITypeParameter.NullabilityConstraint => Nullability.Oblivious;
IReadOnlyList<TypeConstraint> ITypeParameter.TypeConstraints => EmptyList<TypeConstraint>.Instance;
public override IType ChangeNullability(Nullability nullability)
{
if (nullability == Nullability.Oblivious) {

31
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeParameter.cs

@ -19,6 +19,7 @@ @@ -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;
@ -34,7 +35,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -34,7 +35,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly GenericParameterAttributes attr;
// lazy-loaded:
IReadOnlyList<IType> constraints;
IReadOnlyList<TypeConstraint> constraints;
byte unmanagedConstraint = ThreeState.Unknown;
const byte nullabilityNotYetLoaded = 255;
byte nullabilityConstraint = nullabilityNotYetLoaded;
@ -170,16 +171,17 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -170,16 +171,17 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
}
public override IEnumerable<IType> DirectBaseTypes {
public override IReadOnlyList<TypeConstraint> TypeConstraints {
get {
var constraints = LazyInit.VolatileRead(ref this.constraints);
if (constraints != null)
return constraints;
return LazyInit.GetOrSet(ref this.constraints, DecodeConstraints());
if (constraints == null) {
constraints = LazyInit.GetOrSet(ref this.constraints, DecodeConstraints());
}
return constraints;
}
}
private IReadOnlyList<IType> DecodeConstraints()
private IReadOnlyList<TypeConstraint> DecodeConstraints()
{
var metadata = module.metadata;
var gp = metadata.GetGenericParameter(handle);
@ -193,18 +195,25 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -193,18 +195,25 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
var constraintHandleCollection = gp.GetConstraints();
List<IType> result = new List<IType>(constraintHandleCollection.Count + 1);
var result = new List<TypeConstraint>(constraintHandleCollection.Count + 1);
bool hasNonInterfaceConstraint = false;
foreach (var constraintHandle in constraintHandleCollection) {
var constraint = metadata.GetGenericParameterConstraint(constraintHandle);
var ty = module.ResolveType(constraint.Type, new GenericContext(Owner), constraint.GetCustomAttributes(), nullableContext);
result.Add(ty);
var attrs = constraint.GetCustomAttributes();
var ty = module.ResolveType(constraint.Type, new GenericContext(Owner), attrs, nullableContext);
if (attrs.Count == 0) {
result.Add(new TypeConstraint(ty));
} else {
AttributeListBuilder b = new AttributeListBuilder(module);
b.Add(attrs, SymbolKind.Constraint);
result.Add(new TypeConstraint(ty, b.Build()));
}
hasNonInterfaceConstraint |= (ty.Kind != TypeKind.Interface);
}
if (this.HasValueTypeConstraint) {
result.Add(Compilation.FindType(KnownTypeCode.ValueType));
result.Add(new TypeConstraint(Compilation.FindType(KnownTypeCode.ValueType)));
} else if (!hasNonInterfaceConstraint) {
result.Add(Compilation.FindType(KnownTypeCode.Object));
result.Add(new TypeConstraint(Compilation.FindType(KnownTypeCode.Object)));
}
return result;
}

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

@ -107,6 +107,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -107,6 +107,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
bool ITypeParameter.HasValueTypeConstraint => baseType.HasValueTypeConstraint;
bool ITypeParameter.HasUnmanagedConstraint => baseType.HasUnmanagedConstraint;
Nullability ITypeParameter.NullabilityConstraint => baseType.NullabilityConstraint;
IReadOnlyList<TypeConstraint> ITypeParameter.TypeConstraints => baseType.TypeConstraints;
SymbolKind ISymbol.SymbolKind => SymbolKind.TypeParameter;
IEnumerable<IAttribute> ITypeParameter.GetAttributes() => baseType.GetAttributes();
}

11
ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedMethod.cs

@ -257,9 +257,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -257,9 +257,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public override Nullability NullabilityConstraint => baseTp.NullabilityConstraint;
public override IEnumerable<IType> DirectBaseTypes {
IReadOnlyList<TypeConstraint> typeConstraints;
public override IReadOnlyList<TypeConstraint> TypeConstraints {
get {
return baseTp.DirectBaseTypes.Select(t => t.AcceptVisitor(substitution));
var typeConstraints = LazyInit.VolatileRead(ref this.typeConstraints);
if (typeConstraints == null) {
typeConstraints = baseTp.TypeConstraints.SelectReadOnlyArray(c => new TypeConstraint(c.Type.AcceptVisitor(substitution), c.Attributes));
typeConstraints = LazyInit.GetOrSet(ref this.typeConstraints, typeConstraints);
}
return typeConstraints;
}
}
}

Loading…
Cancel
Save