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.
		
		
		
		
		
			
		
			
				
					
					
						
							272 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
	
	
							272 lines
						
					
					
						
							10 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.Diagnostics; | 
						|
using System.IO; | 
						|
using System.Linq; | 
						|
using ICSharpCode.NRefactory.CSharp.Parser; | 
						|
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 | 
						|
{ | 
						|
	/// <summary> | 
						|
	/// Base class with helper functions for resolver unit tests. | 
						|
	/// </summary> | 
						|
	public abstract class ResolverTestBase | 
						|
	{ | 
						|
		protected readonly IUnresolvedAssembly mscorlib = CecilLoaderTests.Mscorlib; | 
						|
		protected IProjectContent project; | 
						|
		protected ICompilation compilation; | 
						|
		 | 
						|
		[SetUp] | 
						|
		public virtual void SetUp() | 
						|
		{ | 
						|
			project = new CSharpProjectContent().AddAssemblyReferences(new [] { mscorlib, CecilLoaderTests.SystemCore }); | 
						|
			compilation = project.CreateCompilation(); | 
						|
		} | 
						|
		 | 
						|
		protected IType ResolveType(Type type) | 
						|
		{ | 
						|
			IType t = compilation.FindType(type); | 
						|
			if (t.Kind == TypeKind.Unknown) | 
						|
				throw new InvalidOperationException("Could not resolve type"); | 
						|
			return t; | 
						|
		} | 
						|
		 | 
						|
		protected ConstantResolveResult MakeConstant(object value) | 
						|
		{ | 
						|
			if (value == null) | 
						|
				return new ConstantResolveResult(SpecialType.NullType, null); | 
						|
			IType type = ResolveType(value.GetType()); | 
						|
			if (type.Kind == TypeKind.Enum) | 
						|
				value = Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType())); | 
						|
			return new ConstantResolveResult(type, value); | 
						|
		} | 
						|
		 | 
						|
		protected ResolveResult MakeResult(Type type) | 
						|
		{ | 
						|
			return new ResolveResult(ResolveType(type)); | 
						|
		} | 
						|
		 | 
						|
		protected static TypeOrNamespaceReference MakeReference(string namespaceName) | 
						|
		{ | 
						|
			string[] nameParts = namespaceName.Split('.'); | 
						|
			TypeOrNamespaceReference r = new SimpleTypeOrNamespaceReference(nameParts[0], new ITypeReference[0], NameLookupMode.TypeInUsingDeclaration); | 
						|
			for (int i = 1; i < nameParts.Length; i++) { | 
						|
				r = new MemberTypeOrNamespaceReference(r, nameParts[i], new ITypeReference[0]); | 
						|
			} | 
						|
			return r; | 
						|
		} | 
						|
		 | 
						|
		protected void AssertConstant(object expectedValue, ResolveResult rr) | 
						|
		{ | 
						|
			Assert.IsFalse(rr.IsError, rr.ToString() + " is an error"); | 
						|
			Assert.IsTrue(rr.IsCompileTimeConstant, rr.ToString() + " is not a compile-time constant"); | 
						|
			Type expectedType = expectedValue.GetType(); | 
						|
			Assert.AreEqual(ResolveType(expectedType), rr.Type, "ResolveResult.Type is wrong"); | 
						|
			if (expectedType.IsEnum) { | 
						|
				Assert.AreEqual(Enum.GetUnderlyingType(expectedType), rr.ConstantValue.GetType(), "ResolveResult.ConstantValue has wrong Type"); | 
						|
				Assert.AreEqual(Convert.ChangeType(expectedValue, Enum.GetUnderlyingType(expectedType)), rr.ConstantValue); | 
						|
			} else { | 
						|
				Assert.AreEqual(expectedType, rr.ConstantValue.GetType(), "ResolveResult.ConstantValue has wrong Type"); | 
						|
				Assert.AreEqual(expectedValue, rr.ConstantValue); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		protected void AssertType(Type expectedType, ResolveResult rr) | 
						|
		{ | 
						|
			Assert.IsFalse(rr.IsError, rr.ToString() + " is an error"); | 
						|
			Assert.IsFalse(rr.IsCompileTimeConstant, rr.ToString() + " is a compile-time constant"); | 
						|
			Assert.AreEqual(compilation.FindType(expectedType), rr.Type); | 
						|
		} | 
						|
		 | 
						|
		protected void AssertError(Type expectedType, ResolveResult rr) | 
						|
		{ | 
						|
			Assert.IsTrue(rr.IsError, rr.ToString() + " is not an error, but an error was expected"); | 
						|
			Assert.IsFalse(rr.IsCompileTimeConstant, rr.ToString() + " is a compile-time constant"); | 
						|
			Assert.AreEqual(compilation.FindType(expectedType), rr.Type); | 
						|
		} | 
						|
		 | 
						|
		protected void TestOperator(UnaryOperatorType op, ResolveResult input, | 
						|
		                            Conversion expectedConversion, Type expectedResultType) | 
						|
		{ | 
						|
			CSharpResolver resolver = new CSharpResolver(compilation); | 
						|
			var rr = resolver.ResolveUnaryOperator(op, input); | 
						|
			AssertType(expectedResultType, rr); | 
						|
			Assert.AreEqual(typeof(OperatorResolveResult), rr.GetType()); | 
						|
			var uorr = (OperatorResolveResult)rr; | 
						|
			AssertConversion(uorr.Operands[0], input, expectedConversion, "Conversion"); | 
						|
		} | 
						|
		 | 
						|
		protected void TestOperator(ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs, | 
						|
		                            Conversion expectedLeftConversion, Conversion expectedRightConversion, Type expectedResultType) | 
						|
		{ | 
						|
			CSharpResolver resolver = new CSharpResolver(compilation); | 
						|
			var rr = resolver.ResolveBinaryOperator(op, lhs, rhs); | 
						|
			AssertType(expectedResultType, rr); | 
						|
			Assert.AreEqual(typeof(OperatorResolveResult), rr.GetType()); | 
						|
			var borr = (OperatorResolveResult)rr; | 
						|
			AssertConversion(borr.Operands[0], lhs, expectedLeftConversion, "Left conversion"); | 
						|
			AssertConversion(borr.Operands[1], rhs, expectedRightConversion, "Right conversion"); | 
						|
		} | 
						|
		 | 
						|
		protected void AssertConversion(ResolveResult conversionResult, ResolveResult expectedRR, Conversion expectedConversion, string text) | 
						|
		{ | 
						|
			if (expectedConversion == Conversion.IdentityConversion) { | 
						|
				Assert.AreSame(expectedRR, conversionResult, "Expected no " + text); | 
						|
			} else { | 
						|
				ConversionResolveResult crr = conversionResult as ConversionResolveResult; | 
						|
				Assert.IsNotNull(crr, "Could not find ConversionResolveResult for " + text); | 
						|
				Assert.AreEqual(expectedConversion, crr.Conversion, text); | 
						|
				Assert.AreSame(expectedRR, crr.Input, "Input of " + text); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		protected IEnumerable<TextLocation> FindDollarSigns(string code) | 
						|
		{ | 
						|
			int line = 1; | 
						|
			int col = 1; | 
						|
			foreach (char c in code) { | 
						|
				if (c == '$') { | 
						|
					yield return new TextLocation(line, col); | 
						|
				} else if (c == '\n') { | 
						|
					line++; | 
						|
					col = 1; | 
						|
				} else { | 
						|
					col++; | 
						|
				} | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		protected Tuple<CSharpAstResolver, AstNode> PrepareResolver(string code) | 
						|
		{ | 
						|
			SyntaxTree syntaxTree = new CSharpParser().Parse(code.Replace("$", ""), "code.cs"); | 
						|
			 | 
						|
			TextLocation[] dollars = FindDollarSigns(code).ToArray(); | 
						|
			Assert.AreEqual(2, dollars.Length, "Expected 2 dollar signs marking start+end of desired node"); | 
						|
			 | 
						|
			SetUp(); | 
						|
			 | 
						|
			CSharpUnresolvedFile unresolvedFile = syntaxTree.ToTypeSystem(); | 
						|
			project = project.AddOrUpdateFiles(unresolvedFile); | 
						|
			compilation = project.CreateCompilation(); | 
						|
			 | 
						|
			CSharpAstResolver resolver = new CSharpAstResolver(compilation, syntaxTree, unresolvedFile); | 
						|
			return Tuple.Create(resolver, FindNode(syntaxTree, dollars[0], dollars[1])); | 
						|
		} | 
						|
		 | 
						|
		protected ResolveResult Resolve(string code) | 
						|
		{ | 
						|
			var prep = PrepareResolver(code); | 
						|
			Debug.WriteLine(new string('=', 70)); | 
						|
			Debug.WriteLine("Starting new resolver for " + prep.Item2); | 
						|
			 | 
						|
			ResolveResult rr = prep.Item1.Resolve(prep.Item2); | 
						|
			Assert.IsNotNull(rr, "ResolveResult is null - did something go wrong while navigating to the target node?"); | 
						|
			Debug.WriteLine("ResolveResult is " + rr); | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		protected Conversion GetConversion(string code) | 
						|
		{ | 
						|
			var prep = PrepareResolver(code); | 
						|
			return prep.Item1.GetConversion((Expression)prep.Item2); | 
						|
		} | 
						|
		 | 
						|
		protected IType GetExpectedType(string code) | 
						|
		{ | 
						|
			var prep = PrepareResolver(code); | 
						|
			return prep.Item1.GetExpectedType((Expression)prep.Item2); | 
						|
		} | 
						|
		 | 
						|
		protected T Resolve<T>(string code) where T : ResolveResult | 
						|
		{ | 
						|
			ResolveResult rr = Resolve(code); | 
						|
			Assert.IsNotNull(rr); | 
						|
			if (typeof(T) == typeof(LambdaResolveResult)) { | 
						|
				Assert.IsTrue(rr is LambdaResolveResult, "Resolve should be " + typeof(T).Name + ", but was " + rr.GetType().Name); | 
						|
			} else { | 
						|
				Assert.IsTrue(rr.GetType() == typeof(T), "Resolve should be " + typeof(T).Name + ", but was " + rr.GetType().Name); | 
						|
			} | 
						|
			return (T)rr; | 
						|
		} | 
						|
		 | 
						|
		protected AstNode FindNode(SyntaxTree syntaxTree, TextLocation start, TextLocation end) | 
						|
		{ | 
						|
			FindNodeVisitor fnv = new FindNodeVisitor(start, end); | 
						|
			syntaxTree.AcceptVisitor(fnv); | 
						|
			Assert.IsNotNull(fnv.ResultNode, "Did not find DOM node at the specified location"); | 
						|
			return fnv.ResultNode; | 
						|
		} | 
						|
		 | 
						|
		sealed class FindNodeVisitor : DepthFirstAstVisitor | 
						|
		{ | 
						|
			readonly TextLocation start; | 
						|
			readonly TextLocation end; | 
						|
			public AstNode ResultNode; | 
						|
			 | 
						|
			public FindNodeVisitor(TextLocation start, TextLocation end) | 
						|
			{ | 
						|
				this.start = start; | 
						|
				this.end = end; | 
						|
			} | 
						|
			 | 
						|
			protected override void VisitChildren(AstNode node) | 
						|
			{ | 
						|
				if (node.StartLocation == start && node.EndLocation == end) { | 
						|
					if (ResultNode != null) | 
						|
						throw new InvalidOperationException("found multiple nodes with same start+end"); | 
						|
					ResultNode = node; | 
						|
					return; | 
						|
				} | 
						|
				base.VisitChildren(node); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		protected ResolveResult ResolveAtLocation(string code) | 
						|
		{ | 
						|
			SyntaxTree syntaxTree = SyntaxTree.Parse(code.Replace("$", ""), "test.cs"); | 
						|
			 | 
						|
			TextLocation[] dollars = FindDollarSigns(code).ToArray(); | 
						|
			Assert.AreEqual(1, dollars.Length, "Expected 1 dollar signs marking the location"); | 
						|
			 | 
						|
			SetUp(); | 
						|
			 | 
						|
			CSharpUnresolvedFile unresolvedFile = syntaxTree.ToTypeSystem(); | 
						|
			project = project.AddOrUpdateFiles(unresolvedFile); | 
						|
			compilation = project.CreateCompilation(); | 
						|
			 | 
						|
			ResolveResult rr = Resolver.ResolveAtLocation.Resolve(compilation, unresolvedFile, syntaxTree, dollars[0]); | 
						|
			return rr; | 
						|
		} | 
						|
		 | 
						|
		protected T ResolveAtLocation<T>(string code) where T : ResolveResult | 
						|
		{ | 
						|
			ResolveResult rr = ResolveAtLocation(code); | 
						|
			Assert.IsNotNull(rr); | 
						|
			Assert.IsTrue(rr.GetType() == typeof(T), "Resolve should be " + typeof(T).Name + ", but was " + rr.GetType().Name); | 
						|
			return (T)rr; | 
						|
		} | 
						|
	} | 
						|
}
 | 
						|
 |