Browse Source

Implemented reading properties from Cecil.

newNRvisualizers
Daniel Grunwald 16 years ago
parent
commit
8c14d6ffe4
  1. 13
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  2. 3
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  3. 185
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  4. 10
      ICSharpCode.NRefactory/TypeSystem/IProperty.cs
  5. 1
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs
  6. 6
      ICSharpCode.NRefactory/TypeSystem/Implementation/AggregateTypeResolveContext.cs
  7. 9
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs
  8. 79
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultProperty.cs

13
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -73,22 +73,23 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void AssemblyAttribute() public void AssemblyAttribute()
{ {
ITypeResolveContext ctx = MultiTypeResolveContext.Combine(testCasePC, CecilLoaderTests.Mscorlib); ITypeResolveContext ctx = AggregateTypeResolveContext.Combine(testCasePC, CecilLoaderTests.Mscorlib);
var attributes = testCasePC.AssemblyAttributes; 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); Assert.AreEqual(3, typeTest.PositionalArguments.Count);
// first argument is (int)42 // 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<>) // 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.IsFalse(rt is ConstructedType); // rt must not be constructed - it's just an unbound type
Assert.AreEqual("System.Action", rt.FullName); Assert.AreEqual("System.Action", rt.FullName);
Assert.AreEqual(1, rt.TypeParameterCount); Assert.AreEqual(1, rt.TypeParameterCount);
// third argument is typeof(IDictionary<string, IList<TestAttribute>>) // third argument is typeof(IDictionary<string, IList<TestAttribute>>)
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.Collections.Generic.IDictionary", crt.FullName);
Assert.AreEqual("System.String", crt.TypeArguments[0].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);
} }
} }
} }

3
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -167,9 +167,10 @@
<Compile Include="TypeSystem\Implementation\DefaultExplicitInterfaceImplementation.cs" /> <Compile Include="TypeSystem\Implementation\DefaultExplicitInterfaceImplementation.cs" />
<Compile Include="TypeSystem\Implementation\DefaultMethod.cs" /> <Compile Include="TypeSystem\Implementation\DefaultMethod.cs" />
<Compile Include="TypeSystem\Implementation\DefaultParameter.cs" /> <Compile Include="TypeSystem\Implementation\DefaultParameter.cs" />
<Compile Include="TypeSystem\Implementation\DefaultProperty.cs" />
<Compile Include="TypeSystem\Implementation\DefaultTypeParameter.cs" /> <Compile Include="TypeSystem\Implementation\DefaultTypeParameter.cs" />
<Compile Include="TypeSystem\Implementation\GetClassTypeReference.cs" /> <Compile Include="TypeSystem\Implementation\GetClassTypeReference.cs" />
<Compile Include="TypeSystem\Implementation\MultiTypeResolveContext.cs" /> <Compile Include="TypeSystem\Implementation\AggregateTypeResolveContext.cs" />
<Compile Include="TypeSystem\Implementation\NestedTypeReference.cs" /> <Compile Include="TypeSystem\Implementation\NestedTypeReference.cs" />
<Compile Include="TypeSystem\Implementation\ProxyTypeResolveContext.cs" /> <Compile Include="TypeSystem\Implementation\ProxyTypeResolveContext.cs" />
<Compile Include="TypeSystem\Implementation\DefaultTypeDefinition.cs" /> <Compile Include="TypeSystem\Implementation\DefaultTypeDefinition.cs" />

