From 1ec3f683ac4dd554693027e607453de1eb5d496e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 4 Aug 2010 20:35:59 +0200 Subject: [PATCH] CecilProjectContent: read classes --- .../ICSharpCode.NRefactory.csproj | 1 + .../TypeSystem/Accessibility.cs | 6 +- .../TypeSystem/CecilProjectContent.cs | 281 ++++++++++++++---- .../TypeSystem/ClassType.cs | 2 +- .../TypeSystem/EntityType.cs | 2 +- ICSharpCode.NRefactory/TypeSystem/IEntity.cs | 31 +- .../TypeSystem/Implementation/BitVector16.cs | 58 ++++ .../Implementation/DefaultTypeDefinition.cs | 70 ++--- 8 files changed, 330 insertions(+), 121 deletions(-) create mode 100644 ICSharpCode.NRefactory/TypeSystem/Implementation/BitVector16.cs diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 681529f4ae..5d34c8a676 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -148,6 +148,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/Accessibility.cs b/ICSharpCode.NRefactory/TypeSystem/Accessibility.cs index de7f6775ed..e075c5153d 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Accessibility.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Accessibility.cs @@ -8,8 +8,10 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Enum that describes the accessibility of an entity. /// - public enum Accessibility + public enum Accessibility : byte { + // note: some code depends on the fact that these values are within the range 0-7 + /// /// The entity is completely inaccessible. This is used for C# explicit interface implementations. /// @@ -37,6 +39,6 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// The entity is accessible in derived classes within the same project content. /// - ProtectedAndInternal + ProtectedAndInternal, } } diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs index 341e18a4cb..fe7e6fb54f 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilProjectContent.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics.Contracts; using System.Text; - using ICSharpCode.NRefactory.TypeSystem.Implementation; using Mono.Cecil; @@ -21,7 +21,31 @@ namespace ICSharpCode.NRefactory.TypeSystem #region Constructor public CecilProjectContent(AssemblyDefinition assemblyDefinition) { - this.assemblyAttributes = ReadAttributes(assemblyDefinition, this); + this.assemblyAttributes = new List(); + ReadAttributes(assemblyDefinition, this.assemblyAttributes); + this.assemblyAttributes = new ReadOnlyCollection(this.assemblyAttributes); + List types = new List(); + foreach (ModuleDefinition module in assemblyDefinition.Modules) { + foreach (TypeDefinition td in module.Types) { + if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) { + string name = td.FullName; + if (name.Length == 0 || name[0] == '<') + continue; + types.Add(new CecilTypeDefinition(this, td)); + } + } + } + foreach (CecilTypeDefinition c in types) { + c.Init(this); + } + } + + public CecilProjectContent(TypeDefinition typeDefinition) + { + this.assemblyAttributes = EmptyList.Instance; + List types = new List(); + types.Add(new CecilTypeDefinition(this, typeDefinition)); + types[0].Init(this); } #endregion @@ -195,6 +219,16 @@ namespace ICSharpCode.NRefactory.TypeSystem return new GetClassTypeReference(name, typeParameterCount); } + static string SplitTypeParameterCountFromReflectionName(string reflectionName) + { + int pos = reflectionName.LastIndexOf('`'); + if (pos < 0) { + return reflectionName; + } else { + return reflectionName.Substring(0, pos); + } + } + static string SplitTypeParameterCountFromReflectionName(string reflectionName, out int typeParameterCount) { int pos = reflectionName.LastIndexOf('`'); @@ -229,32 +263,51 @@ namespace ICSharpCode.NRefactory.TypeSystem #endregion #region Read Attributes - public static IList ReadAttributes(ICustomAttributeProvider attributeProvider, ITypeResolveContext earlyBindContext) + void ReadAttributes(ICustomAttributeProvider attributeProvider, IList outputList) { - Contract.Ensures(Contract.Result>() != null); - if (attributeProvider == null || !attributeProvider.HasCustomAttributes) - return EmptyList.Instance; - var cecilAttributes = attributeProvider.CustomAttributes; - IAttribute[] attributes = new IAttribute[cecilAttributes.Count]; - for (int i = 0; i < attributes.Length; i++) { - attributes[i] = new CecilAttribute(cecilAttributes[i], earlyBindContext); + foreach (var cecilAttribute in attributeProvider.CustomAttributes) { + outputList.Add(new CecilAttribute(cecilAttribute, this)); } - return Array.AsReadOnly(attributes); } sealed class CecilAttribute : Immutable, IAttribute { - ITypeReference attributeType; - volatile CustomAttribute ca; - ITypeResolveContext earlyBindContext; - IList positionalArguments; - IList> namedArguments; + readonly ITypeReference attributeType; + readonly IList positionalArguments; + readonly IList> namedArguments; public CecilAttribute(CustomAttribute ca, ITypeResolveContext earlyBindContext) { this.attributeType = ReadTypeReference(ca.AttributeType, earlyBindContext: earlyBindContext); - this.ca = ca; - this.earlyBindContext = earlyBindContext; + try { + if (ca.HasConstructorArguments) { + var posArgs = new List(); + foreach (var arg in ca.ConstructorArguments) { + posArgs.Add(ReadConstantValue(arg, earlyBindContext)); + } + this.positionalArguments = posArgs.AsReadOnly(); + } else { + this.positionalArguments = EmptyList.Instance; + } + } catch (InvalidOperationException) { + this.positionalArguments = EmptyList.Instance; + } + try { + if (ca.HasFields || ca.HasProperties) { + var namedArgs = new List>(); + foreach (var arg in ca.Fields) { + namedArgs.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument, earlyBindContext))); + } + foreach (var arg in ca.Properties) { + namedArgs.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument, earlyBindContext))); + } + this.namedArguments = namedArgs.AsReadOnly(); + } else { + this.namedArguments = EmptyList>.Instance; + } + } catch (InvalidOperationException) { + this.namedArguments = EmptyList>.Instance; + } } public DomRegion Region { @@ -266,68 +319,25 @@ namespace ICSharpCode.NRefactory.TypeSystem } public IList PositionalArguments { - get { - EnsureArguments(); - return positionalArguments; - } + get { return positionalArguments; } } public IList> NamedArguments { - get { - EnsureArguments(); - return namedArguments; - } - } - - void EnsureArguments() - { - CustomAttribute ca = this.ca; - if (ca != null) { - try { - if (ca.HasConstructorArguments) { - var posArgs = new List(); - foreach (var arg in ca.ConstructorArguments) { - posArgs.Add(ReadConstantValue(arg, earlyBindContext)); - } - this.positionalArguments = posArgs.AsReadOnly(); - } else { - this.positionalArguments = EmptyList.Instance; - } - } catch (InvalidOperationException) { - this.positionalArguments = EmptyList.Instance; - } - try { - if (ca.HasFields || ca.HasProperties) { - var namedArgs = new List>(); - foreach (var arg in ca.Fields) { - namedArgs.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument, earlyBindContext))); - } - foreach (var arg in ca.Properties) { - namedArgs.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument, earlyBindContext))); - } - this.namedArguments = namedArgs.AsReadOnly(); - } else { - this.namedArguments = EmptyList>.Instance; - } - } catch (InvalidOperationException) { - this.namedArguments = EmptyList>.Instance; - } - this.ca = null; - } + get { return namedArguments; } } } #endregion #region Read Constant Value - public static IConstantValue ReadConstantValue(CustomAttributeArgument arg, ITypeResolveContext earlyBindContext) + static IConstantValue ReadConstantValue(CustomAttributeArgument arg, ITypeResolveContext earlyBindContext) { return new CecilConstantValue(arg.Type, arg.Value, earlyBindContext); } sealed class CecilConstantValue : Immutable, IConstantValue { - ITypeReference type; - object value; + readonly ITypeReference type; + readonly object value; public CecilConstantValue(TypeReference type, object value, ITypeResolveContext earlyBindContext) { @@ -350,5 +360,144 @@ namespace ICSharpCode.NRefactory.TypeSystem } } #endregion + + #region Read Type Definition + class CecilTypeDefinition : DefaultTypeDefinition + { + TypeDefinition typeDefinition; + + public CecilTypeDefinition(IProjectContent pc, TypeDefinition typeDefinition) + : base(pc, typeDefinition.Namespace, SplitTypeParameterCountFromReflectionName(typeDefinition.Name)) + { + this.typeDefinition = typeDefinition; + } + + public CecilTypeDefinition(CecilTypeDefinition parentType, string name, TypeDefinition typeDefinition) + : base(parentType, name) + { + this.typeDefinition = typeDefinition; + } + + public void Init(CecilProjectContent pc) + { + InitNestedTypes(pc); + InitModifiers(); + + if (typeDefinition.HasGenericParameters) { + throw new NotImplementedException(); + /*foreach (GenericParameter g in td.GenericParameters) { + this.TypeParameters.Add(new DefaultTypeParameter(this, g.Name, g.Position)); + } + int i = 0; + foreach (GenericParameter g in td.GenericParameters) { + AddConstraintsFromType(this.TypeParameters[i++], g); + }*/ + } + + if (typeDefinition.HasCustomAttributes) { + pc.ReadAttributes(typeDefinition, this.Attributes); + } + + // set base classes + if (typeDefinition.BaseType != null) { + BaseTypes.Add(ReadTypeReference(typeDefinition.BaseType, entity: this, earlyBindContext: pc)); + } + if (typeDefinition.HasInterfaces) { + foreach (TypeReference iface in typeDefinition.Interfaces) { + BaseTypes.Add(ReadTypeReference(iface, entity: this, earlyBindContext: pc)); + } + } + + InitMembers(pc); + + this.typeDefinition = null; + Freeze(); // freeze after initialization + } + + void InitNestedTypes(CecilProjectContent pc) + { + if (!typeDefinition.HasNestedTypes) + return; + foreach (TypeDefinition nestedType in typeDefinition.NestedTypes) { + TypeAttributes visibility = nestedType.Attributes & TypeAttributes.VisibilityMask; + if (visibility == TypeAttributes.NestedPublic + || visibility == TypeAttributes.NestedFamily + || visibility == TypeAttributes.NestedFamORAssem) + { + string name = nestedType.Name; + int pos = name.LastIndexOf('/'); + if (pos > 0) + name = name.Substring(pos + 1); + if (name.Length == 0 || name[0] == '<') + continue; + name = SplitTypeParameterCountFromReflectionName(name); + InnerClasses.Add(new CecilTypeDefinition(this, name, nestedType)); + } + } + foreach (CecilTypeDefinition innerClass in this.InnerClasses) { + innerClass.Init(pc); + } + } + + void InitModifiers() + { + TypeDefinition td = this.typeDefinition; + // set classtype + if (td.IsInterface) { + this.ClassType = ClassType.Interface; + } else if (td.IsEnum) { + this.ClassType = ClassType.Enum; + } else if (td.IsValueType) { + this.ClassType = ClassType.Struct; + } else if (IsDelegate(td)) { + this.ClassType = ClassType.Delegate; + } else if (IsModule(td)) { + this.ClassType = ClassType.Module; + } else { + this.ClassType = ClassType.Class; + } + this.IsSealed = td.IsSealed; + this.IsAbstract = td.IsAbstract; + if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic) { + this.Accessibility = Accessibility.Public; + } else if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily) { + this.Accessibility = Accessibility.Protected; + } else if ((td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) { + // we don't care about the 'OrAssem' part because it's an external assembly + this.Accessibility = Accessibility.Protected; + } else { + this.Accessibility = Accessibility.Public; + } + } + + static bool IsDelegate(TypeDefinition type) + { + if (type.BaseType == null) + return false; + else + return type.BaseType.FullName == "System.Delegate" + || type.BaseType.FullName == "System.MulticastDelegate"; + } + + static bool IsModule(TypeDefinition type) + { + if (!type.HasCustomAttributes) + return false; + foreach (var att in type.CustomAttributes) { + if (att.AttributeType.FullName == "Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute" + || att.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGlobalScopeAttribute") + { + return true; + } + } + return false; + } + + void InitMembers(CecilProjectContent pc) + { + throw new NotImplementedException(); + } + } + #endregion } } diff --git a/ICSharpCode.NRefactory/TypeSystem/ClassType.cs b/ICSharpCode.NRefactory/TypeSystem/ClassType.cs index 539a55305a..5cb63bdfec 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ClassType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ClassType.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace ICSharpCode.NRefactory.TypeSystem { - public enum ClassType + public enum ClassType : byte { Class, Enum, diff --git a/ICSharpCode.NRefactory/TypeSystem/EntityType.cs b/ICSharpCode.NRefactory/TypeSystem/EntityType.cs index 98e79850ff..c572b01be8 100644 --- a/ICSharpCode.NRefactory/TypeSystem/EntityType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/EntityType.cs @@ -8,7 +8,7 @@ namespace ICSharpCode.NRefactory.TypeSystem { public enum EntityType { - Class, + TypeDefinition, Field, Property, Indexer, diff --git a/ICSharpCode.NRefactory/TypeSystem/IEntity.cs b/ICSharpCode.NRefactory/TypeSystem/IEntity.cs index 9633eb0121..841c8dc2e3 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IEntity.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IEntity.cs @@ -26,41 +26,44 @@ namespace ICSharpCode.NRefactory.TypeSystem string Documentation { get; } + /// + /// Gets the accessibility of this entity. + /// + Accessibility Accessibility { get; } + /// /// Gets whether this entity is static. /// Returns true if either the 'static' or the 'const' modifier is set. /// - bool IsStatic { - get; - } - - Accessibility Accessibility { get; } + bool IsStatic { get; } + /// + /// Returns whether this entity is abstract. + /// + /// Static classes also count as abstract classes. bool IsAbstract { get; } + /// + /// Returns whether this entity is sealed. + /// + /// Static classes also count as sealed classes. bool IsSealed { get; } /// /// Gets whether this member is declared to be shadowing another member with the same name. /// - bool IsShadowing { - get; - } + bool IsShadowing { get; } /// /// Gets whether this member is generated by a macro/compiler feature. /// - bool IsSynthetic { - get; - } + bool IsSynthetic { get; } /// /// The assembly in which this entity is defined. /// This property never returns null. /// - IProjectContent ProjectContent { - get; - } + IProjectContent ProjectContent { get; } //bool IsAccessible(IClass callingClass, bool isAccessThoughReferenceOfCurrentClass); } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/BitVector16.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/BitVector16.cs new file mode 100644 index 0000000000..ad4aeb45ca --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/BitVector16.cs @@ -0,0 +1,58 @@ +// +// +// +// +// $Revision$ +// +using System; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Holds 16 boolean values. + /// + public struct BitVector16 : IEquatable + { + ushort data; + + public bool this[ushort mask] { + get { return (data & mask) != 0; } + set { + if (value) + data |= mask; + else + data &= unchecked((ushort)~mask); + } + } + + #region Equals and GetHashCode implementation + public override bool Equals(object obj) + { + if (obj is BitVector16) + return Equals((BitVector16)obj); // use Equals method below + else + return false; + } + + public bool Equals(BitVector16 other) + { + return this.data == other.data; + } + + public override int GetHashCode() + { + return data; + } + + public static bool operator ==(BitVector16 left, BitVector16 right) + { + return left.Equals(right); + } + + public static bool operator !=(BitVector16 left, BitVector16 right) + { + return !left.Equals(right); + } + #endregion + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs index ce97d5ae63..ed6f5c7968 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Diagnostics.Contracts; @@ -21,7 +22,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation readonly string ns; readonly string name; - ClassType classType; IList baseTypes; IList typeParameters; IList innerClasses; @@ -33,7 +33,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation DomRegion region; DomRegion bodyRegion; + + // 1 byte per enum + 2 bytes for flags + ClassType classType; Accessibility accessibility; + BitVector16 flags; + const ushort FlagSealed = 0x0001; + const ushort FlagAbstract = 0x0002; + const ushort FlagShadowing = 0x0004; + const ushort FlagSynthetic = 0x0008; protected override void FreezeInternal() { @@ -209,7 +217,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } public EntityType EntityType { - get { return EntityType.Class; } + get { return EntityType.TypeDefinition; } } public DomRegion Region { @@ -248,12 +256,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return null; } } - public bool IsStatic { - get { - throw new NotImplementedException(); - } - } - public Accessibility Accessibility { get { return accessibility; } set { @@ -262,45 +264,39 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - public bool IsAbstract { - get { - throw new NotImplementedException(); - } - } - - public bool IsSealed { - get { - throw new NotImplementedException(); - } - } - - public bool IsVirtual { - get { - throw new NotImplementedException(); - } + public bool IsStatic { + get { return IsAbstract && IsSealed; } } - public bool IsOverride { - get { - throw new NotImplementedException(); + public bool IsAbstract { + get { return flags[FlagAbstract]; } + set { + CheckBeforeMutation(); + flags[FlagAbstract] = value; } } - public bool IsOverridable { - get { - throw new NotImplementedException(); + public bool IsSealed { + get { return flags[FlagSealed]; } + set { + CheckBeforeMutation(); + flags[FlagSealed] = value; } } public bool IsShadowing { - get { - throw new NotImplementedException(); + get { return flags[FlagShadowing]; } + set { + CheckBeforeMutation(); + flags[FlagShadowing] = value; } } public bool IsSynthetic { - get { - throw new NotImplementedException(); + get { return flags[FlagSynthetic]; } + set { + CheckBeforeMutation(); + flags[FlagSynthetic] = value; } } @@ -385,9 +381,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation // We do not check the project content because assemblies might or might not // be equivalent depending on compiler settings and runtime assembly // redirection. - return other.DeclaringTypeDefinition == null - && this.Namespace == other.Namespace - && this.Name == other.Name + return other.DeclaringTypeDefinition == null + && this.Namespace == other.Namespace + && this.Name == other.Name && this.TypeParameterCount == other.TypeParameterCount; } }