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 @@ -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<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.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 @@ @@ -167,9 +167,10 @@
<Compile Include="TypeSystem\Implementation\DefaultExplicitInterfaceImplementation.cs" />
<Compile Include="TypeSystem\Implementation\DefaultMethod.cs" />
<Compile Include="TypeSystem\Implementation\DefaultParameter.cs" />
<Compile Include="TypeSystem\Implementation\DefaultProperty.cs" />
<Compile Include="TypeSystem\Implementation\DefaultTypeParameter.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\ProxyTypeResolveContext.cs" />
<Compile Include="TypeSystem\Implementation\DefaultTypeDefinition.cs" />

185
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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<CecilTypeDefinition> types = new List<CecilTypeDefinition>();
foreach (ModuleDefinition module in assemblyDefinition.Modules) {
foreach (TypeDefinition td in module.Types) {
@ -223,7 +223,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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 @@ -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<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;
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<IConstantValue>.Instance;
}
try {
if (ca.HasFields || ca.HasProperties) {
var namedArgs = new List<KeyValuePair<string, IConstantValue>>();
foreach (var arg in ca.Fields) {
namedArgs.Add(new KeyValuePair<string, IConstantValue>(arg.Name, loader.ReadConstantValue(arg.Argument)));
}
foreach (var arg in ca.Properties) {
namedArgs.Add(new KeyValuePair<string, IConstantValue>(arg.Name, loader.ReadConstantValue(arg.Argument)));
}
this.namedArguments = namedArgs.AsReadOnly();
} else {
this.namedArguments = EmptyList<KeyValuePair<string, IConstantValue>>.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<string, IConstantValue>(arg.Name, ReadConstantValue(arg.Argument)));
}
foreach (var arg in attribute.Properties) {
a.NamedArguments.Add(new KeyValuePair<string, IConstantValue>(arg.Name, ReadConstantValue(arg.Argument)));
}
} catch (InvalidOperationException) {
this.namedArguments = EmptyList<KeyValuePair<string, IConstantValue>>.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<IConstantValue> PositionalArguments {
get { return positionalArguments; }
}
public IList<KeyValuePair<string, IConstantValue>> NamedArguments {
get { return namedArguments; }
}
return a;
}
#endregion
@ -555,6 +520,29 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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
}
}

10
ICSharpCode.NRefactory/TypeSystem/IProperty.cs

@ -10,8 +10,14 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -10,8 +10,14 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary>
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; }
}

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

@ -22,6 +22,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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;

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

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

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

@ -13,7 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -13,7 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public sealed class DefaultAttribute : AbstractFreezable, IAttribute
{
DomRegion region;
ITypeReference attributeType = SharedTypes.UnknownType;
ITypeReference attributeType;
IList<IConstantValue> positionalArguments;
IList<KeyValuePair<string, IConstantValue>> namedArguments;
@ -34,6 +34,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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 {

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

@ -0,0 +1,79 @@ @@ -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