185
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
TypeStorage typeStorage = new TypeStorage(); TypeStorage typeStorage = new TypeStorage();
CecilProjectContent pc = new CecilProjectContent(typeStorage, assemblyDefinition.Name.FullName, assemblyAttributes.AsReadOnly()); 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<CecilTypeDefinition> types = new List<CecilTypeDefinition>(); List<CecilTypeDefinition> types = new List<CecilTypeDefinition>();
foreach (ModuleDefinition module in assemblyDefinition.Modules) { foreach (ModuleDefinition module in assemblyDefinition.Modules) {
foreach (TypeDefinition td in module.Types) { foreach (TypeDefinition td in module.Types) {
@ -223,7 +223,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
} else { } else {
string name = type.FullName; string name = type.FullName;
if (name == null) 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) { if (name.IndexOf('/') > 0) {
string[] nameparts = name.Split('/'); 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) if (attribute == null)
throw new ArgumentNullException("cecilAttribute"); throw new ArgumentNullException("attribute");
return new CecilAttribute(cecilAttribute, this); DefaultAttribute a = new DefaultAttribute(ReadTypeReference(attribute.AttributeType));
} try {
if (attribute.HasConstructorArguments) {
sealed class CecilAttribute : Immutable, IAttribute foreach (var arg in attribute.ConstructorArguments) {
{ a.PositionalArguments.Add(ReadConstantValue(arg));
readonly ITypeReference attributeType;
readonly IList<IConstantValue> positionalArguments;
readonly IList<KeyValuePair<string, IConstantValue>> namedArguments;
public CecilAttribute(CustomAttribute ca, CecilLoader loader)
{
this.attributeType = loader.ReadTypeReference(ca.AttributeType);
try {
if (ca.HasConstructorArguments) {
var posArgs = new List<IConstantValue>();
foreach (var arg in ca.ConstructorArguments) {
posArgs.Add(loader.ReadConstantValue(arg));
}
this.positionalArguments = posArgs.AsReadOnly();
} else {
this.positionalArguments = EmptyList<IConstantValue>.Instance;
} }
} catch (InvalidOperationException) {
this.positionalArguments = EmptyList<IConstantValue>.Instance;
} }
try { } catch (InvalidOperationException) {
if (ca.HasFields || ca.HasProperties) { // occurs when Cecil can't decode an argument
var namedArgs = new List<KeyValuePair<string, IConstantValue>>(); }
foreach (var arg in ca.Fields) { try {
namedArgs.Add(new KeyValuePair<string, IConstantValue>(arg.Name, loader.ReadConstantValue(arg.Argument))); if (attribute.HasFields || attribute.HasProperties) {
} foreach (var arg in attribute.Fields) {
foreach (var arg in ca.Properties) { a.NamedArguments.Add(new KeyValuePair<string, IConstantValue>(arg.Name, ReadConstantValue(arg.Argument)));
namedArgs.Add(new KeyValuePair<string, IConstantValue>(arg.Name, loader.ReadConstantValue(arg.Argument))); }
} foreach (var arg in attribute.Properties) {
this.namedArguments = namedArgs.AsReadOnly(); a.NamedArguments.Add(new KeyValuePair<string, IConstantValue>(arg.Name, ReadConstantValue(arg.Argument)));
} else {
this.namedArguments = EmptyList<KeyValuePair<string, IConstantValue>>.Instance;
} }
} catch (InvalidOperationException) {
this.namedArguments = EmptyList<KeyValuePair<string, IConstantValue>>.Instance;
} }
} catch (InvalidOperationException) {
// occurs when Cecil can't decode an argument
} }
return a;
public DomRegion Region {
get { return DomRegion.Empty; }
}
public ITypeReference AttributeType {
get { return attributeType; }
}
public IList<IConstantValue> PositionalArguments {
get { return positionalArguments; }
}
public IList<KeyValuePair<string, IConstantValue>> NamedArguments {
get { return namedArguments; }
}
} }
#endregion #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 #endregion
@ -584,13 +572,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
AddAttributes(method, m.Attributes); AddAttributes(method, m.Attributes);
} }
if (parentType.ClassType == ClassType.Interface) { TranslateModifiers(method, m);
// 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);
}
if (method.HasParameters) { if (method.HasParameters) {
foreach (ParameterDefinition p in method.Parameters) { foreach (ParameterDefinition p in method.Parameters) {
@ -620,11 +602,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
|| att == MethodAttributes.FamORAssem; || att == MethodAttributes.FamORAssem;
} }
Accessibility GetAccessibility(MethodAttributes attr) static Accessibility GetAccessibility(MethodAttributes attr)
{ {
switch (attr & MethodAttributes.MemberAccessMask) { switch (attr & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Private: case MethodAttributes.Public:
return Accessibility.Private; return Accessibility.Public;
case MethodAttributes.FamANDAssem: case MethodAttributes.FamANDAssem:
return Accessibility.ProtectedAndInternal; return Accessibility.ProtectedAndInternal;
case MethodAttributes.Assem: case MethodAttributes.Assem:
@ -634,19 +616,25 @@ namespace ICSharpCode.NRefactory.TypeSystem
case MethodAttributes.FamORAssem: case MethodAttributes.FamORAssem:
return Accessibility.ProtectedOrInternal; return Accessibility.ProtectedOrInternal;
default: 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 (m.DeclaringTypeDefinition.ClassType == ClassType.Interface) {
if (method.IsAbstract) // interface members don't have modifiers, but we want to handle them as "public abstract"
member.IsAbstract = true; m.Accessibility = Accessibility.Public;
else if (method.IsFinal) m.IsAbstract = true;
member.IsSealed = true; } else {
else if (method.IsVirtual) m.Accessibility = GetAccessibility(method.Attributes);
member.IsVirtual = true; if (method.IsAbstract)
m.IsAbstract = true;
else if (method.IsFinal)
m.IsSealed = true;
else if (method.IsVirtual)
m.IsVirtual = true;
}
} }
#endregion #endregion
@ -695,6 +683,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
|| att == FieldAttributes.Family || att == FieldAttributes.Family
|| att == FieldAttributes.FamORAssem; || att == FieldAttributes.FamORAssem;
} }
public IField ReadField(FieldDefinition field, ITypeDefinition parentType)
{
throw new NotImplementedException();
}
#endregion #endregion
void AddExplicitInterfaceImplementations(MethodDefinition method, AbstractMember targetMember) void AddExplicitInterfaceImplementations(MethodDefinition method, AbstractMember targetMember)
@ -727,5 +720,43 @@ namespace ICSharpCode.NRefactory.TypeSystem
} }
} }
#endregion #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
} }
} }

