diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index c970897e28..599cd788b6 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -73,22 +73,23 @@ namespace ICSharpCode.NRefactory.TypeSystem [Test] public void AssemblyAttribute() { - ITypeResolveContext ctx = MultiTypeResolveContext.Combine(testCasePC, CecilLoaderTests.Mscorlib); + ITypeResolveContext ctx = AggregateTypeResolveContext.Combine(testCasePC, CecilLoaderTests.Mscorlib); var attributes = testCasePC.AssemblyAttributes; - var typeTest = attributes.First(a => a.AttributeType.Resolve(testCasePC).FullName == typeof(TypeTestAttribute).FullName); + var typeTest = attributes.First(a => a.AttributeType.Resolve(ctx).FullName == typeof(TypeTestAttribute).FullName); Assert.AreEqual(3, typeTest.PositionalArguments.Count); // first argument is (int)42 - Assert.AreEqual(42, (int)typeTest.PositionalArguments[0].GetValue(testCasePC)); + Assert.AreEqual(42, (int)typeTest.PositionalArguments[0].GetValue(ctx)); // second argument is typeof(System.Action<>) - IType rt = (IType)typeTest.PositionalArguments[1].GetValue(testCasePC); + IType rt = (IType)typeTest.PositionalArguments[1].GetValue(ctx); Assert.IsFalse(rt is ConstructedType); // rt must not be constructed - it's just an unbound type Assert.AreEqual("System.Action", rt.FullName); Assert.AreEqual(1, rt.TypeParameterCount); // third argument is typeof(IDictionary>) - ConstructedType crt = (ConstructedType)typeTest.PositionalArguments[2]; + ConstructedType crt = (ConstructedType)typeTest.PositionalArguments[2].GetValue(ctx); Assert.AreEqual("System.Collections.Generic.IDictionary", crt.FullName); Assert.AreEqual("System.String", crt.TypeArguments[0].FullName); - Assert.AreEqual("System.Collections.Generic.IList{NUnit.Framework.TestAttribute}", crt.TypeArguments[1].DotNetName); + // ? for NUnit.TestAttribute (because that assembly isn't in ctx) + Assert.AreEqual("System.Collections.Generic.IList[[?]]", crt.TypeArguments[1].DotNetName); } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 2377e837c7..6a46b98bfa 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -167,9 +167,10 @@ + - + diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index ef5cae2397..0cdeb1f315 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.TypeSystem TypeStorage typeStorage = new TypeStorage(); CecilProjectContent pc = new CecilProjectContent(typeStorage, assemblyDefinition.Name.FullName, assemblyAttributes.AsReadOnly()); - this.EarlyBindContext = MultiTypeResolveContext.Combine(pc, this.EarlyBindContext); + this.EarlyBindContext = AggregateTypeResolveContext.Combine(pc, this.EarlyBindContext); List types = new List(); foreach (ModuleDefinition module in assemblyDefinition.Modules) { foreach (TypeDefinition td in module.Types) { @@ -223,7 +223,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } else { string name = type.FullName; if (name == null) - throw new ApplicationException("type.FullName returned null. Type: " + type.ToString()); + throw new InvalidOperationException("type.FullName returned null. Type: " + type.ToString()); if (name.IndexOf('/') > 0) { string[] nameparts = name.Split('/'); @@ -310,68 +310,33 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - public IAttribute ReadAttribute(CustomAttribute cecilAttribute) + public IAttribute ReadAttribute(CustomAttribute attribute) { - if (cecilAttribute == null) - throw new ArgumentNullException("cecilAttribute"); - return new CecilAttribute(cecilAttribute, this); - } - - sealed class CecilAttribute : Immutable, IAttribute - { - readonly ITypeReference attributeType; - readonly IList positionalArguments; - readonly IList> namedArguments; - - public CecilAttribute(CustomAttribute ca, CecilLoader loader) - { - this.attributeType = loader.ReadTypeReference(ca.AttributeType); - try { - if (ca.HasConstructorArguments) { - var posArgs = new List(); - foreach (var arg in ca.ConstructorArguments) { - posArgs.Add(loader.ReadConstantValue(arg)); - } - this.positionalArguments = posArgs.AsReadOnly(); - } else { - this.positionalArguments = EmptyList.Instance; + if (attribute == null) + throw new ArgumentNullException("attribute"); + DefaultAttribute a = new DefaultAttribute(ReadTypeReference(attribute.AttributeType)); + try { + if (attribute.HasConstructorArguments) { + foreach (var arg in attribute.ConstructorArguments) { + a.PositionalArguments.Add(ReadConstantValue(arg)); } - } 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, loader.ReadConstantValue(arg.Argument))); - } - foreach (var arg in ca.Properties) { - namedArgs.Add(new KeyValuePair(arg.Name, loader.ReadConstantValue(arg.Argument))); - } - this.namedArguments = namedArgs.AsReadOnly(); - } else { - this.namedArguments = EmptyList>.Instance; + } catch (InvalidOperationException) { + // occurs when Cecil can't decode an argument + } + try { + if (attribute.HasFields || attribute.HasProperties) { + foreach (var arg in attribute.Fields) { + a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); + } + foreach (var arg in attribute.Properties) { + a.NamedArguments.Add(new KeyValuePair(arg.Name, ReadConstantValue(arg.Argument))); } - } catch (InvalidOperationException) { - this.namedArguments = EmptyList>.Instance; } + } catch (InvalidOperationException) { + // occurs when Cecil can't decode an argument } - - public DomRegion Region { - get { return DomRegion.Empty; } - } - - public ITypeReference AttributeType { - get { return attributeType; } - } - - public IList PositionalArguments { - get { return positionalArguments; } - } - - public IList> NamedArguments { - get { return namedArguments; } - } + return a; } #endregion @@ -555,6 +520,29 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + if (typeDefinition.HasFields) { + foreach (FieldDefinition field in typeDefinition.Fields) { + if (loader.IsVisible(field.Attributes)) { + this.Fields.Add(loader.ReadField(field, this)); + } + } + } + if (typeDefinition.HasProperties) { + foreach (PropertyDefinition property in typeDefinition.Properties) { + bool getterVisible = property.GetMethod != null && loader.IsVisible(property.GetMethod.Attributes); + bool setterVisible = property.SetMethod != null && loader.IsVisible(property.SetMethod.Attributes); + if (getterVisible || setterVisible) { + this.Properties.Add(loader.ReadProperty(property, this)); + } + } + } + if (typeDefinition.HasEvents) { + foreach (EventDefinition ev in typeDefinition.Events) { + if (ev.AddMethod != null && loader.IsVisible(ev.AddMethod.Attributes)) { + this.Events.Add(loader.ReadEvent(ev, this)); + } + } + } } } #endregion @@ -584,13 +572,7 @@ namespace ICSharpCode.NRefactory.TypeSystem AddAttributes(method, m.Attributes); } - if (parentType.ClassType == ClassType.Interface) { - // interface members don't have modifiers, but we want to handle them as "public abstract" - m.Accessibility = Accessibility.Public; - m.IsAbstract = true; - } else { - TranslateModifiers(method, m); - } + TranslateModifiers(method, m); if (method.HasParameters) { foreach (ParameterDefinition p in method.Parameters) { @@ -620,11 +602,11 @@ namespace ICSharpCode.NRefactory.TypeSystem || att == MethodAttributes.FamORAssem; } - Accessibility GetAccessibility(MethodAttributes attr) + static Accessibility GetAccessibility(MethodAttributes attr) { switch (attr & MethodAttributes.MemberAccessMask) { - case MethodAttributes.Private: - return Accessibility.Private; + case MethodAttributes.Public: + return Accessibility.Public; case MethodAttributes.FamANDAssem: return Accessibility.ProtectedAndInternal; case MethodAttributes.Assem: @@ -634,19 +616,25 @@ namespace ICSharpCode.NRefactory.TypeSystem case MethodAttributes.FamORAssem: return Accessibility.ProtectedOrInternal; default: - return Accessibility.Public; + return Accessibility.Private; } } - void TranslateModifiers(MethodDefinition method, AbstractMember member) + void TranslateModifiers(MethodDefinition method, AbstractMember m) { - member.Accessibility = GetAccessibility(method.Attributes); - if (method.IsAbstract) - member.IsAbstract = true; - else if (method.IsFinal) - member.IsSealed = true; - else if (method.IsVirtual) - member.IsVirtual = true; + if (m.DeclaringTypeDefinition.ClassType == ClassType.Interface) { + // interface members don't have modifiers, but we want to handle them as "public abstract" + m.Accessibility = Accessibility.Public; + m.IsAbstract = true; + } else { + m.Accessibility = GetAccessibility(method.Attributes); + if (method.IsAbstract) + m.IsAbstract = true; + else if (method.IsFinal) + m.IsSealed = true; + else if (method.IsVirtual) + m.IsVirtual = true; + } } #endregion @@ -695,6 +683,11 @@ namespace ICSharpCode.NRefactory.TypeSystem || att == FieldAttributes.Family || att == FieldAttributes.FamORAssem; } + + public IField ReadField(FieldDefinition field, ITypeDefinition parentType) + { + throw new NotImplementedException(); + } #endregion void AddExplicitInterfaceImplementations(MethodDefinition method, AbstractMember targetMember) @@ -727,5 +720,43 @@ namespace ICSharpCode.NRefactory.TypeSystem } } #endregion + + #region Read Property + public IProperty ReadProperty(PropertyDefinition property, ITypeDefinition parentType) + { + if (property == null) + throw new ArgumentNullException("property"); + if (parentType == null) + throw new ArgumentNullException("parentType"); + DefaultProperty p = new DefaultProperty(parentType, property.Name); + TranslateModifiers(property.GetMethod ?? property.SetMethod, p); + p.ReturnType = ReadTypeReference(property.PropertyType, typeAttributes: property, entity: p); + + p.CanGet = property.GetMethod != null && IsVisible(property.GetMethod.Attributes); + p.CanSet = property.SetMethod != null && IsVisible(property.SetMethod.Attributes); + + if (p.CanGet) + p.GetterAccessibility = GetAccessibility(property.GetMethod.Attributes); + if (p.CanSet) + p.SetterAccessibility = GetAccessibility(property.SetMethod.Attributes); + + if (property.HasParameters) { + foreach (ParameterDefinition par in property.Parameters) { + p.Parameters.Add(ReadParameter(par, parentMember: p)); + } + } + if (property.HasCustomAttributes) + AddAttributes(property, p.Attributes); + + return p; + } + #endregion + + #region Read Event + public IEvent ReadEvent(EventDefinition ev, ITypeDefinition parentType) + { + throw new NotImplementedException(); + } + #endregion } } diff --git a/ICSharpCode.NRefactory/TypeSystem/IProperty.cs b/ICSharpCode.NRefactory/TypeSystem/IProperty.cs index 43caf6c8b5..096356e8b5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IProperty.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IProperty.cs @@ -10,8 +10,14 @@ namespace ICSharpCode.NRefactory.TypeSystem /// public interface IProperty : IParameterizedMember { - IMethod GetMethod { get; } - IMethod SetMethod { get; } + bool CanGet { get; } + bool CanSet { get; } + + Accessibility GetterAccessibility { get; } + Accessibility SetterAccessibility { get; } + + //IMethod GetMethod { get; } + //IMethod SetMethod { get; } bool IsIndexer { get; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs index b6439a094c..43ee6f2b10 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs @@ -22,6 +22,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation // 1 byte per enum + 2 bytes for flags Accessibility accessibility; EntityType entityType; + protected BitVector16 flags; const ushort FlagSealed = 0x0001; const ushort FlagAbstract = 0x0002; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/MultiTypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AggregateTypeResolveContext.cs similarity index 93% rename from ICSharpCode.NRefactory/TypeSystem/Implementation/MultiTypeResolveContext.cs rename to ICSharpCode.NRefactory/TypeSystem/Implementation/AggregateTypeResolveContext.cs index 1b92d78364..201154c13b 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/MultiTypeResolveContext.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AggregateTypeResolveContext.cs @@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// Represents multiple type resolve contexts. /// - public class MultiTypeResolveContext : ITypeResolveContext + public class AggregateTypeResolveContext : ITypeResolveContext { /// /// Creates a that combines the given resolve contexts. @@ -23,7 +23,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return b; if (b == null) return a; - return new MultiTypeResolveContext(new [] { a, b }); + return new AggregateTypeResolveContext(new [] { a, b }); } readonly ITypeResolveContext[] contexts; @@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// Creates a new /// - public MultiTypeResolveContext(IEnumerable contexts) + public AggregateTypeResolveContext(IEnumerable contexts) { if (contexts == null) throw new ArgumentNullException("contexts"); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs index a1ecb52fe4..b178016e80 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs @@ -13,7 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public sealed class DefaultAttribute : AbstractFreezable, IAttribute { DomRegion region; - ITypeReference attributeType = SharedTypes.UnknownType; + ITypeReference attributeType; IList positionalArguments; IList> namedArguments; @@ -34,6 +34,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation base.FreezeInternal(); } + public DefaultAttribute(ITypeReference attributeType) + { + if (attributeType == null) + throw new ArgumentNullException("attributeType"); + this.attributeType = attributeType; + } + public DomRegion Region { get { return region; } set { diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultProperty.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultProperty.cs new file mode 100644 index 0000000000..aab8216deb --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultProperty.cs @@ -0,0 +1,79 @@ + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Default implementation of . + /// + public class DefaultProperty : AbstractMember, IProperty + { + Accessibility getterAccessibility; + Accessibility setterAccessibility; + IList parameters; + + const ushort FlagIsIndexer = 0x1000; + const ushort FlagCanGet = 0x2000; + const ushort FlagCanSet = 0x4000; + + protected override void FreezeInternal() + { + parameters = FreezeList(parameters); + base.FreezeInternal(); + } + + public DefaultProperty(ITypeDefinition declaringTypeDefinition, string name) + : base(declaringTypeDefinition, name, EntityType.Property) + { + } + + public bool IsIndexer { + get { return flags[FlagIsIndexer]; } + set { + CheckBeforeMutation(); + flags[FlagIsIndexer] = value; + } + } + + public IList Parameters { + get { + if (parameters == null) + parameters = new List(); + return parameters; + } + } + + public bool CanGet { + get { return flags[FlagCanGet]; } + set { + CheckBeforeMutation(); + flags[FlagCanGet] = value; + } + } + + public bool CanSet { + get { return flags[FlagCanSet]; } + set { + CheckBeforeMutation(); + flags[FlagCanSet] = value; + } + } + + public Accessibility GetterAccessibility { + get { return getterAccessibility; } + set { + CheckBeforeMutation(); + getterAccessibility = value; + } + } + + public Accessibility SetterAccessibility { + get { return setterAccessibility; } + set { + CheckBeforeMutation(); + setterAccessibility = value; + } + } + } +}