Browse Source

Report more types of invalid equality comparisons as errors.

Mark an anonymous function conversion as invalid if there are compiler errors in the implicitly typed lambda.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
77ea4dae30
  1. 25
      ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs
  2. 2
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
  3. 59
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpOperators.cs
  4. 25
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  5. 57
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  6. 54
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/BinaryOperatorTests.cs
  7. 53
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs
  8. 4
      ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

25
ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs

@ -128,6 +128,31 @@ namespace ICSharpCode.NRefactory.CSharp
item.Remove(); item.Remove();
} }
/// <summary>
/// Returns the first element for which the predicate returns true,
/// or the null node (AstNode with IsNull=true) if no such object is found.
/// </summary>
public T FirstOrNullObject(Func<T, bool> predicate = null)
{
foreach (T item in this)
if (predicate == null || predicate(item))
return item;
return role.NullObject;
}
/// <summary>
/// Returns the last element for which the predicate returns true,
/// or the null node (AstNode with IsNull=true) if no such object is found.
/// </summary>
public T LastOrNullObject(Func<T, bool> predicate = null)
{
T result = role.NullObject;
foreach (T item in this)
if (predicate == null || predicate(item))
result = item;
return result;
}
bool ICollection<T>.IsReadOnly { bool ICollection<T>.IsReadOnly {
get { return false; } get { return false; }
} }

2
ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs

@ -38,6 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary> /// <summary>
/// Creates a new C# AST resolver. /// Creates a new C# AST resolver.
/// Use this overload if you are resolving within a complete C# file.
/// </summary> /// </summary>
/// <param name="compilation">The current compilation.</param> /// <param name="compilation">The current compilation.</param>
/// <param name="parsedFile"> /// <param name="parsedFile">
@ -60,6 +61,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <summary> /// <summary>
/// Creates a new C# AST resolver. /// Creates a new C# AST resolver.
/// Use this overload if you are resolving code snippets (not necessarily complete files).
/// </summary> /// </summary>
/// <param name="resolver">The resolver state at the root node (to be more precise: outside the root node).</param> /// <param name="resolver">The resolver state at the root node (to be more precise: outside the root node).</param>
/// <param name="rootNode">The root node of the resolved tree.</param> /// <param name="rootNode">The root node of the resolved tree.</param>

59
ICSharpCode.NRefactory.CSharp/Resolver/CSharpOperators.cs

@ -755,42 +755,75 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
// C# 4.0 spec: §7.10 Relational and type-testing operators // C# 4.0 spec: §7.10 Relational and type-testing operators
static readonly TypeCode[] equalityOperatorsFor = { static readonly TypeCode[] valueEqualityOperatorsFor = {
TypeCode.Int32, TypeCode.UInt32, TypeCode.Int32, TypeCode.UInt32,
TypeCode.Int64, TypeCode.UInt64, TypeCode.Int64, TypeCode.UInt64,
TypeCode.Single, TypeCode.Double, TypeCode.Single, TypeCode.Double,
TypeCode.Decimal, TypeCode.Decimal,
TypeCode.Boolean, TypeCode.Boolean
TypeCode.String, TypeCode.Object
}; };
OperatorMethod[] equalityOperators; OperatorMethod[] valueEqualityOperators;
public OperatorMethod[] EqualityOperators { public OperatorMethod[] ValueEqualityOperators {
get { get {
OperatorMethod[] ops = equalityOperators; OperatorMethod[] ops = valueEqualityOperators;
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier(); LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref equalityOperators, Lift( return LazyInit.GetOrSet(ref valueEqualityOperators, Lift(
equalityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, false)).ToArray() valueEqualityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, false)).ToArray()
)); ));
} }
} }
} }
OperatorMethod[] inequalityOperators; OperatorMethod[] valueInequalityOperators;
public OperatorMethod[] InequalityOperators { public OperatorMethod[] ValueInequalityOperators {
get { get {
OperatorMethod[] ops = inequalityOperators; OperatorMethod[] ops = valueInequalityOperators;
if (ops != null) { if (ops != null) {
LazyInit.ReadBarrier(); LazyInit.ReadBarrier();
return ops; return ops;
} else { } else {
return LazyInit.GetOrSet(ref inequalityOperators, Lift( return LazyInit.GetOrSet(ref valueInequalityOperators, Lift(
equalityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, true)).ToArray() valueEqualityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, true)).ToArray()
));
}
}
}
OperatorMethod[] referenceEqualityOperators;
public OperatorMethod[] ReferenceEqualityOperators {
get {
OperatorMethod[] ops = referenceEqualityOperators;
if (ops != null) {
LazyInit.ReadBarrier();
return ops;
} else {
return LazyInit.GetOrSet(ref referenceEqualityOperators, Lift(
new EqualityOperatorMethod(this, TypeCode.Object, false),
new EqualityOperatorMethod(this, TypeCode.String, false)
));
}
}
}
OperatorMethod[] referenceInequalityOperators;
public OperatorMethod[] ReferenceInequalityOperators {
get {
OperatorMethod[] ops = referenceInequalityOperators;
if (ops != null) {
LazyInit.ReadBarrier();
return ops;
} else {
return LazyInit.GetOrSet(ref referenceInequalityOperators, Lift(
new EqualityOperatorMethod(this, TypeCode.Object, true),
new EqualityOperatorMethod(this, TypeCode.String, true)
)); ));
} }
} }