10
ICSharpCode.NRefactory/TypeSystem/IProperty.cs

@ -10,8 +10,14 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary> /// </summary>
public interface IProperty : IParameterizedMember public interface IProperty : IParameterizedMember
{ {
IMethod GetMethod { get; } bool CanGet { get; }
IMethod SetMethod { get; } bool CanSet { get; }
Accessibility GetterAccessibility { get; }
Accessibility SetterAccessibility { get; }
//IMethod GetMethod { get; }
//IMethod SetMethod { get; }
bool IsIndexer { get; } bool IsIndexer { get; }
} }

1
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs

@ -22,6 +22,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
// 1 byte per enum + 2 bytes for flags // 1 byte per enum + 2 bytes for flags
Accessibility accessibility; Accessibility accessibility;
EntityType entityType; EntityType entityType;
protected BitVector16 flags; protected BitVector16 flags;
const ushort FlagSealed = 0x0001; const ushort FlagSealed = 0x0001;
const ushort FlagAbstract = 0x0002; const ushort FlagAbstract = 0x0002;

6
ICSharpCode.NRefactory/TypeSystem/Implementation/MultiTypeResolveContext.cs → ICSharpCode.NRefactory/TypeSystem/Implementation/AggregateTypeResolveContext.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary> /// <summary>
/// Represents multiple type resolve contexts. /// Represents multiple type resolve contexts.
/// </summary> /// </summary>
public class MultiTypeResolveContext : ITypeResolveContext public class AggregateTypeResolveContext : ITypeResolveContext
{ {
/// <summary> /// <summary>
/// Creates a <see cref="MultiTypeResolveContext"/> that combines the given resolve contexts. /// Creates a <see cref="MultiTypeResolveContext"/> that combines the given resolve contexts.
@ -23,7 +23,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return b; return b;
if (b == null) if (b == null)
return a; return a;
return new MultiTypeResolveContext(new [] { a, b }); return new AggregateTypeResolveContext(new [] { a, b });
} }
readonly ITypeResolveContext[] contexts; readonly ITypeResolveContext[] contexts;
@ -31,7 +31,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary> /// <summary>
/// Creates a new <see cref="MultiTypeResolveContext"/> /// Creates a new <see cref="MultiTypeResolveContext"/>
/// </summary> /// </summary>
public MultiTypeResolveContext(IEnumerable<ITypeResolveContext> contexts) public AggregateTypeResolveContext(IEnumerable<ITypeResolveContext> contexts)
{ {
if (contexts == null) if (contexts == null)
throw new ArgumentNullException("contexts"); throw new ArgumentNullException("contexts");

9
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAttribute.cs

@ -13,7 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public sealed class DefaultAttribute : AbstractFreezable, IAttribute public sealed class DefaultAttribute : AbstractFreezable, IAttribute
{ {
DomRegion region; DomRegion region;
ITypeReference attributeType = SharedTypes.UnknownType; ITypeReference attributeType;
IList<IConstantValue> positionalArguments; IList<IConstantValue> positionalArguments;
IList<KeyValuePair<string, IConstantValue>> namedArguments; IList<KeyValuePair<string, IConstantValue>> namedArguments;
@ -34,6 +34,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
base.FreezeInternal(); base.FreezeInternal();
} }
public DefaultAttribute(ITypeReference attributeType)
{
if (attributeType == null)
throw new ArgumentNullException("attributeType");
this.attributeType = attributeType;
}
public DomRegion Region { public DomRegion Region {
get { return region; } get { return region; }
set { set {

79
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultProperty.cs

@ -0,0 +1,79 @@

using System;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
/// <summary>
/// Default implementation of <see cref="IProperty"/>.
/// </summary>
public class DefaultProperty : AbstractMember, IProperty
{
Accessibility getterAccessibility;
Accessibility setterAccessibility;
IList<IParameter> 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<IParameter> Parameters {
get {
if (parameters == null)
parameters = new List<IParameter>();
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;
}
}
}
}
Loading…
Cancel
Save