From cd6059fa22e8696e1369500a03d26258cd4476f4 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 19 Mar 2010 13:23:19 +0000 Subject: [PATCH] Implemented support for 'dynamic' type in SharpDevelop.Dom. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5625 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../AbstractDesignerGenerator.cs | 2 +- src/Main/Base/Test/ReflectionLayerTests.cs | 38 +++++++- .../ICSharpCode.SharpDevelop.Dom.csproj | 1 + .../Project/Src/CecilReader.cs | 70 +++++++++++---- .../Src/Implementations/DynamicReturnType.cs | 55 ++++++++++++ .../Src/NRefactoryResolver/TypeVisitor.cs | 3 + .../Src/ReflectionLayer/DomPersistence.cs | 7 +- .../Src/ReflectionLayer/ReflectionClass.cs | 12 +-- .../Src/ReflectionLayer/ReflectionEvent.cs | 2 +- .../Src/ReflectionLayer/ReflectionField.cs | 2 +- .../Src/ReflectionLayer/ReflectionMethod.cs | 3 +- .../ReflectionLayer/ReflectionParameter.cs | 2 +- .../Src/ReflectionLayer/ReflectionProperty.cs | 2 +- .../ReflectionLayer/ReflectionReturnType.cs | 89 ++++++++++++++----- 14 files changed, 230 insertions(+), 58 deletions(-) create mode 100644 src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DynamicReturnType.cs diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs index 3493cff65b..25bd49d093 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs @@ -524,7 +524,7 @@ namespace ICSharpCode.FormsDesigner { MethodInfo mInfo = eventType.GetMethod("Invoke"); DefaultMethod m = new DefaultMethod(declaringType, methodName); - m.ReturnType = ReflectionLayer.ReflectionReturnType.Create(m, mInfo.ReturnType, false); + m.ReturnType = ReflectionLayer.ReflectionReturnType.Create(m, mInfo.ReturnType); foreach (ParameterInfo pInfo in mInfo.GetParameters()) { m.Parameters.Add(new ReflectionLayer.ReflectionParameter(pInfo, m)); } diff --git a/src/Main/Base/Test/ReflectionLayerTests.cs b/src/Main/Base/Test/ReflectionLayerTests.cs index 4f224d87a7..191c633279 100644 --- a/src/Main/Base/Test/ReflectionLayerTests.cs +++ b/src/Main/Base/Test/ReflectionLayerTests.cs @@ -7,12 +7,13 @@ using System; using System.Collections.Generic; -using System.Linq; using System.IO; +using System.Linq; using System.Reflection; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.CSharp; using ICSharpCode.SharpDevelop.Dom.ReflectionLayer; using NUnit.Framework; @@ -37,6 +38,7 @@ namespace ICSharpCode.SharpDevelop.Tests protected override IClass GetClass(Type type) { ICompilationUnit cu = new ReflectionProjectContent("TestName", "testlocation", new DomAssemblyName[0], AssemblyParserService.DefaultProjectContentRegistry).AssemblyCompilationUnit; + ((ReflectionProjectContent)cu.ProjectContent).AddReferencedContent(mscorlib); IClass c = new ReflectionClass(cu, type, type.FullName, null); cu.ProjectContent.AddClassToNamespaceList(c); return c; @@ -73,7 +75,9 @@ namespace ICSharpCode.SharpDevelop.Tests DomPersistence.WriteProjectContent((ReflectionProjectContent)c.ProjectContent, memory); memory.Position = 0; - return DomPersistence.LoadProjectContent(memory, AssemblyParserService.DefaultProjectContentRegistry).Classes.Single(); + ReflectionProjectContent loadedPC = DomPersistence.LoadProjectContent(memory, AssemblyParserService.DefaultProjectContentRegistry); + loadedPC.AddReferencedContent(mscorlib); + return loadedPC.Classes.Single(); } protected override IEnumerable GetAssemblyAttributes(Assembly assembly) @@ -99,8 +103,9 @@ namespace ICSharpCode.SharpDevelop.Tests IProjectContent LoadAssembly(Assembly assembly) { - IProjectContent pc = CecilReader.LoadAssembly(assembly.Location, AssemblyParserService.DefaultProjectContentRegistry); + var pc = CecilReader.LoadAssembly(assembly.Location, AssemblyParserService.DefaultProjectContentRegistry); Assert.IsNotNull(pc); + pc.AddReferencedContent(mscorlib); return pc; } @@ -330,7 +335,13 @@ namespace ICSharpCode.SharpDevelop.Tests public void GetIndex(T element) where T: IEquatable {} public int Property { get; protected set; } - public int ReadOnlyPropertyWithPrivateSetter { get; private set; } + public dynamic ReadOnlyPropertyWithPrivateSetter { get; private set; } + + public List DynamicGenerics1(Action param) { return null; } + public void DynamicGenerics2(Action param) { } + public void DynamicGenerics3(Action param) { } + public void DynamicGenerics4(Action param) { } + public void DynamicGenerics5(Action param) { } } protected abstract IClass GetClass(Type type); @@ -398,6 +409,25 @@ namespace ICSharpCode.SharpDevelop.Tests Assert.IsFalse(p.CanSet); } + [Test] + public void DynamicType() + { + IProperty p = testClass.Properties.Single(pr => pr.Name == "ReadOnlyPropertyWithPrivateSetter"); + Assert.IsInstanceOf(typeof(DynamicReturnType), p.ReturnType); + } + + [Test] + public void DynamicTypeInGenerics() + { + CSharpAmbience a = new CSharpAmbience(); + a.ConversionFlags = ConversionFlags.ShowReturnType | ConversionFlags.ShowParameterList; + Assert.AreEqual("List DynamicGenerics1(Action)", a.Convert(testClass.Methods.Single(me => me.Name == "DynamicGenerics1"))); + Assert.AreEqual("void DynamicGenerics2(Action)", a.Convert(testClass.Methods.Single(me => me.Name == "DynamicGenerics2"))); + Assert.AreEqual("void DynamicGenerics3(Action)", a.Convert(testClass.Methods.Single(me => me.Name == "DynamicGenerics3"))); + Assert.AreEqual("void DynamicGenerics4(Action)", a.Convert(testClass.Methods.Single(me => me.Name == "DynamicGenerics4"))); + Assert.AreEqual("void DynamicGenerics5(Action)", a.Convert(testClass.Methods.Single(me => me.Name == "DynamicGenerics5"))); + } + [Test] public void AssemblyAttribute() { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj index 5494e89e23..4874dfe242 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj @@ -92,6 +92,7 @@ + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs index 01e54df0e3..87cdd51882 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs @@ -34,9 +34,11 @@ namespace ICSharpCode.SharpDevelop.Dom return new CecilProjectContent(asm.Name.FullName, fileName, referencedAssemblies.ToArray(), asm, registry); } - static void AddAttributes(IProjectContent pc, IList list, CustomAttributeCollection attributes) + static void AddAttributes(IProjectContent pc, IList list, ICustomAttributeProvider attributeProvider) { - foreach (CustomAttribute att in attributes) { + if (!attributeProvider.HasCustomAttributes) + return; + foreach (CustomAttribute att in attributeProvider.CustomAttributes) { DefaultAttribute a = new DefaultAttribute(CreateType(pc, null, att.Constructor.DeclaringType)); // Currently Cecil returns string instead of TypeReference for typeof() arguments to attributes var parameters = att.Constructor.Parameters; @@ -74,7 +76,13 @@ namespace ICSharpCode.SharpDevelop.Dom /// /// Create a SharpDevelop return type from a Cecil type reference. /// - internal static IReturnType CreateType(IProjectContent pc, IEntity member, TypeReference type) + internal static IReturnType CreateType(IProjectContent pc, IEntity member, TypeReference type, ICustomAttributeProvider attributeProvider = null) + { + int typeIndex = 0; + return CreateType(pc, member, type, attributeProvider, ref typeIndex); + } + + static IReturnType CreateType(IProjectContent pc, IEntity member, TypeReference type, ICustomAttributeProvider attributeProvider, ref int typeIndex) { while (type is ModType) { type = (type as ModType).ElementType; @@ -85,18 +93,22 @@ namespace ICSharpCode.SharpDevelop.Dom } if (type is ReferenceType) { // TODO: Use ByRefRefReturnType - return CreateType(pc, member, (type as ReferenceType).ElementType); + return CreateType(pc, member, (type as ReferenceType).ElementType, attributeProvider, ref typeIndex); } else if (type is PointerType) { - return new PointerReturnType(CreateType(pc, member, (type as PointerType).ElementType)); + typeIndex++; + return new PointerReturnType(CreateType(pc, member, (type as PointerType).ElementType, attributeProvider, ref typeIndex)); } else if (type is ArrayType) { - return new ArrayReturnType(pc, CreateType(pc, member, (type as ArrayType).ElementType), (type as ArrayType).Rank); + typeIndex++; + return new ArrayReturnType(pc, CreateType(pc, member, (type as ArrayType).ElementType, attributeProvider, ref typeIndex), (type as ArrayType).Rank); } else if (type is GenericInstanceType) { GenericInstanceType gType = (GenericInstanceType)type; + IReturnType baseType = CreateType(pc, member, gType.ElementType, attributeProvider, ref typeIndex); IReturnType[] para = new IReturnType[gType.GenericArguments.Count]; for (int i = 0; i < para.Length; ++i) { - para[i] = CreateType(pc, member, gType.GenericArguments[i]); + typeIndex++; + para[i] = CreateType(pc, member, gType.GenericArguments[i], attributeProvider, ref typeIndex); } - return new ConstructedReturnType(CreateType(pc, member, gType.ElementType), para); + return new ConstructedReturnType(baseType, para); } else if (type is GenericParameter) { GenericParameter typeGP = type as GenericParameter; if (typeGP.Owner is MethodDefinition) { @@ -137,6 +149,9 @@ namespace ICSharpCode.SharpDevelop.Dom name = ReflectionClass.SplitTypeParameterCountFromReflectionName(name, out typeParameterCount); } + if (typeParameterCount == 0 && name == "System.Object" && HasDynamicAttribute(attributeProvider, typeIndex)) + return new DynamicReturnType(pc); + IClass c = pc.GetClass(name, typeParameterCount); if (c != null) { return c.DefaultReturnType; @@ -148,6 +163,23 @@ namespace ICSharpCode.SharpDevelop.Dom } } + static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) + { + if (attributeProvider == null || attributeProvider.HasCustomAttributes == false) + return false; + foreach (CustomAttribute a in attributeProvider.CustomAttributes) { + if (a.Constructor.DeclaringType.FullName == "System.Runtime.CompilerServices.DynamicAttribute") { + if (a.ConstructorParameters.Count == 1) { + object[] values = a.ConstructorParameters[0] as object[]; + if (values != null && typeIndex < values.Length && values[typeIndex] is bool) + return (bool)values[typeIndex]; + } + return true; + } + } + return false; + } + private sealed class CecilProjectContent : ReflectionProjectContent { public CecilProjectContent(string fullName, string fileName, DomAssemblyName[] referencedAssemblies, @@ -157,7 +189,7 @@ namespace ICSharpCode.SharpDevelop.Dom foreach (ModuleDefinition module in assembly.Modules) { AddTypes(module.Types); } - AddAttributes(this, this.AssemblyCompilationUnit.Attributes, assembly.CustomAttributes); + AddAttributes(this, this.AssemblyCompilationUnit.Attributes, assembly); InitializeSpecialClasses(); this.AssemblyCompilationUnit.Freeze(); } @@ -203,7 +235,7 @@ namespace ICSharpCode.SharpDevelop.Dom { this.FullyQualifiedName = fullName; - AddAttributes(compilationUnit.ProjectContent, this.Attributes, td.CustomAttributes); + AddAttributes(compilationUnit.ProjectContent, this.Attributes, td); // set classtype if (td.IsInterface) { @@ -297,8 +329,8 @@ namespace ICSharpCode.SharpDevelop.Dom if (IsVisible(field.Attributes) && !field.IsSpecialName) { DefaultField f = new DefaultField(this, field.Name); f.Modifiers = TranslateModifiers(field); - f.ReturnType = CreateType(this.ProjectContent, this, field.FieldType); - AddAttributes(CompilationUnit.ProjectContent, f.Attributes, field.CustomAttributes); + f.ReturnType = CreateType(this.ProjectContent, this, field.FieldType, field); + AddAttributes(CompilationUnit.ProjectContent, f.Attributes, field); Fields.Add(f); } } @@ -315,8 +347,8 @@ namespace ICSharpCode.SharpDevelop.Dom } else { e.Modifiers = TranslateModifiers(eventDef); } - e.ReturnType = CreateType(this.ProjectContent, this, eventDef.EventType); - AddAttributes(CompilationUnit.ProjectContent, e.Attributes, eventDef.CustomAttributes); + e.ReturnType = CreateType(this.ProjectContent, this, eventDef.EventType, eventDef); + AddAttributes(CompilationUnit.ProjectContent, e.Attributes, eventDef); Events.Add(e); } } @@ -343,7 +375,7 @@ namespace ICSharpCode.SharpDevelop.Dom } else { p.Modifiers = TranslateModifiers(property); } - p.ReturnType = CreateType(this.ProjectContent, this, property.PropertyType); + p.ReturnType = CreateType(this.ProjectContent, this, property.PropertyType, property); p.CanGet = property.GetMethod != null && IsVisible(property.GetMethod.Attributes); p.CanSet = property.SetMethod != null && IsVisible(property.SetMethod.Attributes); if (p.CanGet) @@ -354,7 +386,7 @@ namespace ICSharpCode.SharpDevelop.Dom p.IsIndexer = true; } AddParameters(p, property.Parameters); - AddAttributes(CompilationUnit.ProjectContent, p.Attributes, property.CustomAttributes); + AddAttributes(CompilationUnit.ProjectContent, p.Attributes, property); Properties.Add(p); } } @@ -386,8 +418,8 @@ namespace ICSharpCode.SharpDevelop.Dom if (method.IsConstructor) m.ReturnType = this.DefaultReturnType; else - m.ReturnType = CreateType(this.ProjectContent, m, method.ReturnType.ReturnType); - AddAttributes(CompilationUnit.ProjectContent, m.Attributes, method.CustomAttributes); + m.ReturnType = CreateType(this.ProjectContent, m, method.ReturnType.ReturnType, method.ReturnType); + AddAttributes(CompilationUnit.ProjectContent, m.Attributes, method); if (this.ClassType == ClassType.Interface) { m.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract; } else { @@ -416,7 +448,7 @@ namespace ICSharpCode.SharpDevelop.Dom void AddParameters(IMethodOrProperty target, ParameterDefinitionCollection plist) { foreach (ParameterDefinition par in plist) { - IReturnType pReturnType = CreateType(this.ProjectContent, target, par.ParameterType); + IReturnType pReturnType = CreateType(this.ProjectContent, target, par.ParameterType, par); DefaultParameter p = new DefaultParameter(par.Name, pReturnType, DomRegion.Empty); if (par.ParameterType is ReferenceType) { if ((par.Attributes & ParameterAttributes.Out) == ParameterAttributes.Out) { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DynamicReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DynamicReturnType.cs new file mode 100644 index 0000000000..9eda44c671 --- /dev/null +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DynamicReturnType.cs @@ -0,0 +1,55 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.SharpDevelop.Dom +{ + public class DynamicReturnType : AbstractReturnType + { + readonly IProjectContent pc; + + public DynamicReturnType(IProjectContent pc) + { + if (pc == null) + throw new ArgumentNullException("pc"); + this.pc = pc; + } + + public override IClass GetUnderlyingClass() + { + return null; + } + + public override List GetMethods() + { + return new List(); + } + public override List GetProperties() + { + return new List(); + } + public override List GetFields() + { + return new List(); + } + public override List GetEvents() + { + return new List(); + } + + public override string Name { + get { return "dynamic"; } + } + + public override string FullyQualifiedName { + get { return "dynamic"; } + set { throw new NotSupportedException(); } + } + } +} diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs index 516c9f30dd..1bd242bd16 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/TypeVisitor.cs @@ -47,6 +47,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver reference = ((InnerClassTypeReference)reference).CombineToNormalTypeReference(); } + if (reference.Type == "dynamic") + return new DynamicReturnType(projectContent); + bool useLazyReturnType = (options & ReturnTypeOptions.Lazy) == ReturnTypeOptions.Lazy; bool isBaseTypeReference = (options & ReturnTypeOptions.BaseTypeReference) == ReturnTypeOptions.BaseTypeReference; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs index 40bed41c83..ce428f7f51 100755 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs @@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Dom { public const long FileMagic = 0x11635233ED2F428C; public const long IndexFileMagic = 0x11635233ED2F427D; - public const short FileVersion = 25; + public const short FileVersion = 26; ProjectContentRegistry registry; string cacheDirectory; @@ -592,6 +592,7 @@ namespace ICSharpCode.SharpDevelop.Dom const int NullRTReferenceCode = -5; const int VoidRTCode = -6; const int PointerRTCode = -7; + const int DynamicRTCode = -8; void WriteType(IReturnType rt) { @@ -603,6 +604,8 @@ namespace ICSharpCode.SharpDevelop.Dom string name = rt.FullyQualifiedName; if (name == "System.Void") { writer.Write(VoidRTCode); + } else if (name == "dynamic") { + writer.Write(DynamicRTCode); } else { writer.Write(classIndices[new ClassNameTypeCountPair(rt)]); } @@ -660,6 +663,8 @@ namespace ICSharpCode.SharpDevelop.Dom return new VoidReturnType(pc); case PointerRTCode: return new PointerReturnType(ReadType()); + case DynamicRTCode: + return new DynamicReturnType(pc); default: return types[index]; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs index dff9d6ba6b..19e4707414 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs @@ -70,7 +70,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer internal static void AddAttributes(IProjectContent pc, IList list, IList attributes) { foreach (CustomAttributeData att in attributes) { - DefaultAttribute a = new DefaultAttribute(ReflectionReturnType.Create(pc, null, att.Constructor.DeclaringType, false)); + DefaultAttribute a = new DefaultAttribute(ReflectionReturnType.Create(pc, att.Constructor.DeclaringType)); foreach (CustomAttributeTypedArgument arg in att.ConstructorArguments) { a.PositionalArguments.Add(ReplaceTypeByIReturnType(pc, arg.Value)); } @@ -84,7 +84,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer static object ReplaceTypeByIReturnType(IProjectContent pc, object val) { if (val is Type) { - return ReflectionReturnType.Create(pc, null, (Type)val, false, false); + return ReflectionReturnType.Create(pc, (Type)val, forceGenericType: false); } else { return val; } @@ -208,11 +208,11 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer // set base classes if (type.BaseType != null) { // it's null for System.Object ONLY !!! - BaseTypes.Add(ReflectionReturnType.Create(this, type.BaseType, false)); + BaseTypes.Add(ReflectionReturnType.Create(this, type.BaseType)); } foreach (Type iface in type.GetInterfaces()) { - BaseTypes.Add(ReflectionReturnType.Create(this, iface, false)); + BaseTypes.Add(ReflectionReturnType.Create(this, iface)); } InitMembers(type); @@ -222,9 +222,9 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer { foreach (Type constraint in type.GetGenericParameterConstraints()) { if (tp.Method != null) { - tp.Constraints.Add(ReflectionReturnType.Create(tp.Method, constraint, false)); + tp.Constraints.Add(ReflectionReturnType.Create(tp.Method, constraint)); } else { - tp.Constraints.Add(ReflectionReturnType.Create(tp.Class, constraint, false)); + tp.Constraints.Add(ReflectionReturnType.Create(tp.Class, constraint)); } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionEvent.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionEvent.cs index 496e1bf757..68fc6b9e37 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionEvent.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionEvent.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer { public ReflectionEvent(EventInfo eventInfo, IClass declaringType) : base(declaringType, eventInfo.Name) { - this.ReturnType = ReflectionReturnType.Create(this, eventInfo.EventHandlerType, false); + this.ReturnType = ReflectionReturnType.Create(this, eventInfo.EventHandlerType, attributeProvider: eventInfo); // get modifiers MethodInfo methodBase = null; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionField.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionField.cs index 694a8f6a08..034f806dd4 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionField.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionField.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer { public ReflectionField(FieldInfo fieldInfo, IClass declaringType) : base(declaringType, fieldInfo.Name) { - this.ReturnType = ReflectionReturnType.Create(this, fieldInfo.FieldType, false); + this.ReturnType = ReflectionReturnType.Create(this, fieldInfo.FieldType, attributeProvider: fieldInfo); ModifierEnum modifiers = ModifierEnum.None; if (fieldInfo.IsInitOnly) { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionMethod.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionMethod.cs index 2e748e0101..95b3864f65 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionMethod.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionMethod.cs @@ -30,7 +30,8 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer : base(declaringType, methodBase is ConstructorInfo ? "#ctor" : methodBase.Name) { if (methodBase is MethodInfo) { - this.ReturnType = ReflectionReturnType.Create(this, ((MethodInfo)methodBase).ReturnType, false); + MethodInfo m = ((MethodInfo)methodBase); + this.ReturnType = ReflectionReturnType.Create(this, m.ReturnType, attributeProvider: m.ReturnTypeCustomAttributes); } else if (methodBase is ConstructorInfo) { this.ReturnType = DeclaringType.DefaultReturnType; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionParameter.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionParameter.cs index 724751bffd..9ba321472f 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionParameter.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionParameter.cs @@ -16,7 +16,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer { Type type = parameterInfo.ParameterType; - this.ReturnType = ReflectionReturnType.Create(member, type, false); + this.ReturnType = ReflectionReturnType.Create(member, type, attributeProvider: parameterInfo); if (type.IsByRef && parameterInfo.IsOut) { this.Modifiers = ParameterModifiers.Out; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionProperty.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionProperty.cs index 6f5a2fae6f..f58eaf1317 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionProperty.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionProperty.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer { public ReflectionProperty(PropertyInfo propertyInfo, IClass declaringType) : base(declaringType, propertyInfo.Name) { - this.ReturnType = ReflectionReturnType.Create(this, propertyInfo.PropertyType, false); + this.ReturnType = ReflectionReturnType.Create(this, propertyInfo.PropertyType, attributeProvider: propertyInfo); CanGet = propertyInfo.CanRead; CanSet = propertyInfo.CanWrite; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionReturnType.cs index ab00fef42a..4d950b4368 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionReturnType.cs @@ -7,6 +7,8 @@ using System; using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer @@ -90,47 +92,69 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer } #endregion - public static IReturnType Create(IClass @class, Type type, bool createLazyReturnType) - { - return Create(@class.ProjectContent, @class, type, createLazyReturnType); - } - - public static IReturnType Create(IMember member, Type type, bool createLazyReturnType) - { - return Create(member.DeclaringType.ProjectContent, member, type, createLazyReturnType); - } - - public static IReturnType Create(IProjectContent pc, IEntity member, Type type, bool createLazyReturnType) - { - return Create(pc, member, type, createLazyReturnType, true); - } - /// /// Creates a IReturnType from the reflection type. /// /// The project content used as context. - /// The member used as context (e.g. as GenericReturnType) + /// The member used as context (e.g. as GenericReturnType) /// The reflection return type that should be converted /// Set this parameter to false to create a direct return type /// (without GetClassReturnType indirection) where possible /// Set this parameter to false to allow unbound generic types /// The IReturnType - public static IReturnType Create(IProjectContent pc, IEntity member, Type type, bool createLazyReturnType, bool forceGenericType) + /// Attribute provider for lookup of [Dynamic] attribute + public static IReturnType Create(IProjectContent pc, Type type, + IEntity entity = null, + bool createLazyReturnType = false, + bool forceGenericType = true, + ICustomAttributeProvider attributeProvider = null) + { + if (pc == null) + throw new ArgumentNullException("pc"); + if (type == null) + throw new ArgumentNullException("type"); + int typeIndex = 0; + return Create(pc, type, entity, createLazyReturnType, attributeProvider, ref typeIndex, forceGenericType); + } + + public static IReturnType Create(IEntity entity, Type type, + bool createLazyReturnType = false, + bool forceGenericType = true, + ICustomAttributeProvider attributeProvider = null) + { + if (entity == null) + throw new ArgumentNullException("entity"); + if (type == null) + throw new ArgumentNullException("type"); + int typeIndex = 0; + return Create(entity.ProjectContent, type, entity, createLazyReturnType, attributeProvider, ref typeIndex, forceGenericType); + } + + static IReturnType Create(IProjectContent pc, Type type, + IEntity member, + bool createLazyReturnType, + ICustomAttributeProvider attributeProvider, + ref int typeIndex, + bool forceGenericType = true) { if (type.IsByRef) { // TODO: Use ByRefRefReturnType - return Create(pc, member, type.GetElementType(), createLazyReturnType); + return Create(pc, type.GetElementType(), member, createLazyReturnType, attributeProvider, ref typeIndex); } else if (type.IsPointer) { - return new PointerReturnType(Create(pc, member, type.GetElementType(), createLazyReturnType)); + typeIndex++; + return new PointerReturnType(Create(pc, type.GetElementType(), member, createLazyReturnType, attributeProvider, ref typeIndex)); } else if (type.IsArray) { - return new ArrayReturnType(pc, Create(pc, member, type.GetElementType(), createLazyReturnType), type.GetArrayRank()); + typeIndex++; + return new ArrayReturnType(pc, Create(pc, type.GetElementType(), member, createLazyReturnType, attributeProvider, ref typeIndex), type.GetArrayRank()); } else if (type.IsGenericType && (forceGenericType || !type.IsGenericTypeDefinition)) { + IReturnType baseType = Create(pc, type.GetGenericTypeDefinition(), member, createLazyReturnType, attributeProvider, ref typeIndex, forceGenericType: false); Type[] args = type.GetGenericArguments(); List para = new List(args.Length); for (int i = 0; i < args.Length; ++i) { - para.Add(Create(pc, member, args[i], createLazyReturnType)); + typeIndex++; + para.Add(Create(pc, args[i], member, createLazyReturnType, attributeProvider, ref typeIndex)); } - return new ConstructedReturnType(Create(pc, member, type.GetGenericTypeDefinition(), createLazyReturnType, false), para); + return new ConstructedReturnType(baseType, para); } else if (type.IsGenericParameter) { IClass c = (member is IClass) ? (IClass)member : (member is IMember) ? ((IMember)member).DeclaringType : null; if (c != null && type.GenericParameterPosition < c.TypeParameters.Count) { @@ -154,6 +178,10 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer throw new ApplicationException("type.FullName returned null. Type: " + type.ToString()); int typeParameterCount; name = ReflectionClass.ConvertReflectionNameToFullName(name, out typeParameterCount); + + if (typeParameterCount == 0 && name == "System.Object" && HasDynamicAttribute(attributeProvider, typeIndex)) + return new DynamicReturnType(pc); + if (!createLazyReturnType) { IClass c = pc.GetClass(name, typeParameterCount); if (c != null) @@ -164,5 +192,22 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer return new GetClassReturnType(pc, name, typeParameterCount); } } + + static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) + { + if (attributeProvider == null) + return false; + object[] attributes = attributeProvider.GetCustomAttributes(typeof(DynamicAttribute), false); + if (attributes.Length == 0) + return false; + DynamicAttribute attr = attributes[0] as DynamicAttribute; + if (attr != null) { + var transformFlags = attr.TransformFlags; + if (transformFlags != null && typeIndex < transformFlags.Count) + return transformFlags[typeIndex]; + return true; + } + return false; + } } }