25
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -703,21 +703,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs); return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs);
} }
if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality) { if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality) {
if (lhsType.Kind == TypeKind.Null && NullableType.IsNullable(rhs.Type) if (lhsType.IsReferenceType == true && rhsType.IsReferenceType == true) {
|| rhsType.Kind == TypeKind.Null && NullableType.IsNullable(lhs.Type)) // If it's a reference comparison
{ if (op == BinaryOperatorType.Equality)
// §7.10.9 Equality operators and null methodGroup = operators.ReferenceEqualityOperators;
// "x == null", "null == x", "x != null" and "null != x" are valid else
// even if the struct does not define operator ==. methodGroup = operators.ReferenceInequalityOperators;
break;
} else if (lhsType.Kind == TypeKind.Null && IsNullableTypeOrNonValueType(rhs.Type)
|| IsNullableTypeOrNonValueType(lhs.Type) && rhsType.Kind == TypeKind.Null) {
// compare type parameter or nullable type with the null literal
return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs); return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs);
} }
} }
switch (op) { switch (op) {
case BinaryOperatorType.Equality: case BinaryOperatorType.Equality:
methodGroup = operators.EqualityOperators; methodGroup = operators.ValueEqualityOperators;
break; break;
case BinaryOperatorType.InEquality: case BinaryOperatorType.InEquality:
methodGroup = operators.InequalityOperators; methodGroup = operators.ValueInequalityOperators;
break; break;
case BinaryOperatorType.LessThan: case BinaryOperatorType.LessThan:
methodGroup = operators.LessThanOperators; methodGroup = operators.LessThanOperators;
@ -800,6 +804,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
bool IsNullableTypeOrNonValueType(IType type)
{
return NullableType.IsNullable(type) || type.IsReferenceType != false;
}
ResolveResult BinaryOperatorResolveResult(IType resultType, ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs) ResolveResult BinaryOperatorResolveResult(IType resultType, ResolveResult lhs, BinaryOperatorType op, ResolveResult rhs)
{ {
return new OperatorResolveResult(resultType, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow), lhs, rhs); return new OperatorResolveResult(resultType, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow), lhs, rhs);

57
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -286,21 +286,28 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public readonly IType ReturnType; public readonly IType ReturnType;
public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda; public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda;
public readonly LambdaTypeHypothesis Hypothesis; public readonly LambdaTypeHypothesis Hypothesis;
readonly bool isValid;
public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis) public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis, bool isValid)
{ {
if (returnType == null) if (returnType == null)
throw new ArgumentNullException("returnType"); throw new ArgumentNullException("returnType");
this.ReturnType = returnType; this.ReturnType = returnType;
this.Hypothesis = hypothesis; this.Hypothesis = hypothesis;
this.isValid = isValid;
} }
public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda) public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda, bool isValid)
{ {
if (returnType == null) if (returnType == null)
throw new ArgumentNullException("returnType"); throw new ArgumentNullException("returnType");
this.ReturnType = returnType; this.ReturnType = returnType;
this.ExplicitlyTypedLambda = explicitlyTypedLambda; this.ExplicitlyTypedLambda = explicitlyTypedLambda;
this.isValid = isValid;
}
public override bool IsValid {
get { return isValid; }
} }
public override bool IsImplicit { public override bool IsImplicit {
@ -1761,7 +1768,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IList<ResolveResult> returnValues; IList<ResolveResult> returnValues;
bool isValidAsVoidMethod; bool isValidAsVoidMethod;
bool isEndpointUnreachable; bool isEndpointUnreachable;
bool success;
// The actual return type is set when the lambda is applied by the conversion. // The actual return type is set when the lambda is applied by the conversion.
IType actualReturnType; IType actualReturnType;
@ -1822,7 +1828,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
delegate { delegate {
var oldNavigator = visitor.navigator; var oldNavigator = visitor.navigator;
visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator); visitor.navigator = new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, oldNavigator);
visitor.AnalyzeLambda(body, isAsync, out success, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues); visitor.AnalyzeLambda(body, isAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues);
visitor.navigator = oldNavigator; visitor.navigator = oldNavigator;
}); });
Log.Unindent(); Log.Unindent();
@ -1831,7 +1837,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (inferredReturnType == null) if (inferredReturnType == null)
throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType"); throw new InvalidOperationException("AnalyzeLambda() didn't set inferredReturnType");
} }
return success; return true;
} }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, Conversions conversions) public override Conversion IsValid(IType[] parameterTypes, IType returnType, Conversions conversions)
@ -1841,11 +1847,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, isAsync, returnValues, returnType, conversions); bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, isAsync, returnValues, returnType, conversions);
Log.Unindent(); Log.Unindent();
Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType); Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType);
if (valid) { return new AnonymousFunctionConversion(returnType, this, valid);
return new AnonymousFunctionConversion(returnType, this);
} else {
return Conversion.None;
}
} }
public override IType GetInferredReturnType(IType[] parameterTypes) public override IType GetInferredReturnType(IType[] parameterTypes)
@ -2021,7 +2023,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return h; return h;
} }
ResolveVisitor visitor = new ResolveVisitor(storedContext, parsedFile); ResolveVisitor visitor = new ResolveVisitor(storedContext, parsedFile);
visitor.SetNavigator(new ConstantModeResolveVisitorNavigator(ResolveVisitorNavigationMode.Resolve, null));
var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null); var newHypothesis = new LambdaTypeHypothesis(this, parameterTypes, visitor, lambda != null ? lambda.Parameters : null);
hypotheses.Add(newHypothesis); hypotheses.Add(newHypothesis);
return newHypothesis; return newHypothesis;
@ -2094,7 +2095,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// with the parent ResolveVisitor. /// with the parent ResolveVisitor.
/// This is done when the AnonymousFunctionConversion is applied on the parent visitor. /// This is done when the AnonymousFunctionConversion is applied on the parent visitor.
/// </summary> /// </summary>
sealed class LambdaTypeHypothesis sealed class LambdaTypeHypothesis : IResolveVisitorNavigator
{ {
readonly ImplicitlyTypedLambda lambda; readonly ImplicitlyTypedLambda lambda;
internal readonly IParameter[] lambdaParameters; internal readonly IParameter[] lambdaParameters;
@ -2116,6 +2117,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.lambda = lambda; this.lambda = lambda;
this.parameterTypes = parameterTypes; this.parameterTypes = parameterTypes;
this.visitor = visitor; this.visitor = visitor;
visitor.SetNavigator(this);
Log.WriteLine("Analyzing " + ToString() + "..."); Log.WriteLine("Analyzing " + ToString() + "...");
Log.Indent(); Log.Indent();
@ -2138,12 +2140,29 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
visitor.AnalyzeLambda(lambda.BodyExpression, lambda.IsAsync, out success, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues); success = true;
visitor.AnalyzeLambda(lambda.BodyExpression, lambda.IsAsync, out isValidAsVoidMethod, out isEndpointUnreachable, out inferredReturnType, out returnExpressions, out returnValues);
visitor.resolver = oldResolver; visitor.resolver = oldResolver;
Log.Unindent(); Log.Unindent();
Log.WriteLine("Finished analyzing " + ToString()); Log.WriteLine("Finished analyzing " + ToString());
} }
ResolveVisitorNavigationMode IResolveVisitorNavigator.Scan(AstNode node)
{
return ResolveVisitorNavigationMode.Resolve;
}
void IResolveVisitorNavigator.Resolved(AstNode node, ResolveResult result)
{
if (result.IsError)
success = false;
}
void IResolveVisitorNavigator.ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
success &= conversion.IsValid;
}
internal int CountUnknownParameters() internal int CountUnknownParameters()
{ {
int c = 0; int c = 0;
@ -2156,11 +2175,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public Conversion IsValid(IType returnType, Conversions conversions) public Conversion IsValid(IType returnType, Conversions conversions)
{ {
if (success && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, lambda.IsAsync, returnValues, returnType, conversions)) { bool valid = success && IsValidLambda(isValidAsVoidMethod, isEndpointUnreachable, lambda.IsAsync, returnValues, returnType, conversions);
return new AnonymousFunctionConversion(returnType, this); return new AnonymousFunctionConversion(returnType, this, valid);
} else {
return Conversion.None;
}
} }
public void MergeInto(ResolveVisitor parentVisitor, IType returnType) public void MergeInto(ResolveVisitor parentVisitor, IType returnType)
@ -2288,7 +2304,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return SpecialType.UnknownType; return SpecialType.UnknownType;
} }
void AnalyzeLambda(AstNode body, bool isAsync, out bool success, out bool isValidAsVoidMethod, out bool isEndpointUnreachable, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues) void AnalyzeLambda(AstNode body, bool isAsync, out bool isValidAsVoidMethod, out bool isEndpointUnreachable, out IType inferredReturnType, out IList<Expression> returnExpressions, out IList<ResolveResult> returnValues)
{ {
isEndpointUnreachable = false; isEndpointUnreachable = false;
Expression expr = body as Expression; Expression expr = body as Expression;
@ -2329,9 +2345,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (isAsync) if (isAsync)
inferredReturnType = GetTaskType(inferredReturnType); inferredReturnType = GetTaskType(inferredReturnType);
Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType); Log.WriteLine("Lambda return type was inferred to: " + inferredReturnType);
// TODO: check for compiler errors within the lambda body
success = true;
} }
static bool ExpressionPermittedAsStatement(Expression expr) static bool ExpressionPermittedAsStatement(Expression expr)

