// 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.Linq; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Resolver { [TestFixture] public class NameLookupTests : ResolverTestBase { CSharpResolver resolver; public override void SetUp() { base.SetUp(); resolver = new CSharpResolver(compilation).WithCurrentUsingScope(MakeUsingScope(string.Empty)); } ResolvedUsingScope MakeUsingScope(string namespaceName = "", string[] usings = null, KeyValuePair[] usingAliases = null) { UsingScope usingScope = new UsingScope(); if (!string.IsNullOrEmpty(namespaceName)) { foreach (string element in namespaceName.Split('.')) { usingScope = new UsingScope(usingScope, string.IsNullOrEmpty(usingScope.NamespaceName) ? element : usingScope.NamespaceName + "." + element); } } if (usings != null) { foreach (string u in usings) usingScope.Usings.Add(MakeReference(u)); } if (usingAliases != null) { foreach (var pair in usingAliases) usingScope.UsingAliases.Add(new KeyValuePair(pair.Key, MakeReference(pair.Value))); } return usingScope.Resolve(compilation); } [Test] public void SimpleNameLookupWithoutContext() { // without any using scope, we still want to find elements of the global namespace: var nrr = (NamespaceResolveResult)resolver.WithCurrentUsingScope(null).ResolveSimpleName("System", new IType[0]); Assert.AreEqual("System", nrr.NamespaceName); } [Test] public void SimpleNamespaceLookup() { NamespaceResolveResult nrr = (NamespaceResolveResult)resolver.ResolveSimpleName("System", new IType[0]); Assert.AreEqual("System", nrr.NamespaceName); Assert.AreSame(SpecialType.UnknownType, nrr.Type); } [Test] public void NamespaceInParentNamespaceLookup() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope("System.Collections.Generic")); NamespaceResolveResult nrr = (NamespaceResolveResult)resolverWithUsing.ResolveSimpleName("Text", new IType[0]); Assert.AreEqual("System.Text", nrr.NamespaceName); } [Test] public void NamespacesAreNotImported() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope(usings: new [] { "System" })); Assert.IsTrue(resolverWithUsing.ResolveSimpleName("Collections", new IType[0]).IsError); } [Test] public void ImportedType() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope(usings: new [] { "System" })); TypeResolveResult trr = (TypeResolveResult)resolverWithUsing.ResolveSimpleName("String", new IType[0]); Assert.AreEqual("System.String", trr.Type.FullName); } [Test] public void UnknownIdentifierTest() { UnknownIdentifierResolveResult uirr = (UnknownIdentifierResolveResult)resolver.ResolveSimpleName("xyz", new IType[0]); Assert.IsTrue(uirr.IsError); Assert.AreEqual("xyz", uirr.Identifier); } [Test] public void GlobalIsUnknownIdentifier() { Assert.IsTrue(resolver.ResolveSimpleName("global", new IType[0]).IsError); } [Test] public void GlobalIsAlias() { NamespaceResolveResult nrr = (NamespaceResolveResult)resolver.ResolveAlias("global"); Assert.AreEqual("", nrr.NamespaceName); } [Test] public void AliasToImportedType() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope(usings: new [] { "System" }, usingAliases: new [] { new KeyValuePair( "x", "String" )})); UnknownIdentifierResolveResult rr = (UnknownIdentifierResolveResult)resolverWithUsing.ResolveSimpleName("x", new IType[0]); // Unknown identifier (as String isn't looked up in System) Assert.AreEqual("String", rr.Identifier); } [Test] public void AliasToImportedType2() { UsingScope mainUsingScope = new UsingScope(); mainUsingScope.Usings.Add(MakeReference("System")); UsingScope nestedUsingScope = new UsingScope(mainUsingScope, "SomeNamespace"); nestedUsingScope.UsingAliases.Add(new KeyValuePair("x", MakeReference("String"))); var resolverWithUsing = resolver.WithCurrentUsingScope(nestedUsingScope.Resolve(compilation)); TypeResolveResult trr = (TypeResolveResult)resolverWithUsing.ResolveSimpleName("x", new IType[0]); Assert.AreEqual("System.String", trr.Type.FullName); } [Test] public void AliasOperatorOnTypeAlias() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope(usingAliases: new [] { new KeyValuePair( "x", "System.String" )})); Assert.IsTrue(resolverWithUsing.ResolveAlias("x").IsError); } [Test] public void AliasOperatorOnNamespaceAlias() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope(usingAliases: new [] { new KeyValuePair( "x", "System.Collections.Generic" )})); NamespaceResolveResult nrr = (NamespaceResolveResult)resolverWithUsing.ResolveAlias("x"); Assert.AreEqual("System.Collections.Generic", nrr.NamespaceName); } [Test] public void AliasOperatorOnNamespace() { Assert.IsTrue(resolver.ResolveAlias("System").IsError); } [Test] public void FindClassInCurrentNamespace() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope("System.Collections")); TypeResolveResult trr = (TypeResolveResult)resolverWithUsing.ResolveSimpleName("String", new IType[0]); Assert.AreEqual("System.String", trr.Type.FullName); } [Test] public void FindNeighborNamespace() { var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope("System.Collections")); NamespaceResolveResult nrr = (NamespaceResolveResult)resolverWithUsing.ResolveSimpleName("Text", new IType[0]); Assert.AreEqual("System.Text", nrr.NamespaceName); } [Test] public void FindTypeParameters() { var listOfT = compilation.FindType(typeof(List<>)).GetDefinition(); var resolverWithContext = resolver .WithCurrentUsingScope(MakeUsingScope("System.Collections.Generic")) .WithCurrentTypeDefinition(listOfT) .WithCurrentMember(listOfT.Methods.Single(m => m.Name == "ConvertAll")); TypeResolveResult trr; trr = (TypeResolveResult)resolverWithContext.ResolveSimpleName("TOutput", new IType[0]); Assert.AreSame(((IMethod)resolverWithContext.CurrentMember).TypeParameters[0], trr.Type); trr = (TypeResolveResult)resolverWithContext.ResolveSimpleName("T", new IType[0]); Assert.AreSame(resolverWithContext.CurrentTypeDefinition.TypeParameters[0], trr.Type); } [Test] public void SimpleParameter() { string program = @"class A { void Method(string a) { string b = $a$; } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("a", result.Variable.Name); Assert.IsTrue(result.IsParameter); Assert.AreEqual("System.String", result.Type.FullName); } [Test] public void SimpleLocalVariable() { string program = @"class A { void Method() { string a; string b = $a$; } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("a", result.Variable.Name); Assert.IsFalse(result.IsParameter); Assert.AreEqual("System.String", result.Type.FullName); } [Test] public void UnknownTypeTest() { string program = @"class A { void Method($StringBuilder$ b) { } } "; UnknownIdentifierResolveResult result = Resolve(program); Assert.AreEqual("StringBuilder", result.Identifier); Assert.AreSame(SpecialType.UnknownType, result.Type); } const string propertyNameAmbiguousWithTypeNameProgram = @"class A { public Color Color { get; set; } void Method() { $ } } class Color { public static readonly Color Empty = null; public static int M() { } public int M(int a) { } } "; [Test] public void PropertyNameAmbiguousWithTypeName() { string program = propertyNameAmbiguousWithTypeNameProgram; TypeResolveResult trr = Resolve(program.Replace("$", "$Color$ c;")); Assert.AreEqual("Color", trr.Type.Name); MemberResolveResult mrr = Resolve(program.Replace("$", "x = $Color$;")); Assert.AreEqual("Color", mrr.Member.Name); } [Test] public void PropertyNameAmbiguousWithTypeName_MemberAccessOnAmbiguousIdentifier() { string program = propertyNameAmbiguousWithTypeNameProgram; Resolve(program.Replace("$", "$Color$ = Color.Empty;")); Resolve(program.Replace("$", "Color = $Color$.Empty;")); } [Test] public void PropertyNameAmbiguousWithTypeName_MethodInvocationOnAmbiguousIdentifier() { string program = propertyNameAmbiguousWithTypeNameProgram; Resolve(program.Replace("$", "x = $Color$.M(1);")); Resolve(program.Replace("$", "x = $Color$.M();")); } [Test] public void ValueInsideSetterTest() { string program = @"class A { public string Property { set { var a = $value$; } } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("System.String", result.Type.FullName); Assert.AreEqual("value", result.Variable.Name); } [Test] public void ValueInsideEventTest() { string program = @"using System; class A { public event EventHandler Ev { add { var a = $value$; } remove {} } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("System.EventHandler", result.Type.FullName); Assert.AreEqual("value", result.Variable.Name); } [Test] public void ValueInsideIndexerSetterTest() { string program = @"using System; class A { public string this[int arg] { set { var a = $value$; } } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("System.String", result.Type.FullName); Assert.AreEqual("value", result.Variable.Name); } [Test] public void AnonymousMethodParameters() { string program = @"using System; class A { void Method() { SomeEvent += delegate(object sender, EventArgs e) { $e$.ToString(); }; } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("System.EventArgs", result.Type.FullName); Assert.AreEqual("e", result.Variable.Name); } [Test] public void DefaultTypeCSharp() { string program = @"class A { void Method() { $int$ a; } } "; TypeResolveResult result = Resolve(program); Assert.AreEqual("System.Int32", result.Type.FullName); } [Test] public void LoopVariableScopeTest() { string program = @"using System; class TestClass { void Test() { for (int i = 0; i < 10; i++) { $1$.ToString(); } for (long i = 0; i < 10; i++) { $2$.ToString(); } } } "; LocalResolveResult lr = Resolve(program.Replace("$1$", "$i$").Replace("$2$", "i")); Assert.AreEqual("System.Int32", lr.Type.ReflectionName); lr = Resolve(program.Replace("$1$", "i").Replace("$2$", "$i$")); Assert.AreEqual("System.Int64", lr.Type.ReflectionName); } [Test] public void NamespacePreferenceTest() { // Classes in the current namespace are preferred over classes from // imported namespaces string program = @"using System; namespace Testnamespace { class A { $Activator$ a; } class Activator { } } "; var result = Resolve(program); Assert.AreEqual("Testnamespace.Activator", result.Type.FullName); } [Test] public void ParentNamespaceTypeLookup() { string program = @"using System; namespace Root { class Alpha {} } namespace Root.Child { class Beta { $Alpha$ a; } } "; var result = Resolve(program); Assert.AreEqual("Root.Alpha", result.Type.FullName); } [Test] public void ImportAliasTest() { string program = @"using COL = System.Collections; class TestClass { COL.ArrayList ff; } "; TypeResolveResult type = Resolve(program.Replace("COL.ArrayList", "$COL.ArrayList$")); Assert.IsNotNull(type, "COL.ArrayList should resolve to a type"); Assert.AreEqual("System.Collections.ArrayList", type.Type.FullName, "TypeResolveResult"); MemberResolveResult member = Resolve(program.Replace("ff", "$ff$")); Assert.AreEqual("System.Collections.ArrayList", member.Type.FullName, "the full type should be resolved"); } [Test] public void ImportAliasNamespaceResolveTest() { NamespaceResolveResult ns; string program = "using COL = System.Collections;\r\nclass A {\r\n$.ArrayList a;\r\n}\r\n"; ns = Resolve(program.Replace("$", "$COL$")); Assert.AreEqual("System.Collections", ns.NamespaceName, "COL"); ns = Resolve(program.Replace("$", "$COL.Generic$")); Assert.AreEqual("System.Collections.Generic", ns.NamespaceName, "COL.Generic"); } [Test] public void ImportAliasClassResolveTest() { string program = @"using COL = System.Collections.ArrayList; class TestClass { void Test() { COL a = new COL(); } } "; TypeResolveResult trr = Resolve(program.Replace("COL a", "$COL$ a")); Assert.AreEqual("System.Collections.ArrayList", trr.Type.FullName, "COL"); ResolveResult rr = Resolve(program.Replace("new COL()", "$new COL()$")); Assert.AreEqual("System.Collections.ArrayList", rr.Type.FullName, "a"); } [Test] public void ImportSubnamespaceWithAliasTest() { string program = @"namespace PC { // Define an alias for the nested namespace. using Project = PC.MyCompany.Project; class A { Project.MyClass M() { // Use the alias $Project.MyClass$ mc = new Project.MyClass(); return mc; } } namespace MyCompany { namespace Project { public class MyClass { } } } } "; var mrr = Resolve(program); Assert.AreEqual("PC.MyCompany.Project.MyClass", mrr.Type.FullName); } [Test] public void ResolveNamespaceSD_863() { string program = @"using System; namespace A.C { class D {} } namespace A.B.C { class D {} } namespace A.B { class TestClass { void Test() { C.D x; } } } "; NamespaceResolveResult nrr = Resolve(program.Replace("C.D", "$C$.D")); Assert.AreEqual("A.B.C", nrr.NamespaceName, "nrr.Name"); TypeResolveResult trr = Resolve(program.Replace("C.D", "$C.D$")); Assert.AreEqual("A.B.C.D", trr.Type.FullName); } [Test] public void ResolveTypeSD_863() { string program = @"using System; namespace A { class C {} } namespace A.B { class C {} class TestClass { void Test() { $C$ a; } } } "; TypeResolveResult trr = Resolve(program); Assert.AreEqual("A.B.C", trr.Type.FullName); } [Test] public void InnerTypeResolve1 () { string program = @"public class C { public class Inner { } } class TestClass { void Test() { $C.Inner$ a; } } "; TypeResolveResult trr = Resolve(program); Assert.AreEqual("C.Inner", trr.Type.FullName); } [Test] public void InnerTypeResolve2 () { string program = @"public class C { public class D { public class Inner { } }} class TestClass { void Test() { $C.D.Inner$ a; } } "; TypeResolveResult trr = Resolve(program); Assert.AreEqual("C.D.Inner", trr.Type.FullName); } [Test] public void ShortMaxValueTest() { string program = @"using System; class TestClass { object a = $short.MaxValue$; } "; MemberResolveResult rr = Resolve(program); Assert.AreEqual("System.Int16", rr.Type.FullName); Assert.AreEqual("System.Int16.MaxValue", rr.Member.FullName); Assert.AreEqual(short.MaxValue, rr.ConstantValue); } [Test] public void ClassWithSameNameAsNamespace() { string program = @"using System; namespace XX { class Test { static void X() { a = $; } } class XX { public static void Test() {} } }"; TypeResolveResult trr = Resolve(program.Replace("$", "$XX$")); Assert.AreEqual("XX.XX", trr.Type.FullName); NamespaceResolveResult nrr = Resolve(program.Replace("$", "$global::XX$.T")); Assert.AreEqual("XX", nrr.NamespaceName); trr = Resolve(program.Replace("$", "$global::XX.XX$")); Assert.AreEqual("XX.XX", trr.Type.FullName); InvocationResolveResult mrr = Resolve(program.Replace("$", "$XX.Test()$")); Assert.AreEqual("XX.XX.Test", mrr.Member.FullName); } [Test] public void ClassNameLookup1() { string program = @"namespace MainNamespace { using Test.Subnamespace; class Program { static void M($Test.TheClass$ c) {} } } namespace Test { public class TheClass { } } namespace Test.Subnamespace { public class Test { public class TheClass { } } } "; TypeResolveResult trr = Resolve(program); Assert.AreEqual("Test.Subnamespace.Test.TheClass", trr.Type.FullName); } [Test] public void ClassNameLookup2() { string program = @"using Test.Subnamespace; namespace MainNamespace { class Program { static void M($Test.TheClass$ c) {} } } namespace Test { public class TheClass { } } namespace Test.Subnamespace { public class Test { public class TheClass { } } } "; TypeResolveResult trr = Resolve(program); Assert.AreEqual("Test.TheClass", trr.Type.FullName); } [Test] public void ClassNameLookup3() { string program = @"namespace MainNamespace { using Test.Subnamespace; class Program { static void M($Test$ c) {} } } namespace Test { public class TheClass { } } namespace Test.Subnamespace { public class Test { public class TheClass { } } } "; TypeResolveResult trr = Resolve(program); Assert.AreEqual("Test.Subnamespace.Test", trr.Type.FullName); } [Test] public void ClassNameLookup4() { string program = @"using Test.Subnamespace; namespace MainNamespace { class Program { static void M($Test$ c) {} } } namespace Test { public class TheClass { } } namespace Test.Subnamespace { public class Test { public class TheClass { } } } "; NamespaceResolveResult nrr = Resolve(program); Assert.AreEqual("Test", nrr.NamespaceName); } [Test] public void ClassNameLookup5() { string program = @"namespace MainNamespace { using A; class M { void X($Test$ a) {} } namespace Test { class B {} } } namespace A { class Test {} }"; NamespaceResolveResult nrr = Resolve(program); Assert.AreEqual("MainNamespace.Test", nrr.NamespaceName); } [Test] public void InvocableRule() { string program = @"using System; class DerivedClass : BaseClass { static void X() { a = $; } private static new int Test; } class BaseClass { public static string Test() {} }"; MemberResolveResult mrr = Resolve(program.Replace("$", "$BaseClass.Test()$")); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); mrr = Resolve(program.Replace("$", "$Test$")); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); mrr = Resolve(program.Replace("$", "$DerivedClass.Test$")); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); // returns BaseClass.Test because DerivedClass.Test is not invocable mrr = Resolve(program.Replace("$", "$DerivedClass.Test()$")); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); } [Test] public void InvocableRule2() { string program = @"using System; class DerivedClass : BaseClass { static void X() { a = $; } private static new int Test; } delegate string SomeDelegate(); class BaseClass { public static SomeDelegate Test; }"; MemberResolveResult mrr = Resolve(program.Replace("$", "$BaseClass.Test$()")); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); mrr = Resolve(program.Replace("$", "$Test$")); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); mrr = Resolve(program.Replace("$", "$DerivedClass.Test$")); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); // returns BaseClass.Test because DerivedClass.Test is not invocable mrr = Resolve(program.Replace("$", "$DerivedClass.Test$()")); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); } [Test] public void AccessibleRule() { string program = @"using System; class BaseClass { static void X() { a = $DerivedClass.Test$; } public static int Test; } class DerivedClass : BaseClass { private static new int Test; } "; // returns BaseClass.Test because DerivedClass.Test is not accessible MemberResolveResult mrr = Resolve(program); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); } [Test] public void FieldHidingProperty() { string program = @"using System; class DerivedClass : BaseClass { static void X() { a = $Test$; } public static new int Test; } class BaseClass { public static int Test { get { return 0; } } } "; MemberResolveResult mrr = Resolve(program); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); } [Test] public void PropertyHidingField() { string program = @"using System; class DerivedClass : BaseClass { static void X() { a = $Test$; } public static new int Test { get { return 0; } } } class BaseClass { public static int Test; } "; MemberResolveResult mrr = Resolve(program); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); } [Test] public void SD_1487() { string program = @"using System; class C2 : C1 { public static void M() { a = $; } } class C1 { protected static int Field; }"; MemberResolveResult mrr; mrr = Resolve(program.Replace("$", "$Field$")); Assert.IsFalse(mrr.IsError); Assert.AreEqual("C1.Field", mrr.Member.FullName); mrr = Resolve(program.Replace("$", "$C1.Field$")); Assert.IsFalse(mrr.IsError); Assert.AreEqual("C1.Field", mrr.Member.FullName); mrr = Resolve(program.Replace("$", "$C2.Field$")); Assert.IsFalse(mrr.IsError); Assert.AreEqual("C1.Field", mrr.Member.FullName); } [Test] public void NullableValue() { string program = @"using System; class Test { public static void M(int? a) { $a.Value$.ToString(); } }"; MemberResolveResult rr = Resolve(program); Assert.AreEqual("System.Nullable.Value", rr.Member.FullName); Assert.AreEqual("System.Int32", rr.Member.ReturnType.FullName); } [Test] public void MethodHidesEvent() { // see SD-1542 string program = @"using System; class Test : Form { public Test() { a = $base.KeyDown$; } void KeyDown(object sender, EventArgs e) {} } class Form { public event EventHandler KeyDown; }"; var mrr = Resolve(program); Assert.AreEqual("Form.KeyDown", mrr.Member.FullName); var mgrr = Resolve(program.Replace("base", "this")); Assert.AreEqual("Test.KeyDown", mgrr.Methods.Single().FullName); } [Test] public void ProtectedMemberVisibleWhenBaseTypeReferenceIsInOtherPart() { string program = @"using System; partial class A { void M1() { $x$ = 0; } } partial class A : B { } class B { protected int x; }"; var mrr = Resolve(program); Assert.AreEqual("B.x", mrr.Member.FullName); } [Test] public void SubstituteClassAndMethodTypeParametersAtOnce() { string program = @"class C { static void M(X a, T b) { $C.M$(b, a); } }"; var rr = Resolve(program); Assert.AreEqual("X", rr.TypeArguments.Single().Name); var m = (SpecializedMethod)rr.Methods.Single(); Assert.AreSame(rr.TypeArguments.Single(), m.TypeArguments.Single()); Assert.AreEqual("T", m.Parameters[0].Type.Name); Assert.AreEqual("X", m.Parameters[1].Type.Name); } [Test] public void InheritingInnerClassShouldNotCauseStackOverflow() { string program = @"class Test : $Test.Base$, Test.ITest { public class Base {} interface ITest {} }"; var result = Resolve(program); Assert.AreEqual("Test.Base", result.Type.FullName); } [Test] public void InnerClassInheritingFromProtectedBaseInnerClassShouldNotCauseStackOverflow() { string program = @"class Base { protected class NestedBase {} } class Derived : Base { class NestedDerived : $NestedBase$ { } }"; var result = Resolve(program); Assert.AreEqual("Base.NestedBase", result.Type.FullName); } [Test] public void EnumMembersHaveUnderlyingTypeWithinInitializers_MemberFromSameEnum() { string program = @"enum E { A = 0, B = $A$ + 1 }"; var result = Resolve(program); Assert.AreEqual("E.A", result.Member.FullName); Assert.AreEqual("System.Int32", result.Type.ReflectionName); Assert.AreEqual("E", result.Member.ReturnType.ReflectionName); } [Test] public void EnumMembersHaveUnderlyingTypeWithinInitializers_MemberFromOtherEnum() { string program = @"enum A : ushort { X = 1 } enum B { Y = $A.X$ }"; var result = Resolve(program); Assert.AreEqual("A.X", result.Member.FullName); Assert.AreEqual("System.UInt16", result.Type.ReflectionName); Assert.AreEqual("A", result.Member.ReturnType.ReflectionName); } [Test] public void EnumMembersHaveUnderlyingTypeWithinInitializers_RuleDoesNotApplyToAttributes() { string program = @"enum A { X = 1, [SomeAttribute($X$)] Y }"; var result = Resolve(program); Assert.AreEqual("A.X", result.Member.FullName); Assert.AreEqual("A", result.Type.ReflectionName); } [Test] public void InheritFromProtectedInnerClassTest() { string program = @" class Test { protected class Foo { public int Bar = 0; } } class MainClass : Test { class Foo2 : Test.Foo { public Foo2 () { Console.WriteLine ($Bar$); } } } "; var result = Resolve(program); Assert.IsFalse(result.IsError); Assert.AreEqual("Test.Foo.Bar", result.Member.FullName); } [Test] public void LocalInsideUnsafeBlock() { string program = @"class A { void Method() { unsafe { string a; string b = $a$; } } } "; LocalResolveResult result = Resolve(program); Assert.AreEqual("a", result.Variable.Name); Assert.IsFalse(result.IsParameter); Assert.AreEqual("System.String", result.Type.FullName); } [Test] public void DuplicateUsingDirective() { string program = @" using foo; using foo; namespace bar { using foo; using foo; public class Bar { public void M() { new $Foo$(); } } } namespace foo { public class Foo { } }"; var result = Resolve(program); Assert.IsFalse(result.IsError); Assert.AreEqual("foo.Foo", result.Type.FullName); } [Test] public void BaseTypeReference_refers_to_outer_type() { string program = @"class B {} class A : $B$ { class B {} }"; var result = Resolve(program); Assert.IsFalse(result.IsError); Assert.AreEqual("B", result.Type.FullName); // also check if the reference in the type system is correct var a = ((ITypeDefinition)result.Type).Compilation.RootNamespace.GetTypeDefinition("A", 0); Assert.AreEqual("B", a.DirectBaseTypes.Single().FullName); } [Test] public void Class_constraint_refers_to_outer_type() { string program = @"class B {} class A where T : $B$ { class B {} }"; var result = Resolve(program); Assert.IsFalse(result.IsError); Assert.AreEqual("B", result.Type.FullName); // also check if the reference in the type system is correct var a = ((ITypeDefinition)result.Type).Compilation.RootNamespace.GetTypeDefinition("A", 1); Assert.AreEqual("B", a.TypeParameters.Single().DirectBaseTypes.Single().FullName); } [Test] public void Method_constraint_refers_to_inner_type() { string program = @"class B {} class A { void M() where T : $B$ {} class B {} }"; var result = Resolve(program); Assert.IsFalse(result.IsError); Assert.AreEqual("A.B", result.Type.FullName); // also check if the reference in the type system is correct var a = ((ITypeDefinition)result.Type).Compilation.RootNamespace.GetTypeDefinition("A", 0); var method = a.Methods.Single(m => m.Name == "M"); Assert.AreEqual("A.B", method.TypeParameters.Single().DirectBaseTypes.Single().FullName); } [Test] public void EmptyNamespaces() { // should maybe a typesystem test - but empty namespaces don't make sense in cecil. string program = @"namespace A.B.C.D { } namespace Test { using $A.B.C.D$; public class C { public static void Main () { } } } "; var nrr = Resolve(program); Assert.AreEqual("A.B.C.D", nrr.NamespaceName); } } }