From e0f3421c1da276a3275c29b3e127eb900862d376 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 14 Apr 2012 13:11:32 +0200 Subject: [PATCH] Add support for type forwarders. --- .../TypeSystem/CecilLoaderTests.cs | 11 ++++ .../Visitors/CSharpToVBConverterVisitor.cs | 15 +++++ .../TypeSystem/CecilLoader.cs | 41 ++++-------- .../DefaultUnresolvedAssembly.cs | 63 ++++++++++++++++--- .../Implementation/GetClassTypeReference.cs | 29 +++------ 5 files changed, 102 insertions(+), 57 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs index 9dc4d4a1bf..e2ac3972b6 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs @@ -297,5 +297,16 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.IsFalse(getDecoder.IsVirtual); Assert.IsTrue(getDecoder.IsOverride); } + + [Test] + public void FindRedirectedType() + { + var compilationWithSystemCore = new SimpleCompilation(systemCore.Value, mscorlib.Value); + + var typeRef = ReflectionHelper.ParseReflectionName("System.Func`2, System.Core"); + ITypeDefinition c = typeRef.Resolve(compilationWithSystemCore.TypeResolveContext).GetDefinition(); + Assert.IsNotNull(c, "System.Func<,> not found"); + Assert.AreEqual("mscorlib", c.ParentAssembly.AssemblyName); + } } } diff --git a/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs b/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs index 16fb84e70d..1725d7ec96 100644 --- a/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs +++ b/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs @@ -2220,5 +2220,20 @@ namespace ICSharpCode.NRefactory.VB.Visitors { throw new NotImplementedException(); } + + public AstNode VisitNewLine(CSharp.NewLineNode newLineNode, object data) + { + return null; + } + + public AstNode VisitWhitespace(CSharp.WhitespaceNode whitespaceNode, object data) + { + return null; + } + + public AstNode VisitText(CSharp.TextNode textNode, object data) + { + return null; + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index cd018fa9f1..aa2e4268fd 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -117,6 +117,18 @@ namespace ICSharpCode.NRefactory.TypeSystem currentAssembly.AssemblyAttributes.AddRange(assemblyAttributes); currentAssembly.ModuleAttributes.AddRange(assemblyAttributes); + // Register type forwarders: + foreach (ExportedType type in assemblyDefinition.MainModule.ExportedTypes) { + if (type.IsForwarder) { + int typeParameterCount; + string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); + var typeRef = new GetClassTypeReference(GetAssemblyReference(type.Scope), type.Namespace, name, typeParameterCount); + typeRef = this.InterningProvider.Intern(typeRef); + var key = new FullNameAndTypeParameterCount(type.Namespace, name, typeParameterCount); + currentAssembly.AddTypeForwarder(key, typeRef); + } + } + // Create and register all types: List cecilTypeDefs = new List(); List typeDefs = new List(); @@ -336,7 +348,6 @@ namespace ICSharpCode.NRefactory.TypeSystem #region Read Attributes #region Assembly Attributes - static readonly ITypeReference typeForwardedToAttributeTypeRef = typeof(TypeForwardedToAttribute).ToTypeReference(); static readonly ITypeReference assemblyVersionAttributeTypeRef = typeof(System.Reflection.AssemblyVersionAttribute).ToTypeReference(); void AddAttributes(AssemblyDefinition assembly, IList outputList) @@ -354,34 +365,6 @@ namespace ICSharpCode.NRefactory.TypeSystem assemblyVersion.PositionalArguments.Add(new SimpleConstantValue(KnownTypeReference.String, assembly.Name.Version.ToString())); outputList.Add(assemblyVersion); } - - // TypeForwardedToAttribute - foreach (ExportedType type in assembly.MainModule.ExportedTypes) { - if (type.IsForwarder) { - int typeParameterCount; - string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); - var typeForwardedTo = new DefaultUnresolvedAttribute(typeForwardedToAttributeTypeRef, new[] { KnownTypeReference.Type }); - var typeRef = new GetClassTypeReference(GetAssemblyReference(type.Scope), type.Namespace, name, typeParameterCount); - typeForwardedTo.PositionalArguments.Add(new TypeOfConstantValue(typeRef)); - outputList.Add(typeForwardedTo); - } - } - } - - [Serializable] - sealed class TypeOfConstantValue : IConstantValue - { - readonly ITypeReference typeRef; - - public TypeOfConstantValue(ITypeReference typeRef) - { - this.typeRef = typeRef; - } - - public ResolveResult Resolve(ITypeResolveContext context) - { - return new TypeOfResolveResult(context.Compilation.FindType(KnownTypeCode.Type), typeRef.Resolve(context)); - } } #endregion diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs index a941d4c49a..a15e83d26a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs @@ -23,6 +23,8 @@ using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; using System.Threading; + +using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -37,6 +39,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation IList assemblyAttributes; IList moduleAttributes; Dictionary typeDefinitions = new Dictionary(FullNameAndTypeParameterCountComparer.Ordinal); + Dictionary typeForwarders = new Dictionary(FullNameAndTypeParameterCountComparer.Ordinal); protected override void FreezeInternal() { @@ -103,6 +106,43 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation typeDefinitions.Add(key, typeDefinition); } + static readonly ITypeReference typeForwardedToAttributeTypeRef = typeof(System.Runtime.CompilerServices.TypeForwardedToAttribute).ToTypeReference(); + + /// + /// Adds a type forwarder. + /// This adds both an assembly attribute and an internal forwarder entry, which will be used + /// by the resolved assembly to provide the forwarded types. + /// + /// The name of the type. + /// The reference used to look up the type in the target assembly. + public void AddTypeForwarder(FullNameAndTypeParameterCount typeName, ITypeReference referencedType) + { + if (referencedType == null) + throw new ArgumentNullException("referencedType"); + FreezableHelper.ThrowIfFrozen(this); + var attribute = new DefaultUnresolvedAttribute(typeForwardedToAttributeTypeRef, new[] { KnownTypeReference.Type }); + attribute.PositionalArguments.Add(new TypeOfConstantValue(referencedType)); + assemblyAttributes.Add(attribute); + + typeForwarders[typeName] = referencedType; + } + + [Serializable] + sealed class TypeOfConstantValue : IConstantValue + { + readonly ITypeReference typeRef; + + public TypeOfConstantValue(ITypeReference typeRef) + { + this.typeRef = typeRef; + } + + public ResolveResult Resolve(ITypeResolveContext context) + { + return new TypeOfResolveResult(context.Compilation.FindType(KnownTypeCode.Type), typeRef.Resolve(context)); + } + } + public IUnresolvedTypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) { var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount); @@ -206,7 +246,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation sealed class DefaultResolvedAssembly : IAssembly { - readonly DefaultUnresolvedAssembly unresolved; + readonly DefaultUnresolvedAssembly unresolvedAssembly; readonly ICompilation compilation; readonly ITypeResolveContext context; readonly Dictionary unresolvedTypeDict; @@ -216,7 +256,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public DefaultResolvedAssembly(ICompilation compilation, DefaultUnresolvedAssembly unresolved) { this.compilation = compilation; - this.unresolved = unresolved; + this.unresolvedAssembly = unresolved; this.unresolvedTypeDict = unresolved.GetTypeDictionary(compilation.NameComparer); this.rootNamespace = new NS(this, unresolved.GetUnresolvedRootNamespace(compilation.NameComparer), null); this.context = new SimpleTypeResolveContext(this); @@ -225,7 +265,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } public IUnresolvedAssembly UnresolvedAssembly { - get { return unresolved; } + get { return unresolvedAssembly; } } public bool IsMainAssembly { @@ -233,7 +273,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } public string AssemblyName { - get { return unresolved.AssemblyName; } + get { return unresolvedAssembly.AssemblyName; } } public IList AssemblyAttributes { get; private set; } @@ -254,13 +294,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) { - return GetTypeDefinition(unresolved.GetTypeDefinition(ns, name, typeParameterCount)); + var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount); + + IUnresolvedTypeDefinition td; + ITypeReference typeRef; + if (unresolvedAssembly.typeDefinitions.TryGetValue(key, out td)) + return GetTypeDefinition(td); + else if (unresolvedAssembly.typeForwarders.TryGetValue(key, out typeRef)) + return typeRef.Resolve(compilation.TypeResolveContext).GetDefinition(); + else + return null; } ITypeDefinition GetTypeDefinition(IUnresolvedTypeDefinition unresolved) { - if (unresolved == null) - return null; return typeDict.GetOrAdd(unresolved, t => CreateTypeDefinition(t)); } @@ -278,7 +325,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IEnumerable TopLevelTypeDefinitions { get { - return unresolved.TopLevelTypeDefinitions.Select(t => GetTypeDefinition(t)); + return unresolvedAssembly.TopLevelTypeDefinitions.Select(t => GetTypeDefinition(t)); } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs index dada91480d..b5b6da763b 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs @@ -73,37 +73,26 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public string Name { get { return name; } } public int TypeParameterCount { get { return typeParameterCount; } } - IType ResolveInContext(ITypeResolveContext context) - { - IType type = null; - var compilation = context.Compilation; - foreach (var asm in new[] { - context.CurrentAssembly - }.Concat (compilation.Assemblies)) { - if (asm != null) { - type = asm.GetTypeDefinition(nameSpace, name, typeParameterCount); - if (type != null) - return type; - } - } - return type; - } - public IType Resolve(ITypeResolveContext context) { if (context == null) throw new ArgumentNullException("context"); + IType type = null; if (assembly == null) { - type = ResolveInContext(context); + var compilation = context.Compilation; + foreach (var asm in new[] { context.CurrentAssembly }.Concat(compilation.Assemblies)) { + if (asm != null) { + type = asm.GetTypeDefinition(nameSpace, name, typeParameterCount); + if (type != null) + return type; + } + } } else { IAssembly asm = assembly.Resolve(context); if (asm != null) { type = asm.GetTypeDefinition(nameSpace, name, typeParameterCount); } - if (type == null) { - type = ResolveInContext(context); - } } return type ?? new UnknownType(nameSpace, name, typeParameterCount); }