From 5670248de8ade23ad5f3f34e2b4745bfaafcf4c0 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 11 Sep 2012 09:56:25 +0200 Subject: [PATCH] Add 'FullTypeName' struct, and use it to represent type names. Contains some breaking API changes: - Renamed 'FullNameAndTypeParameterCount' to 'TopLevelTypeName'. - IAssembly.GetTypeDefinition(string, string, int) -> IAssembly.GetTypeDefinition(TopLevelTypeName) - IAssembly.GetTypeDefinition(IUnresolvedTypeDefinition) -> IAssembly.GetTypeDefinition(FullTypeName) - GetClassTypeReference now supports nested types --- .../Completion/CSharpCompletionEngine.cs | 4 +- .../Refactoring/RefactoringContext.cs | 2 +- .../Refactoring/TypeSystemAstBuilder.cs | 18 +- .../TypeSystem/AliasNamespaceReference.cs | 6 + .../TypeSystem/CSharpAssembly.cs | 23 +- .../MemberTypeOrNamespaceReference.cs | 15 +- .../SimpleTypeOrNamespaceReference.cs | 13 +- .../TypeSystem/TypeOrNamespaceReference.cs | 14 +- .../CSharp/CodeCompletion/TestBase.cs | 4 +- .../Refactoring/TypeSystemAstBuilderTests.cs | 2 +- .../CSharp/Resolver/ConversionsTest.cs | 4 +- .../CSharp/Resolver/MemberLookupTests.cs | 6 +- .../Documentation/IDStringTests.cs | 2 +- .../TypeSystem/GetAllBaseTypesTest.cs | 5 +- .../TypeSystem/GetMembersTests.cs | 10 +- .../TypeSystem/TypeParameterTests.cs | 6 +- .../TypeSystem/TypeSystemHelper.cs | 6 + .../TypeSystem/TypeSystemTests.cs | 9 +- .../GetPotentiallyNestedClassTypeReference.cs | 2 +- .../ICSharpCode.NRefactory.csproj | 4 +- .../TypeSystem/CecilLoader.cs | 10 +- .../TypeSystem/ExtensionMethods.cs | 57 +++- .../TypeSystem/FullTypeName.cs | 312 ++++++++++++++++++ .../TypeSystem/IAssembly.cs | 2 +- .../TypeSystem/ICompilation.cs | 3 + .../TypeSystem/ITypeDefinition.cs | 6 + .../DefaultResolvedTypeDefinition.cs | 4 + .../DefaultUnresolvedAssembly.cs | 26 +- .../DefaultUnresolvedTypeDefinition.cs | 24 +- .../FullNameAndTypeParameterCount.cs | 69 +--- .../Implementation/GetClassTypeReference.cs | 99 +++--- .../Implementation/KnownTypeCache.cs | 2 +- .../TypeSystem/Implementation/UnknownType.cs | 50 +-- .../TypeSystem/ReflectionHelper.cs | 12 +- .../TypeSystem/TopLevelTypeName.cs | 144 ++++++++ 35 files changed, 731 insertions(+), 244 deletions(-) create mode 100644 ICSharpCode.NRefactory/TypeSystem/FullTypeName.cs create mode 100644 ICSharpCode.NRefactory/TypeSystem/TopLevelTypeName.cs diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 957477f46d..2d0b66b4de 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1336,7 +1336,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } if (this.currentMember != null && !(node is AstType)) { - var def = ctx.CurrentTypeDefinition ?? Compilation.MainAssembly.GetTypeDefinition(currentType); + var def = ctx.CurrentTypeDefinition; + if (def == null && currentType != null) + def = Compilation.MainAssembly.GetTypeDefinition(currentType.FullTypeName); if (def != null) { bool isProtectedAllowed = true; foreach (var member in def.GetMembers ()) { diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs index 6b9c6fe82c..578b5a6838 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs @@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring public virtual AstType CreateShortType(string ns, string name, int typeParameterCount = 0) { var builder = CreateTypeSytemAstBuilder(); - return builder.ConvertType(ns, name, typeParameterCount); + return builder.ConvertType(new TopLevelTypeName(ns, name, typeParameterCount)); } public virtual IEnumerable GetSelectedNodes() diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs index 78bca9521e..12faf6e8ab 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs @@ -142,17 +142,27 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return astType; } - public AstType ConvertType(string ns, string name, int typeParameterCount = 0) + public AstType ConvertType(FullTypeName fullTypeName) { if (resolver != null) { foreach (var asm in resolver.Compilation.Assemblies) { - var def = asm.GetTypeDefinition(ns, name, typeParameterCount); + var def = asm.GetTypeDefinition(fullTypeName); if (def != null) { return ConvertType(def); } } } - return new MemberType(new SimpleType(ns), name); + TopLevelTypeName top = fullTypeName.TopLevelTypeName; + AstType type; + if (string.IsNullOrEmpty(top.Namespace)) { + type = new SimpleType(top.Name); + } else { + type = new SimpleType(top.Namespace).MemberType(top.Name); + } + for (int i = 0; i < fullTypeName.NestingLevel; i++) { + type = type.MemberType(fullTypeName.GetNestedTypeName(i)); + } + return type; } AstType ConvertTypeHelper(IType type) @@ -601,7 +611,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { if (GenerateBody) { return new BlockStatement { - new ThrowStatement(new ObjectCreateExpression(ConvertType("System", "NotImplementedException"))) + new ThrowStatement(new ObjectCreateExpression(ConvertType(new TopLevelTypeName("System", "NotImplementedException", 0)))) }; } else { return BlockStatement.Null; diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/AliasNamespaceReference.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/AliasNamespaceReference.cs index d214103436..03590b8c91 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/AliasNamespaceReference.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/AliasNamespaceReference.cs @@ -51,6 +51,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem return resolver.ResolveAlias(identifier); } + public override IType ResolveType(CSharpResolver resolver) + { + // alias cannot refer to types + return SpecialType.UnknownType; + } + public override string ToString() { return identifier + "::"; diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs index 9b0f15a531..02bbc68f25 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs @@ -181,9 +181,9 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem return fullAssemblyName.Substring(0, pos); } - Dictionary typeDict; + Dictionary typeDict; - Dictionary GetTypes() + Dictionary GetTypes() { var dict = LazyInit.VolatileRead(ref this.typeDict); if (dict != null) { @@ -192,9 +192,9 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem // Always use the ordinal comparer for the main dictionary so that partial classes // get merged correctly. // The compilation's comparer will be used for the per-namespace dictionaries. - var comparer = FullNameAndTypeParameterCountComparer.Ordinal; + var comparer = TopLevelTypeNameComparer.Ordinal; dict = projectContent.TopLevelTypeDefinitions - .GroupBy(t => new FullNameAndTypeParameterCount(t.Namespace, t.Name, t.TypeParameters.Count), comparer) + .GroupBy(t => new TopLevelTypeName(t.Namespace, t.Name, t.TypeParameters.Count), comparer) .ToDictionary(g => g.Key, g => CreateResolvedTypeDefinition(g.ToArray()), comparer); return LazyInit.GetOrSet(ref this.typeDict, dict); } @@ -205,11 +205,10 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem return new DefaultResolvedTypeDefinition(context, parts); } - public ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) + public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName) { - var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount); ITypeDefinition def; - if (GetTypes().TryGetValue(key, out def)) + if (GetTypes().TryGetValue(topLevelTypeName, out def)) return def; else return null; @@ -233,7 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem readonly string fullName; readonly string name; internal readonly List childNamespaces = new List(); - internal readonly Dictionary types; + internal readonly Dictionary types; public NS(CSharpAssembly assembly) { @@ -243,7 +242,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem // Our main dictionary for the CSharpAssembly is using an ordinal comparer. // If the compilation's comparer isn't ordinal, we need to create a new dictionary with the compilation's comparer. if (assembly.compilation.NameComparer != StringComparer.Ordinal) { - this.types = new Dictionary(new FullNameAndTypeParameterCountComparer(assembly.compilation.NameComparer)); + this.types = new Dictionary(new TopLevelTypeNameComparer(assembly.compilation.NameComparer)); } } @@ -254,7 +253,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem this.fullName = fullName; this.name = name; if (parentNamespace.types != null) - this.types = new Dictionary(parentNamespace.types.Comparer); + this.types = new Dictionary(parentNamespace.types.Comparer); } string INamespace.ExternAlias { @@ -310,15 +309,15 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount) { + var key = new TopLevelTypeName(fullName, name, typeParameterCount); if (types != null) { - var key = new FullNameAndTypeParameterCount(fullName, name, typeParameterCount); ITypeDefinition typeDef; if (types.TryGetValue(key, out typeDef)) return typeDef; else return null; } else { - return assembly.GetTypeDefinition(fullName, name, typeParameterCount); + return assembly.GetTypeDefinition(key); } } } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/MemberTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/MemberTypeOrNamespaceReference.cs index 6956472c59..5ec7eb0f91 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/MemberTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/MemberTypeOrNamespaceReference.cs @@ -22,6 +22,7 @@ using System.Collections.ObjectModel; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -58,7 +59,11 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem } public IList TypeArguments { - get { return new ReadOnlyCollection(typeArguments); } + get { return typeArguments; } + } + + public NameLookupMode LookupMode { + get { return lookupMode; } } /// @@ -67,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem /// public MemberTypeOrNamespaceReference AddSuffix(string suffix) { - return new MemberTypeOrNamespaceReference(target, identifier + suffix, typeArguments); + return new MemberTypeOrNamespaceReference(target, identifier + suffix, typeArguments, lookupMode); } public override ResolveResult Resolve(CSharpResolver resolver) @@ -86,6 +91,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem } } + public override IType ResolveType(CSharpResolver resolver) + { + TypeResolveResult trr = Resolve(resolver) as TypeResolveResult; + return trr != null ? trr.Type : new UnknownType(null, identifier, typeArguments.Count); + } + public override string ToString() { if (typeArguments.Count == 0) diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/SimpleTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/SimpleTypeOrNamespaceReference.cs index d0047ef6e3..a1ebe1b80b 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/SimpleTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/SimpleTypeOrNamespaceReference.cs @@ -23,6 +23,7 @@ using System.Collections.ObjectModel; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -51,7 +52,11 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem } public IList TypeArguments { - get { return new ReadOnlyCollection(typeArguments); } + get { return typeArguments; } + } + + public NameLookupMode LookupMode { + get { return lookupMode; } } /// @@ -69,6 +74,12 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem return resolver.LookupSimpleNameOrTypeName(identifier, typeArgs, lookupMode); } + public override IType ResolveType(CSharpResolver resolver) + { + TypeResolveResult trr = Resolve(resolver) as TypeResolveResult; + return trr != null ? trr.Type : new UnknownType(null, identifier, typeArguments.Count); + } + public override string ToString() { if (typeArguments.Count == 0) diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs index a822b9a66d..ddbcea2cab 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs @@ -34,6 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem /// public abstract ResolveResult Resolve(CSharpResolver resolver); + /// + /// Returns the type that is referenced; or an if the type isn't found. + /// + public abstract IType ResolveType(CSharpResolver resolver); + /// /// Returns the namespace that is referenced; or null if no such namespace is found. /// @@ -43,15 +48,6 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem return nrr != null ? nrr.Namespace : null; } - /// - /// Returns the type that is referenced; or if the type isn't found. - /// - public IType ResolveType(CSharpResolver resolver) - { - TypeResolveResult trr = Resolve(resolver) as TypeResolveResult; - return trr != null ? trr.Type : SpecialType.UnknownType; - } - IType ITypeReference.Resolve(ITypeResolveContext context) { // Strictly speaking, we might have to resolve the type in a nested compilation, similar diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/TestBase.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/TestBase.cs index 3ee87bfa77..72969a027f 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/TestBase.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/TestBase.cs @@ -1,4 +1,4 @@ -// +// // TestBase.cs // // Author: @@ -38,7 +38,7 @@ using System.Diagnostics; namespace ICSharpCode.NRefactory.CSharp.CodeCompletion { [TestFixture] - public class TestBase + public abstract class TestBase { class TestListener : TraceListener { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs index 3f639b4c23..82a677cb15 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/TypeSystemAstBuilderTests.cs @@ -217,7 +217,7 @@ namespace OtherNS { public void AmbiguousType() { Assert.AreEqual("System.Array", TypeToString(compilation.FindType(typeof(Array)))); - Assert.AreEqual("OtherNS.Array", TypeToString(compilation.MainAssembly.GetTypeDefinition("OtherNS", "Array", 0))); + Assert.AreEqual("OtherNS.Array", TypeToString(compilation.MainAssembly.GetTypeDefinition(new TopLevelTypeName("OtherNS", "Array")))); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs index 4702395891..d95d91605d 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs @@ -508,8 +508,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver ) } ) })); ICompilation compilation = TypeSystemHelper.CreateCompilation(a, b); - ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a); - ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b); + ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a.FullTypeName); + ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b.FullTypeName); IType type1 = new ParameterizedType(resolvedB, new [] { compilation.FindType(KnownTypeCode.Double) }); IType type2 = new ParameterizedType(resolvedA, new [] { new ParameterizedType(resolvedB, new[] { compilation.FindType(KnownTypeCode.String) }) }); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs index 882273873d..83b196f067 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs @@ -61,7 +61,7 @@ class Derived : Middle { public override void Method() {} }"; var unresolvedFile = Parse(program); - ITypeDefinition derived = compilation.MainAssembly.GetTypeDefinition(unresolvedFile.TopLevelTypeDefinitions[2]); + ITypeDefinition derived = compilation.MainAssembly.GetTypeDefinition(unresolvedFile.TopLevelTypeDefinitions[2].FullTypeName); var rr = lookup.Lookup(new ResolveResult(derived), "Method", EmptyList.Instance, true) as MethodGroupResolveResult; Assert.AreEqual(2, rr.MethodsGroupedByDeclaringType.Count()); @@ -88,7 +88,7 @@ class Derived : Base { public override void Method(string a) {} }"; var unresolvedFile = Parse(program); - ITypeDefinition derived = compilation.MainAssembly.GetTypeDefinition(unresolvedFile.TopLevelTypeDefinitions[1]); + ITypeDefinition derived = compilation.MainAssembly.GetTypeDefinition(unresolvedFile.TopLevelTypeDefinitions[1].FullTypeName); var rr = lookup.Lookup(new ResolveResult(derived), "Method", EmptyList.Instance, true) as MethodGroupResolveResult; Assert.AreEqual(2, rr.MethodsGroupedByDeclaringType.Count()); @@ -116,7 +116,7 @@ class Derived : Base { public override void Method(S a) {} }"; var unresolvedFile = Parse(program); - ITypeDefinition derived = compilation.MainAssembly.GetTypeDefinition(unresolvedFile.TopLevelTypeDefinitions[1]); + ITypeDefinition derived = compilation.MainAssembly.GetTypeDefinition(unresolvedFile.TopLevelTypeDefinitions[1].FullTypeName); var rr = lookup.Lookup(new ResolveResult(derived), "Method", EmptyList.Instance, true) as MethodGroupResolveResult; Assert.AreEqual(1, rr.MethodsGroupedByDeclaringType.Count()); diff --git a/ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs b/ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs index 5d30b6e403..9bdbe5c04a 100644 --- a/ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs +++ b/ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs @@ -59,7 +59,7 @@ namespace ICSharpCode.NRefactory.Documentation ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount = 0) { - return compilation.MainAssembly.GetTypeDefinition(nameSpace, name, typeParameterCount); + return compilation.MainAssembly.GetTypeDefinition(new TopLevelTypeName(nameSpace, name, typeParameterCount)); } [Test] diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs index b53ef9d30f..9200c50840 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs @@ -83,7 +83,7 @@ namespace System.Collections.Generic { ITypeDefinition Resolve(IUnresolvedTypeDefinition typeDef) { - return compilation.MainAssembly.GetTypeDefinition(typeDef); + return typeDef.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition(); } [Test] @@ -135,8 +135,7 @@ namespace System.Collections.Generic { // class C : C {} var c = new DefaultUnresolvedTypeDefinition(string.Empty, "C"); c.BaseTypes.Add(c); - compilation = TypeSystemHelper.CreateCompilation(c); - ITypeDefinition resolvedC = Resolve(c); + ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilationAndResolve(c); Assert.AreEqual(new [] { resolvedC }, resolvedC.GetAllBaseTypes().ToArray()); } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs index a35c37883c..6628e2de96 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs @@ -31,8 +31,8 @@ namespace ICSharpCode.NRefactory.TypeSystem public void EmptyClassHasToString() { DefaultUnresolvedTypeDefinition c = new DefaultUnresolvedTypeDefinition(string.Empty, "C"); - var compilation = TypeSystemHelper.CreateCompilation(c); - Assert.AreEqual("System.Object.ToString", compilation.MainAssembly.GetTypeDefinition(c).GetMethods(m => m.Name == "ToString").Single().FullName); + var resolvedC = TypeSystemHelper.CreateCompilationAndResolve(c); + Assert.AreEqual("System.Object.ToString", resolvedC.GetMethods(m => m.Name == "ToString").Single().FullName); } [Test] @@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.TypeSystem c.BaseTypes.Add(b2); var compilation = TypeSystemHelper.CreateCompilation(b1, b2, c); - ITypeDefinition resolvedC = compilation.MainAssembly.GetTypeDefinition(c); + ITypeDefinition resolvedC = compilation.MainAssembly.GetTypeDefinition(c.FullTypeName); Assert.AreEqual(new[] { "P1", "P2" }, resolvedC.GetProperties().Select(p => p.Name).ToArray()); // Test that there's only one copy of ToString(): Assert.AreEqual(1, resolvedC.GetMethods(m => m.Name == "ToString").Count()); @@ -91,8 +91,8 @@ namespace ICSharpCode.NRefactory.TypeSystem a.NestedTypes.Add(b); var compilation = TypeSystemHelper.CreateCompilation(a, b); - ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a); - ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b); + ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a.FullTypeName); + ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b.FullTypeName); // A<> gets self-parameterized, B<> stays unbound Assert.AreEqual("A`1+B`1[[`0],[]]", resolvedA.GetNestedTypes().Single().ReflectionName); diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeParameterTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeParameterTests.cs index 8dad6bb71c..e081eefbd8 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeParameterTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeParameterTests.cs @@ -36,7 +36,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Constraints = { new TypeParameterReference(EntityType.TypeDefinition, 0) } }); - ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilation(c).MainAssembly.GetTypeDefinition(c); + ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilationAndResolve(c); // At runtime, we might have T=System.ValueType and U=int, so C# can't inherit the 'class' constraint // from one type parameter to another. Assert.AreEqual(true, resolvedC.TypeParameters[0].IsReferenceType); @@ -54,7 +54,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Constraints = { new TypeParameterReference(EntityType.TypeDefinition, 0) } }); - ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilation(c).MainAssembly.GetTypeDefinition(c); + ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilationAndResolve(c); // At runtime, we might have T=System.ValueType and U=int, so C# can't inherit the 'class' constraint // from one type parameter to another. Assert.AreEqual(true, resolvedC.TypeParameters[0].IsReferenceType); @@ -73,7 +73,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Constraints = { new TypeParameterReference(EntityType.TypeDefinition, 0) } }); - ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilation(c).MainAssembly.GetTypeDefinition(c); + ITypeDefinition resolvedC = TypeSystemHelper.CreateCompilationAndResolve(c); Assert.AreEqual(true, resolvedC.TypeParameters[0].IsReferenceType); Assert.AreEqual(true, resolvedC.TypeParameters[1].IsReferenceType); Assert.AreEqual("System.Collections.Generic.List`1[[System.String]]", resolvedC.TypeParameters[0].EffectiveBaseClass.ReflectionName); diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemHelper.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemHelper.cs index d5c94561e4..f7671aa102 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemHelper.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemHelper.cs @@ -44,5 +44,11 @@ namespace ICSharpCode.NRefactory.TypeSystem pc = pc.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore }); return pc.CreateCompilation(); } + + public static ITypeDefinition CreateCompilationAndResolve(IUnresolvedTypeDefinition unresolvedTypeDefinition) + { + var compilation = CreateCompilation(unresolvedTypeDefinition); + return unresolvedTypeDefinition.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition(); + } } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index 1a3538f9a9..40c1d00c59 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -137,8 +137,13 @@ namespace ICSharpCode.NRefactory.TypeSystem ParameterizedType crt = (ParameterizedType)rt.ReferencedType; Assert.AreEqual("System.Collections.Generic.IDictionary", crt.FullName); Assert.AreEqual("System.String", crt.TypeArguments[0].FullName); - // ? for NUnit.TestAttribute (because that assembly isn't in ctx) - Assert.AreEqual("System.Collections.Generic.IList`1[[?]]", crt.TypeArguments[1].ReflectionName); + // we know the name for TestAttribute, but not necessarily the namespace, as NUnit is not in the compilation + Assert.AreEqual("System.Collections.Generic.IList", crt.TypeArguments[1].FullName); + var testAttributeType = ((ParameterizedType)crt.TypeArguments[1]).TypeArguments.Single(); + Assert.AreEqual("TestAttribute", testAttributeType.Name); + Assert.AreEqual(TypeKind.Unknown, testAttributeType.Kind); + // (more accurately, we know the namespace and reflection name if the type was loaded by cecil, + // but not if we parsed it from C#) } [Test] diff --git a/ICSharpCode.NRefactory/Documentation/GetPotentiallyNestedClassTypeReference.cs b/ICSharpCode.NRefactory/Documentation/GetPotentiallyNestedClassTypeReference.cs index 0e5e7404c8..bb6cfd6bc3 100644 --- a/ICSharpCode.NRefactory/Documentation/GetPotentiallyNestedClassTypeReference.cs +++ b/ICSharpCode.NRefactory/Documentation/GetPotentiallyNestedClassTypeReference.cs @@ -51,7 +51,7 @@ namespace ICSharpCode.NRefactory.Documentation foreach (var asm in assemblies) { if (asm == null) continue; - ITypeDefinition typeDef = asm.GetTypeDefinition(ns, name, topLevelTPC); + ITypeDefinition typeDef = asm.GetTypeDefinition(new TopLevelTypeName(ns, name, topLevelTPC)); for (int j = i + 1; j < parts.Length && typeDef != null; j++) { int tpc = (j == parts.Length - 1 ? typeParameterCount : 0); typeDef = typeDef.NestedTypes.FirstOrDefault(n => n.Name == parts[j] && n.TypeParameterCount == tpc); diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 9b8e85e343..d20a2aceac 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -138,6 +138,7 @@ + @@ -223,6 +224,7 @@ + @@ -284,4 +286,4 @@ - + \ No newline at end of file diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index 67099a30e7..32c15308ec 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -190,7 +190,7 @@ namespace ICSharpCode.NRefactory.TypeSystem name = interningProvider.Intern(name); var typeRef = new GetClassTypeReference(GetAssemblyReference(type.Scope), ns, name, typeParameterCount); typeRef = interningProvider.Intern(typeRef); - var key = new FullNameAndTypeParameterCount(ns, name, typeParameterCount); + var key = new TopLevelTypeName(ns, name, typeParameterCount); currentAssembly.AddTypeForwarder(key, typeRef); } } @@ -1793,6 +1793,12 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return cecilTypeDef.FullName; } } + public FullTypeName FullTypeName { + get { + return new TopLevelTypeName(namespaceName, this.Name, typeParameters.Count); + } + } + public TypeKind Kind { get { return kind; } } @@ -1884,7 +1890,7 @@ namespace ICSharpCode.NRefactory.TypeSystem throw new ArgumentNullException("context"); if (context.CurrentAssembly == null) throw new ArgumentException("An ITypeDefinition cannot be resolved in a context without a current assembly."); - return context.CurrentAssembly.GetTypeDefinition(this) + return context.CurrentAssembly.GetTypeDefinition(this.FullTypeName) ?? (IType)new UnknownType(this.Namespace, this.Name, this.TypeParameters.Count); } diff --git a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs index f15885817c..52f7ec258a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs @@ -392,28 +392,59 @@ namespace ICSharpCode.NRefactory.TypeSystem #endregion #region IAssembly.GetTypeDefinition() + /// + /// Retrieves the specified type in this compilation. + /// Returns an if the type cannot be found in this compilation. + /// + /// + /// There can be multiple types with the same full name in a compilation, as a + /// full type name is only unique per assembly. + /// If there are multiple possible matches, this method will return just one of them. + /// When possible, use instead to + /// retrieve a type from a specific assembly. + /// + public static IType FindType(this ICompilation compilation, FullTypeName fullTypeName) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + foreach (IAssembly asm in compilation.Assemblies) { + ITypeDefinition def = asm.GetTypeDefinition(fullTypeName); + if (def != null) + return def; + } + return new UnknownType(fullTypeName); + } + /// /// Gets the type definition for the specified unresolved type. /// Returns null if the unresolved type does not belong to this assembly. /// - public static ITypeDefinition GetTypeDefinition(this IAssembly assembly, IUnresolvedTypeDefinition unresolved) + public static ITypeDefinition GetTypeDefinition(this IAssembly assembly, FullTypeName fullTypeName) { if (assembly == null) throw new ArgumentNullException("assembly"); - if (unresolved == null) + TopLevelTypeName topLevelTypeName = fullTypeName.TopLevelTypeName; + ITypeDefinition typeDef = assembly.GetTypeDefinition(topLevelTypeName); + if (typeDef == null) return null; - if (unresolved.DeclaringTypeDefinition != null) { - ITypeDefinition parentType = GetTypeDefinition(assembly, unresolved.DeclaringTypeDefinition); - if (parentType == null) - return null; - foreach (var nestedType in parentType.NestedTypes) { - if (nestedType.Name == unresolved.Name && nestedType.TypeParameterCount == unresolved.TypeParameters.Count) - return nestedType; - } - return null; - } else { - return assembly.GetTypeDefinition(unresolved.Namespace, unresolved.Name, unresolved.TypeParameters.Count); + int typeParameterCount = topLevelTypeName.TypeParameterCount; + for (int i = 0; i < fullTypeName.NestingLevel; i++) { + string name = fullTypeName.GetNestedTypeName(i); + typeParameterCount += fullTypeName.GetNestedTypeAdditionalTypeParameterCount(i); + typeDef = FindNestedType(typeDef, name, typeParameterCount); + if (typeDef == null) + break; + } + return typeDef; + } + + static ITypeDefinition FindNestedType(ITypeDefinition typeDef, string name, int typeParameterCount) + { + foreach (var nestedType in typeDef.NestedTypes) { + if (nestedType.Name == name && nestedType.TypeParameterCount == typeParameterCount) + return nestedType; } + return null; } #endregion diff --git a/ICSharpCode.NRefactory/TypeSystem/FullTypeName.cs b/ICSharpCode.NRefactory/TypeSystem/FullTypeName.cs new file mode 100644 index 0000000000..dd76eb22a5 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/FullTypeName.cs @@ -0,0 +1,312 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Holds the full name of a type definition. + /// A full type name uniquely identifies a type definition within a single assembly. + /// + /// + /// A full type name can only represent type definitions, not arbitrary types. + /// It does not include any type arguments, and can not refer to array or pointer types. + /// + /// + /// + [Serializable] + public struct FullTypeName : IEquatable + { + [Serializable] + struct NestedTypeName + { + public readonly string Name; + public readonly int AdditionalTypeParameterCount; + + public NestedTypeName(string name, int additionalTypeParameterCount) + { + if (name == null) + throw new ArgumentNullException("name"); + this.Name = name; + this.AdditionalTypeParameterCount = additionalTypeParameterCount; + } + } + + readonly TopLevelTypeName topLevelType; + readonly NestedTypeName[] nestedTypes; + + FullTypeName(TopLevelTypeName topLevelTypeName, NestedTypeName[] nestedTypes) + { + this.topLevelType = topLevelTypeName; + this.nestedTypes = nestedTypes; + } + + /// + /// Constructs a FullTypeName representing the given top-level type. + /// + /// + /// FullTypeName has an implicit conversion operator from TopLevelTypeName, + /// so you can simply write: + /// FullTypeName f = new TopLevelTypeName(...); + /// + public FullTypeName(TopLevelTypeName topLevelTypeName) + { + this.topLevelType = topLevelTypeName; + this.nestedTypes = null; + } + + /// + /// Constructs a FullTypeName by parsing the given reflection name. + /// Note that FullTypeName can only represent type definition names. If the reflection name + /// might refer to a parameterized type or array etc., use + /// instead. + /// + /// + /// Expected syntax: NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] } + /// where # are type parameter counts + /// + public FullTypeName(string reflectionName) + { + int pos = reflectionName.IndexOf('+'); + if (pos < 0) { + // top-level type + this.topLevelType = new TopLevelTypeName(reflectionName); + this.nestedTypes = null; + } else { + // nested type + string[] parts = reflectionName.Split('+'); + this.topLevelType = new TopLevelTypeName(parts[0]); + this.nestedTypes = new NestedTypeName[parts.Length - 1]; + for (int i = 0; i < nestedTypes.Length; i++) { + int tpc; + string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(parts[i + 1], out tpc); + nestedTypes[i] = new NestedTypeName(name, tpc); + } + } + } + + /// + /// Gets the top-level type name. + /// + public TopLevelTypeName TopLevelTypeName { + get { return topLevelType; } + } + + /// + /// Gets whether this is a nested type. + /// + public bool IsNested { + get { + return nestedTypes != null; + } + } + + /// + /// Gets the nesting level. + /// + public int NestingLevel { + get { + return nestedTypes != null ? nestedTypes.Length : 0; + } + } + + /// + /// Gets the name of the type. + /// For nested types, this is the name of the innermost type. + /// + public string Name { + get { + if (nestedTypes != null) + return nestedTypes[nestedTypes.Length - 1].Name; + else + return topLevelType.Name; + } + } + + public string ReflectionName { + get { + if (nestedTypes == null) + return topLevelType.ReflectionName; + StringBuilder b = new StringBuilder(topLevelType.ReflectionName); + foreach (NestedTypeName nt in nestedTypes) { + b.Append('+'); + b.Append(nt.Name); + if (nt.AdditionalTypeParameterCount > 0) { + b.Append('`'); + b.Append(nt.AdditionalTypeParameterCount); + } + } + return b.ToString(); + } + } + + /// + /// Gets the total type parameter count. + /// + public int TypeParameterCount { + get { + int tpc = topLevelType.TypeParameterCount; + if (nestedTypes != null) { + foreach (var nt in nestedTypes) { + tpc += nt.AdditionalTypeParameterCount; + } + } + return tpc; + } + } + + /// + /// Gets the name of the nested type at the given level. + /// + public string GetNestedTypeName(int nestingLevel) + { + if (nestedTypes == null) + throw new InvalidOperationException(); + return nestedTypes[nestingLevel].Name; + } + + /// + /// Gets the number of additional type parameters of the nested type at the given level. + /// + public int GetNestedTypeAdditionalTypeParameterCount(int nestingLevel) + { + if (nestedTypes == null) + throw new InvalidOperationException(); + return nestedTypes[nestingLevel].AdditionalTypeParameterCount; + } + + /// + /// Gets the declaring type name. + /// + /// This is a top-level type name. + public FullTypeName GetDeclaringType() + { + if (nestedTypes == null) + throw new InvalidOperationException(); + if (nestedTypes.Length == 1) + return topLevelType; + NestedTypeName[] outerNestedTypeNames = new NestedTypeName[nestedTypes.Length - 1]; + Array.Copy(nestedTypes, 0, outerNestedTypeNames, 0, outerNestedTypeNames.Length); + return new FullTypeName(topLevelType, nestedTypes); + } + + /// + /// Gets a nested type name. + /// + public FullTypeName NestedType(string name, int additionalTypeParameterCount) + { + if (name == null) + throw new ArgumentNullException("name"); + var newNestedType = new NestedTypeName(name, additionalTypeParameterCount); + if (nestedTypes == null) + return new FullTypeName(topLevelType, new[] { newNestedType }); + NestedTypeName[] newNestedTypeNames = new NestedTypeName[nestedTypes.Length + 1]; + nestedTypes.CopyTo(newNestedTypeNames, 0); + newNestedTypeNames[newNestedTypeNames.Length - 1] = newNestedType; + return new FullTypeName(topLevelType, newNestedTypeNames); + } + + public static implicit operator FullTypeName(TopLevelTypeName topLevelTypeName) + { + return new FullTypeName(topLevelTypeName); + } + + public override string ToString() + { + return this.ReflectionName; + } + + #region Equals and GetHashCode implementation + public override bool Equals(object obj) + { + return obj is FullTypeName && Equals((FullTypeName)obj); + } + + public bool Equals(FullTypeName other) + { + return FullTypeNameComparer.Ordinal.Equals(this, other); + } + + public override int GetHashCode() + { + return FullTypeNameComparer.Ordinal.GetHashCode(this); + } + + public static bool operator ==(FullTypeName left, FullTypeName right) + { + return left.Equals(right); + } + + public static bool operator !=(FullTypeName left, FullTypeName right) + { + return !left.Equals(right); + } + #endregion + } + + [Serializable] + public sealed class FullTypeNameComparer : IEqualityComparer + { + public static readonly FullTypeNameComparer Ordinal = new FullTypeNameComparer(StringComparer.Ordinal); + public static readonly FullTypeNameComparer OrdinalIgnoreCase = new FullTypeNameComparer(StringComparer.OrdinalIgnoreCase); + + public readonly StringComparer NameComparer; + + public FullTypeNameComparer(StringComparer nameComparer) + { + this.NameComparer = nameComparer; + } + + public bool Equals(FullTypeName x, FullTypeName y) + { + if (x.NestingLevel != y.NestingLevel) + return false; + TopLevelTypeName topX = x.TopLevelTypeName; + TopLevelTypeName topY = y.TopLevelTypeName; + if (topX.TypeParameterCount == topY.TypeParameterCount + && NameComparer.Equals(topX.Name, topY.Name) + && NameComparer.Equals(topX.Namespace, topY.Namespace)) + { + for (int i = 0; i < x.NestingLevel; i++) { + if (x.GetNestedTypeAdditionalTypeParameterCount(i) != y.GetNestedTypeAdditionalTypeParameterCount(i)) + return false; + if (!NameComparer.Equals(x.GetNestedTypeName(i), y.GetNestedTypeName(i))) + return false; + } + return true; + } + return false; + } + + public int GetHashCode(FullTypeName obj) + { + TopLevelTypeName top = obj.TopLevelTypeName; + int hash = NameComparer.GetHashCode(top.Name) ^ NameComparer.GetHashCode(top.Namespace) ^ top.TypeParameterCount; + unchecked { + for (int i = 0; i < obj.NestingLevel; i++) { + hash *= 31; + hash += NameComparer.GetHashCode(obj.Name) ^ obj.TypeParameterCount; + } + } + return hash; + } + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs b/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs index c93484300a..1c31e69942 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs @@ -115,7 +115,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Gets the type definition for a top-level type. /// /// This method uses ordinal name comparison, not the compilation's name comparer. - ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount); + ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName); /// /// Gets all non-nested types in the assembly. diff --git a/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs b/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs index 478776aa30..44e4647ec6 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs @@ -37,6 +37,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Gets the list of all assemblies in the compilation. /// + /// + /// This main assembly is the first entry in the list. + /// IList Assemblies { get; } /// diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs index 7cd98c8d23..ccc627f45e 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs @@ -30,6 +30,7 @@ namespace ICSharpCode.NRefactory.TypeSystem { TypeKind Kind { get; } + FullTypeName FullTypeName { get; } IList BaseTypes { get; } IList TypeParameters { get; } @@ -119,6 +120,11 @@ namespace ICSharpCode.NRefactory.TypeSystem /// IType EnumUnderlyingType { get; } + /// + /// Gets the full name of this type. + /// + FullTypeName FullTypeName { get; } + /// /// Gets/Sets the declaring type (incl. type arguments, if any). /// This property never returns null -- for top-level entities, it returns SharedTypes.UnknownType. diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs index af7df8f1c5..b6cd1e09ce 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs @@ -566,6 +566,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return parts[0].Namespace; } } + public FullTypeName FullTypeName { + get { return parts[0].FullTypeName; } + } + public DomRegion Region { get { return parts[0].Region; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs index 1111ef638f..2016ee1f30 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs @@ -39,8 +39,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation string fullAssemblyName; IList assemblyAttributes; IList moduleAttributes; - Dictionary typeDefinitions = new Dictionary(FullNameAndTypeParameterCountComparer.Ordinal); - Dictionary typeForwarders = new Dictionary(FullNameAndTypeParameterCountComparer.Ordinal); + Dictionary typeDefinitions = new Dictionary(TopLevelTypeNameComparer.Ordinal); + Dictionary typeForwarders = new Dictionary(TopLevelTypeNameComparer.Ordinal); protected override void FreezeInternal() { @@ -144,7 +144,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (typeDefinition.DeclaringTypeDefinition != null) throw new ArgumentException("Cannot add nested types."); FreezableHelper.ThrowIfFrozen(this); - var key = new FullNameAndTypeParameterCount(typeDefinition.Namespace, typeDefinition.Name, typeDefinition.TypeParameters.Count); + var key = new TopLevelTypeName(typeDefinition.Namespace, typeDefinition.Name, typeDefinition.TypeParameters.Count); typeDefinitions.Add(key, typeDefinition); } @@ -157,7 +157,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// The name of the type. /// The reference used to look up the type in the target assembly. - public void AddTypeForwarder(FullNameAndTypeParameterCount typeName, ITypeReference referencedType) + public void AddTypeForwarder(TopLevelTypeName typeName, ITypeReference referencedType) { if (referencedType == null) throw new ArgumentNullException("referencedType"); @@ -187,7 +187,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IUnresolvedTypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) { - var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount); + var key = new TopLevelTypeName(ns ?? string.Empty, name, typeParameterCount); IUnresolvedTypeDefinition td; if (typeDefinitions.TryGetValue(key, out td)) return td; @@ -216,9 +216,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } //[NonSerialized] - //List> cachedTypeDictionariesPerNameComparer; + //List> cachedTypeDictionariesPerNameComparer; - Dictionary GetTypeDictionary(StringComparer nameComparer) + Dictionary GetTypeDictionary(StringComparer nameComparer) { Debug.Assert(IsFrozen); if (nameComparer == StringComparer.Ordinal) @@ -291,7 +291,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation readonly DefaultUnresolvedAssembly unresolvedAssembly; readonly ICompilation compilation; readonly ITypeResolveContext context; - readonly Dictionary unresolvedTypeDict; + readonly Dictionary unresolvedTypeDict; readonly ConcurrentDictionary typeDict = new ConcurrentDictionary(); readonly INamespace rootNamespace; @@ -338,15 +338,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return assembly == this; } - public ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) + public ITypeDefinition GetTypeDefinition(TopLevelTypeName topLevelTypeName) { - var key = new FullNameAndTypeParameterCount(ns ?? string.Empty, name, typeParameterCount); - IUnresolvedTypeDefinition td; ITypeReference typeRef; - if (unresolvedAssembly.typeDefinitions.TryGetValue(key, out td)) + if (unresolvedAssembly.typeDefinitions.TryGetValue(topLevelTypeName, out td)) return GetTypeDefinition(td); - else if (unresolvedAssembly.typeForwarders.TryGetValue(key, out typeRef)) + else if (unresolvedAssembly.typeForwarders.TryGetValue(topLevelTypeName, out typeRef)) return typeRef.Resolve(compilation.TypeResolveContext).GetDefinition(); else return null; @@ -453,7 +451,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount) { - var key = new FullNameAndTypeParameterCount(ns.FullName, name, typeParameterCount); + var key = new TopLevelTypeName(ns.FullName, name, typeParameterCount); IUnresolvedTypeDefinition unresolvedTypeDef; if (assembly.unresolvedTypeDict.TryGetValue(key, out unresolvedTypeDef)) return assembly.GetTypeDefinition(unresolvedTypeDef); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs index 39c99cb4c9..42e7cefb03 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs @@ -141,24 +141,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } public override string ReflectionName { + get { + return this.FullTypeName.ReflectionName; + } + } + + public FullTypeName FullTypeName { get { IUnresolvedTypeDefinition declaringTypeDef = this.DeclaringTypeDefinition; if (declaringTypeDef != null) { - if (this.TypeParameters.Count > declaringTypeDef.TypeParameters.Count) { - return declaringTypeDef.ReflectionName + "+" + this.Name + "`" + (this.TypeParameters.Count - declaringTypeDef.TypeParameters.Count).ToString(CultureInfo.InvariantCulture); - } else { - return declaringTypeDef.ReflectionName + "+" + this.Name; - } - } else if (string.IsNullOrEmpty(namespaceName)) { - if (this.TypeParameters.Count > 0) - return this.Name + "`" + this.TypeParameters.Count.ToString(CultureInfo.InvariantCulture); - else - return this.Name; + return declaringTypeDef.FullTypeName.NestedType(this.Name, this.TypeParameters.Count - declaringTypeDef.TypeParameters.Count); } else { - if (this.TypeParameters.Count > 0) - return namespaceName + "." + this.Name + "`" + this.TypeParameters.Count.ToString(CultureInfo.InvariantCulture); - else - return namespaceName + "." + this.Name; + return new TopLevelTypeName(namespaceName, this.Name, this.TypeParameters.Count); } } } @@ -226,7 +220,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("context"); if (context.CurrentAssembly == null) throw new ArgumentException("An ITypeDefinition cannot be resolved in a context without a current assembly."); - return context.CurrentAssembly.GetTypeDefinition(this) + return context.CurrentAssembly.GetTypeDefinition(this.FullTypeName) ?? (IType)new UnknownType(this.Namespace, this.Name, this.TypeParameters.Count); } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs index 1057d9403f..6180328bf0 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs @@ -21,73 +21,8 @@ using System.Collections.Generic; namespace ICSharpCode.NRefactory.TypeSystem.Implementation { - [Serializable] - public struct FullNameAndTypeParameterCount : IEquatable + [Obsolete("This struct was renamed to 'TopLevelTypeName'.", true)] + public struct FullNameAndTypeParameterCount { - public readonly string Namespace; - public readonly string Name; - public readonly int TypeParameterCount; - - public FullNameAndTypeParameterCount(string nameSpace, string name, int typeParameterCount) - { - if (nameSpace == null) - throw new ArgumentNullException("nameSpace"); - if (name == null) - throw new ArgumentNullException("name"); - this.Namespace = nameSpace; - this.Name = name; - this.TypeParameterCount = typeParameterCount; - } - - public override bool Equals(object obj) - { - return (obj is FullNameAndTypeParameterCount) && Equals((FullNameAndTypeParameterCount)obj); - } - - public bool Equals(FullNameAndTypeParameterCount other) - { - return this.Namespace == other.Namespace && this.Name == other.Name && this.TypeParameterCount == other.TypeParameterCount; - } - - public override int GetHashCode() - { - return Name.GetHashCode() ^ Namespace.GetHashCode() ^ TypeParameterCount; - } - - public static bool operator ==(FullNameAndTypeParameterCount lhs, FullNameAndTypeParameterCount rhs) - { - return lhs.Equals(rhs); - } - - public static bool operator !=(FullNameAndTypeParameterCount lhs, FullNameAndTypeParameterCount rhs) - { - return !lhs.Equals(rhs); - } - } - - [Serializable] - public sealed class FullNameAndTypeParameterCountComparer : IEqualityComparer - { - public static readonly FullNameAndTypeParameterCountComparer Ordinal = new FullNameAndTypeParameterCountComparer(StringComparer.Ordinal); - public static readonly FullNameAndTypeParameterCountComparer OrdinalIgnoreCase = new FullNameAndTypeParameterCountComparer(StringComparer.OrdinalIgnoreCase); - - public readonly StringComparer NameComparer; - - public FullNameAndTypeParameterCountComparer(StringComparer nameComparer) - { - this.NameComparer = nameComparer; - } - - public bool Equals(FullNameAndTypeParameterCount x, FullNameAndTypeParameterCount y) - { - return x.TypeParameterCount == y.TypeParameterCount - && NameComparer.Equals(x.Name, y.Name) - && NameComparer.Equals(x.Namespace, y.Namespace); - } - - public int GetHashCode(FullNameAndTypeParameterCount obj) - { - return NameComparer.GetHashCode(obj.Name) ^ NameComparer.GetHashCode(obj.Namespace) ^ obj.TypeParameterCount; - } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs index e561b71acf..527eac9972 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetClassTypeReference.cs @@ -28,24 +28,31 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public sealed class GetClassTypeReference : ITypeReference, ISupportsInterning { readonly IAssemblyReference assembly; - readonly string nameSpace, name; - readonly int typeParameterCount; + readonly FullTypeName fullTypeName; /// - /// Creates a new GetClassTypeReference that searches a top-level type. + /// Creates a new GetClassTypeReference that searches a type definition. /// - /// The namespace name containing the type, e.g. "System.Collections.Generic". + /// The full name of the type. + /// A reference to the assembly containing this type. + /// If this parameter is null, the GetClassTypeReference will search in all + /// assemblies belonging to the compilation. + /// + public GetClassTypeReference(FullTypeName fullTypeName, IAssemblyReference assembly = null) + { + this.fullTypeName = fullTypeName; + this.assembly = assembly; + } + + /// + /// Creates a new GetClassTypeReference that searches a top-level type in all assemblies. + /// + /// The namespace name containing the type, e.g. "System.Collections.Generic". /// The name of the type, e.g. "List". /// The number of type parameters, (e.g. 1 for List<T>). - public GetClassTypeReference(string nameSpace, string name, int typeParameterCount = 0) + public GetClassTypeReference(string namespaceName, string name, int typeParameterCount = 0) { - if (nameSpace == null) - throw new ArgumentNullException("nameSpace"); - if (name == null) - throw new ArgumentNullException("name"); - this.nameSpace = nameSpace; - this.name = name; - this.typeParameterCount = typeParameterCount; + this.fullTypeName = new TopLevelTypeName(namespaceName, name, typeParameterCount); } /// @@ -53,25 +60,33 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// A reference to the assembly containing this type. /// If this parameter is null, the GetClassTypeReference will search in all assemblies belonging to the ICompilation. - /// The namespace name containing the type, e.g. "System.Collections.Generic". + /// The namespace name containing the type, e.g. "System.Collections.Generic". /// The name of the type, e.g. "List". /// The number of type parameters, (e.g. 1 for List<T>). - public GetClassTypeReference(IAssemblyReference assembly, string nameSpace, string name, int typeParameterCount = 0) + public GetClassTypeReference(IAssemblyReference assembly, string namespaceName, string name, int typeParameterCount = 0) { - if (nameSpace == null) - throw new ArgumentNullException("nameSpace"); - if (name == null) - throw new ArgumentNullException("name"); this.assembly = assembly; - this.nameSpace = nameSpace; - this.name = name; - this.typeParameterCount = typeParameterCount; + this.fullTypeName = new TopLevelTypeName(namespaceName, name, typeParameterCount); } + /// + /// Gets the assembly reference. + /// This property returns null if the GetClassTypeReference is searching in all assemblies + /// of the compilation. + /// public IAssemblyReference Assembly { get { return assembly; } } - public string Namespace { get { return nameSpace; } } - public string Name { get { return name; } } - public int TypeParameterCount { get { return typeParameterCount; } } + + /// + /// Gets the full name of the type this reference is searching for. + /// + public FullTypeName FullTypeName { get { return fullTypeName; } } + + [Obsolete("Use the FullTypeName property instead. GetClassTypeReference now supports nested types, where the Namespace/Name/TPC tripel isn't sufficient for identifying the type.")] + public string Namespace { get { return fullTypeName.TopLevelTypeName.Namespace; } } + [Obsolete("Use the FullTypeName property instead. GetClassTypeReference now supports nested types, where the Namespace/Name/TPC tripel isn't sufficient for identifying the type.")] + public string Name { get { return fullTypeName.Name; } } + [Obsolete("Use the FullTypeName property instead. GetClassTypeReference now supports nested types, where the Namespace/Name/TPC tripel isn't sufficient for identifying the type.")] + public int TypeParameterCount { get { return fullTypeName.TypeParameterCount; } } public IType Resolve(ITypeResolveContext context) { @@ -80,52 +95,42 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation IType type = null; if (assembly == 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 (context.CurrentAssembly != null) { + type = context.CurrentAssembly.GetTypeDefinition(fullTypeName); + } + if (type == null) { + var compilation = context.Compilation; + foreach (var asm in new[] { context.CurrentAssembly }.Concat(compilation.Assemblies)) { + type = asm.GetTypeDefinition(fullTypeName); if (type != null) - return type; + break; } } } else { IAssembly asm = assembly.Resolve(context); if (asm != null) { - type = asm.GetTypeDefinition(nameSpace, name, typeParameterCount); + type = asm.GetTypeDefinition(fullTypeName); } } - return type ?? new UnknownType(nameSpace, name, typeParameterCount); + return type ?? new UnknownType(fullTypeName); } public override string ToString() { - string asmSuffix = (assembly != null ? ", " + assembly.ToString() : null); - if (typeParameterCount == 0) - return BuildQualifiedName(nameSpace, name) + asmSuffix; - else - return BuildQualifiedName(nameSpace, name) + "`" + typeParameterCount + asmSuffix; - } - - static string BuildQualifiedName (string name1, string name2) - { - if (string.IsNullOrEmpty (name1)) - return name2; - if (string.IsNullOrEmpty (name2)) - return name1; - return name1 + "." + name2; + return fullTypeName.ToString() + (assembly != null ? ", " + assembly.ToString() : null); } int ISupportsInterning.GetHashCodeForInterning() { unchecked { - return 33 * assembly.GetHashCode() + 27 * nameSpace.GetHashCode() + name.GetHashCode() + typeParameterCount; + return 33 * assembly.GetHashCode() + fullTypeName.GetHashCode(); } } bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) { GetClassTypeReference o = other as GetClassTypeReference; - return o != null && assembly == o.assembly && name == o.name && nameSpace == o.nameSpace && typeParameterCount == o.typeParameterCount; + return o != null && assembly == o.assembly && fullTypeName == o.fullTypeName; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs index f17c4f2664..adcd1a8e34 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs @@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (typeRef == null) return SpecialType.UnknownType; foreach (IAssembly asm in compilation.Assemblies) { - var typeDef = asm.GetTypeDefinition(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount); + var typeDef = asm.GetTypeDefinition(new TopLevelTypeName(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount)); if (typeDef != null) return typeDef; } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/UnknownType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/UnknownType.cs index dc915306f3..3ae0b3d42b 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/UnknownType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/UnknownType.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Diagnostics; namespace ICSharpCode.NRefactory.TypeSystem.Implementation { @@ -26,9 +27,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation [Serializable] public class UnknownType : AbstractType, ITypeReference { - readonly string namespaceName; - readonly string name; - readonly int typeParameterCount; + readonly bool namespaceKnown; + readonly FullTypeName fullTypeName; /// /// Creates a new unknown type. @@ -40,9 +40,24 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation { if (name == null) throw new ArgumentNullException("name"); - this.namespaceName = namespaceName; - this.name = name; - this.typeParameterCount = typeParameterCount; + this.namespaceKnown = namespaceName != null; + this.fullTypeName = new TopLevelTypeName(namespaceName ?? string.Empty, name, typeParameterCount); + } + + /// + /// Creates a new unknown type. + /// + /// Full name of the unknown type. + public UnknownType(FullTypeName fullTypeName) + { + if (fullTypeName.Name == null) { + Debug.Assert(fullTypeName == default(FullTypeName)); + this.namespaceKnown = false; + this.fullTypeName = new TopLevelTypeName(string.Empty, "?", 0); + } else { + this.namespaceKnown = true; + this.fullTypeName = fullTypeName; + } } public override TypeKind Kind { @@ -62,15 +77,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } public override string Name { - get { return name; } + get { return fullTypeName.Name; } } public override string Namespace { - get { return namespaceName ?? string.Empty; } + get { return fullTypeName.TopLevelTypeName.Namespace; } } public override string ReflectionName { - get { return "?"; } + get { return namespaceKnown ? fullTypeName.ReflectionName : "?"; } + } + + public override int TypeParameterCount { + get { return fullTypeName.TypeParameterCount; } } public override bool? IsReferenceType { @@ -79,14 +98,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public override int GetHashCode() { - int hashCode = 0; - unchecked { - if (namespaceName != null) - hashCode += 1000000007 * namespaceName.GetHashCode(); - hashCode += 1000000009 * name.GetHashCode(); - hashCode += 1000000021 * typeParameterCount.GetHashCode(); - } - return hashCode; + return (namespaceKnown ? 812571 : 12651) ^ fullTypeName.GetHashCode(); } public override bool Equals(IType other) @@ -94,12 +106,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation UnknownType o = other as UnknownType; if (o == null) return false; - return this.namespaceName == o.namespaceName && this.name == o.name && this.typeParameterCount == o.typeParameterCount; + return this.namespaceKnown == o.namespaceKnown && this.fullTypeName == o.fullTypeName; } public override string ToString() { - return "[UnknownType " + this.FullName + "]"; + return "[UnknownType " + fullTypeName.ReflectionName + "]"; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs b/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs index 142b715990..cee12ff034 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs @@ -56,17 +56,6 @@ namespace ICSharpCode.NRefactory.TypeSystem { return type.ToTypeReference().Resolve(compilation.TypeResolveContext); } - - /// - /// Retrieves the specified type in this compilation. - /// Returns if the type cannot be found in this compilation. - /// - [Obsolete("Use ReflectionHelper.ParseReflectionName(reflectionTypeName).Resolve(compilation.TypeResolveContext) instead. " + - "Make sure to read the ParseReflectionName() documentation for caveats.")] - public static IType FindType(this ICompilation compilation, string reflectionTypeName) - { - return ParseReflectionName(reflectionTypeName).Resolve(compilation.TypeResolveContext); - } #endregion #region Type.ToTypeReference() @@ -218,6 +207,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// first, and if the type is not found there, /// it will look in all other assemblies of the compilation. /// + /// public static ITypeReference ParseReflectionName(string reflectionTypeName) { if (reflectionTypeName == null) diff --git a/ICSharpCode.NRefactory/TypeSystem/TopLevelTypeName.cs b/ICSharpCode.NRefactory/TypeSystem/TopLevelTypeName.cs new file mode 100644 index 0000000000..00fd98d303 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/TopLevelTypeName.cs @@ -0,0 +1,144 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + /// + /// Holds the name of a top-level type. + /// This struct cannot refer to nested classes. + /// + [Serializable] + public struct TopLevelTypeName : IEquatable + { + readonly string namespaceName; + readonly string name; + readonly int typeParameterCount; + + public TopLevelTypeName(string namespaceName, string name, int typeParameterCount = 0) + { + if (namespaceName == null) + throw new ArgumentNullException("namespaceName"); + if (name == null) + throw new ArgumentNullException("name"); + this.namespaceName = namespaceName; + this.name = name; + this.typeParameterCount = typeParameterCount; + } + + public TopLevelTypeName(string reflectionName) + { + int pos = reflectionName.LastIndexOf('.'); + if (pos < 0) { + namespaceName = string.Empty; + name = reflectionName; + } else { + namespaceName = reflectionName.Substring(0, pos); + name = reflectionName.Substring(pos + 1); + } + name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name, out typeParameterCount); + } + + public string Namespace { + get { return namespaceName; } + } + + public string Name { + get { return name; } + } + + public int TypeParameterCount { + get { return typeParameterCount; } + } + + public string ReflectionName { + get { + StringBuilder b = new StringBuilder(); + if (!string.IsNullOrEmpty(namespaceName)) { + b.Append(namespaceName); + b.Append('.'); + } + b.Append(name); + if (typeParameterCount > 0) { + b.Append('`'); + b.Append(typeParameterCount); + } + return b.ToString(); + } + } + + public override string ToString() + { + return this.ReflectionName; + } + + public override bool Equals(object obj) + { + return (obj is TopLevelTypeName) && Equals((TopLevelTypeName)obj); + } + + public bool Equals(TopLevelTypeName other) + { + return this.namespaceName == other.namespaceName && this.name == other.name && this.typeParameterCount == other.typeParameterCount; + } + + public override int GetHashCode() + { + return (name != null ? name.GetHashCode() : 0) ^ (namespaceName != null ? namespaceName.GetHashCode() : 0) ^ typeParameterCount; + } + + public static bool operator ==(TopLevelTypeName lhs, TopLevelTypeName rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(TopLevelTypeName lhs, TopLevelTypeName rhs) + { + return !lhs.Equals(rhs); + } + } + + [Serializable] + public sealed class TopLevelTypeNameComparer : IEqualityComparer + { + public static readonly TopLevelTypeNameComparer Ordinal = new TopLevelTypeNameComparer(StringComparer.Ordinal); + public static readonly TopLevelTypeNameComparer OrdinalIgnoreCase = new TopLevelTypeNameComparer(StringComparer.OrdinalIgnoreCase); + + public readonly StringComparer NameComparer; + + public TopLevelTypeNameComparer(StringComparer nameComparer) + { + this.NameComparer = nameComparer; + } + + public bool Equals(TopLevelTypeName x, TopLevelTypeName y) + { + return x.TypeParameterCount == y.TypeParameterCount + && NameComparer.Equals(x.Name, y.Name) + && NameComparer.Equals(x.Namespace, y.Namespace); + } + + public int GetHashCode(TopLevelTypeName obj) + { + return NameComparer.GetHashCode(obj.Name) ^ NameComparer.GetHashCode(obj.Namespace) ^ obj.TypeParameterCount; + } + } +}