54
ICSharpCode.NRefactory.Tests/CSharp/Resolver/BinaryOperatorTests.cs

@ -299,6 +299,15 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Equality, MakeResult(typeof(float)), TestOperator(MakeResult(typeof(int)), BinaryOperatorType.Equality, MakeResult(typeof(float)),
Conversion.ImplicitNumericConversion, Conversion.IdentityConversion, typeof(bool)); Conversion.ImplicitNumericConversion, Conversion.IdentityConversion, typeof(bool));
AssertType(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeResult(typeof(int)), MakeConstant(null)));
AssertError(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeResult(typeof(int)), MakeResult(typeof(string))));
AssertError(typeof(bool), resolver.ResolveBinaryOperator(
BinaryOperatorType.Equality, MakeResult(typeof(int)), MakeResult(typeof(object))));
} }
[Test] [Test]
@ -586,6 +595,37 @@ class Test {
Assert.AreEqual("System.Byte", irr.Type.ReflectionName); Assert.AreEqual("System.Byte", irr.Type.ReflectionName);
} }
[Test]
public void CompareDateTimeWithNullLiteral()
{
string program = @"using System;
class Test {
static void Inc(DateTime x) {
var c = $x == null$;
}
}";
var irr = Resolve<OperatorResolveResult>(program);
Assert.IsFalse(irr.IsError);
Assert.IsTrue(irr.IsLiftedOperator);
Assert.IsNotNull(irr.UserDefinedOperatorMethod);
Assert.AreEqual(compilation.FindType(KnownTypeCode.Boolean), irr.Type);
}
[Test]
public void CompareStructWithNullLiteral()
{
string program = @"
struct X { }
class Test {
static void Inc(X x) {
var c = $x == null$;
}
}";
var irr = Resolve(program);
Assert.IsTrue(irr.IsError);
Assert.AreEqual(compilation.FindType(KnownTypeCode.Boolean), irr.Type);
}
[Test] [Test]
public void CompareNullableStructWithNullLiteral() public void CompareNullableStructWithNullLiteral()
{ {
@ -601,6 +641,20 @@ class Test {
Assert.AreEqual(compilation.FindType(KnownTypeCode.Boolean), irr.Type); Assert.AreEqual(compilation.FindType(KnownTypeCode.Boolean), irr.Type);
} }
[Test]
public void CompareUnrestrictedTypeParameterWithNullLiteral()
{
string program = @"
class Test {
static void Inc<X>(X x) {
var c = $x == null$;
}
}";
var irr = Resolve<OperatorResolveResult>(program);
Assert.IsFalse(irr.IsError);
Assert.AreEqual(compilation.FindType(KnownTypeCode.Boolean), irr.Type);
}
[Test] [Test]
public void LiftedEqualityOperator() public void LiftedEqualityOperator()
{ {

53
ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs

@ -368,7 +368,7 @@ class TestClass {
string program = @"using System; string program = @"using System;
class TestClass { class TestClass {
static void Method<T>(System.Collections.Generic.List<T> list) { static void Method<T>(System.Collections.Generic.List<T> list) {
$list.ConvertAll(x => (int)x)$; $list.ConvertAll(x => (int)(object)x)$;
} }
}"; }";
var rr = Resolve<CSharpInvocationResolveResult>(program); var rr = Resolve<CSharpInvocationResolveResult>(program);
@ -500,18 +500,51 @@ class Test {
Assert.AreEqual("propertyExpression", rr.Member.Parameters.Single().Name); Assert.AreEqual("propertyExpression", rr.Member.Parameters.Single().Name);
} }
/* TODO write test for this [Test]
class A public void ParenthesizedExpressionIsNotValidExpressionStatement()
{ {
string program = @"using System;
class A {
static void Foo(string x, Action<Action> y) { Console.WriteLine(1); } static void Foo(string x, Action<Action> y) { Console.WriteLine(1); }
static void Foo(object x, Func<Func<int>, int> y) { Console.WriteLine(2); } static void Foo(object x, Func<Func<int>, int> y) { Console.WriteLine(2); }
static void Main() static void Main()
{ { ";
Foo(null, x => x()); // Prints 1 var rr = ResolveAtLocation<CSharpInvocationResolveResult>(program + "$Foo(null, x => x()); // Prints 1\n}}");
Foo(null, x => (x())); // Prints 2 Assert.IsFalse(rr.IsError);
} Assert.AreEqual("System.String", rr.Member.Parameters[0].Type.ReflectionName);
}
*/ rr = ResolveAtLocation<CSharpInvocationResolveResult>(program + "$Foo(null, x => (x())); // Prints 2\n}}");
Assert.IsFalse(rr.IsError);
Assert.AreEqual("System.Object", rr.Member.Parameters[0].Type.ReflectionName);
}
[Test]
public void LambdaWithComparisonToString()
{
string program = @"using System;
class Test {
static void Foo(Func<int, bool> f) {}
static void Foo(Func<string, bool> f) {}
static void Main() { $Foo(x => x == ""text"")$; } }";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
var invoke = rr.Member.Parameters.Single().Type.GetDelegateInvokeMethod();
Assert.AreEqual("System.String", invoke.Parameters.Single().Type.ReflectionName);
}
[Test]
public void LambdaWithComparisonToInt()
{
string program = @"using System;
class Test {
static void Foo(Func<int, bool> f) {}
static void Foo(Func<string, bool> f) {}
static void Main() { $Foo(x => x == 42)$; } }";
var rr = Resolve<CSharpInvocationResolveResult>(program);
Assert.IsFalse(rr.IsError);
var invoke = rr.Member.Parameters.Single().Type.GetDelegateInvokeMethod();
Assert.AreEqual("System.Int32", invoke.Parameters.Single().Type.ReflectionName);
}
} }
} }

4
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

@ -59,6 +59,10 @@ namespace ICSharpCode.NRefactory.Semantics
get { return targetResult; } get { return targetResult; }
} }
/// <summary>
/// Gets the member.
/// This property never returns null.
/// </summary>
public IMember Member { public IMember Member {
get { return member; } get { return member; }
} }

Loading…
Cancel
Save