#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1097 lines
30 KiB

// 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<string, string>[] 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<string, TypeOrNamespaceReference>(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<string, string>( "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<string, TypeOrNamespaceReference>("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<string, string>( "x", "System.String" )}));
Assert.IsTrue(resolverWithUsing.ResolveAlias("x").IsError);
}
[Test]
public void AliasOperatorOnNamespaceAlias()
{
var resolverWithUsing = resolver.WithCurrentUsingScope(MakeUsingScope(usingAliases: new [] { new KeyValuePair<string, string>( "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<LocalResolveResult>(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<LocalResolveResult>(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<UnknownIdentifierResolveResult>(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<TypeResolveResult>(program.Replace("$", "$Color$ c;"));
Assert.AreEqual("Color", trr.Type.Name);
MemberResolveResult mrr = Resolve<MemberResolveResult>(program.Replace("$", "x = $Color$;"));
Assert.AreEqual("Color", mrr.Member.Name);
}
[Test]
public void PropertyNameAmbiguousWithTypeName_MemberAccessOnAmbiguousIdentifier()
{
string program = propertyNameAmbiguousWithTypeNameProgram;
Resolve<MemberResolveResult>(program.Replace("$", "$Color$ = Color.Empty;"));
Resolve<TypeResolveResult>(program.Replace("$", "Color = $Color$.Empty;"));
}
[Test]
public void PropertyNameAmbiguousWithTypeName_MethodInvocationOnAmbiguousIdentifier()
{
string program = propertyNameAmbiguousWithTypeNameProgram;
Resolve<MemberResolveResult>(program.Replace("$", "x = $Color$.M(1);"));
Resolve<TypeResolveResult>(program.Replace("$", "x = $Color$.M();"));
}
[Test]
public void ValueInsideSetterTest()
{
string program = @"class A {
public string Property {
set {
var a = $value$;
}
}
}
";
LocalResolveResult result = Resolve<LocalResolveResult>(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<LocalResolveResult>(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<LocalResolveResult>(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<LocalResolveResult>(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<TypeResolveResult>(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<LocalResolveResult>(program.Replace("$1$", "$i$").Replace("$2$", "i"));
Assert.AreEqual("System.Int32", lr.Type.ReflectionName);
lr = Resolve<LocalResolveResult>(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<TypeResolveResult>(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<TypeResolveResult>(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<TypeResolveResult>(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<MemberResolveResult>(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<AliasNamespaceResolveResult>(program.Replace("$", "$COL$"));
Assert.AreEqual("System.Collections", ns.NamespaceName, "COL");
ns = Resolve<NamespaceResolveResult>(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<AliasTypeResolveResult>(program.Replace("COL a", "$COL$ a"));
Assert.AreEqual("System.Collections.ArrayList", trr.Type.FullName, "COL");
ResolveResult rr = Resolve<CSharpInvocationResolveResult>(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<NamespaceResolveResult>(program.Replace("C.D", "$C$.D"));
Assert.AreEqual("A.B.C", nrr.NamespaceName, "nrr.Name");
TypeResolveResult trr = Resolve<TypeResolveResult>(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<TypeResolveResult>(program);
Assert.AreEqual("A.B.C", trr.Type.FullName);
}
[Test]
public void InnerTypeResolve1 ()
{
string program = @"public class C<T> { public class Inner { } }
class TestClass {
void Test() {
$C<string>.Inner$ a;
}
}
";
TypeResolveResult trr = Resolve<TypeResolveResult>(program);
Assert.AreEqual("C.Inner", trr.Type.FullName);
}
[Test]
public void InnerTypeResolve2 ()
{
string program = @"public class C<T> { public class D<S,U> { public class Inner { } }}
class TestClass {
void Test() {
$C<string>.D<int,TestClass>.Inner$ a;
}
}
";
TypeResolveResult trr = Resolve<TypeResolveResult>(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<MemberResolveResult>(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<TypeResolveResult>(program.Replace("$", "$XX$"));
Assert.AreEqual("XX.XX", trr.Type.FullName);
NamespaceResolveResult nrr = Resolve<NamespaceResolveResult>(program.Replace("$", "$global::XX$.T"));
Assert.AreEqual("XX", nrr.NamespaceName);
trr = Resolve<TypeResolveResult>(program.Replace("$", "$global::XX.XX$"));
Assert.AreEqual("XX.XX", trr.Type.FullName);
InvocationResolveResult mrr = Resolve<CSharpInvocationResolveResult>(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<TypeResolveResult>(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<TypeResolveResult>(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<TypeResolveResult>(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<NamespaceResolveResult>(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<NamespaceResolveResult>(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<CSharpInvocationResolveResult>(program.Replace("$", "$BaseClass.Test()$"));
Assert.AreEqual("BaseClass.Test", mrr.Member.FullName);
mrr = Resolve<MemberResolveResult>(program.Replace("$", "$Test$"));
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
mrr = Resolve<MemberResolveResult>(program.Replace("$", "$DerivedClass.Test$"));
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
// returns BaseClass.Test because DerivedClass.Test is not invocable
mrr = Resolve<CSharpInvocationResolveResult>(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<MemberResolveResult>(program.Replace("$", "$BaseClass.Test$()"));
Assert.AreEqual("BaseClass.Test", mrr.Member.FullName);
mrr = Resolve<MemberResolveResult>(program.Replace("$", "$Test$"));
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
mrr = Resolve<MemberResolveResult>(program.Replace("$", "$DerivedClass.Test$"));
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
// returns BaseClass.Test because DerivedClass.Test is not invocable
mrr = Resolve<MemberResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(program.Replace("$", "$Field$"));
Assert.IsFalse(mrr.IsError);
Assert.AreEqual("C1.Field", mrr.Member.FullName);
mrr = Resolve<MemberResolveResult>(program.Replace("$", "$C1.Field$"));
Assert.IsFalse(mrr.IsError);
Assert.AreEqual("C1.Field", mrr.Member.FullName);
mrr = Resolve<MemberResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(program);
Assert.AreEqual("Form.KeyDown", mrr.Member.FullName);
var mgrr = Resolve<MethodGroupResolveResult>(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<MemberResolveResult>(program);
Assert.AreEqual("B.x", mrr.Member.FullName);
}
[Test]
public void SubstituteClassAndMethodTypeParametersAtOnce()
{
string program = @"class C<X> { static void M<T>(X a, T b) { $C<T>.M<X>$(b, a); } }";
var rr = Resolve<MethodGroupResolveResult>(program);
Assert.AreEqual("X", rr.TypeArguments.Single().Name);
var m = 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<TypeResolveResult>(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<TypeResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(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<MemberResolveResult>(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<LocalResolveResult>(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<TypeResolveResult>(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<TypeResolveResult>(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<T> where T : $B$ {
class B {}
}";
var result = Resolve<TypeResolveResult>(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<T>() where T : $B$ {}
class B {}
}";
var result = Resolve<TypeResolveResult>(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<NamespaceResolveResult>(program);
Assert.AreEqual("A.B.C.D", nrr.NamespaceName);
}
}
}