diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs new file mode 100644 index 0000000000..d1178757eb --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs @@ -0,0 +1,85 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + // assign short name to the fake reflection type + using dynamic = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.Dynamic; + + [TestFixture] + public class ConditionalOperatorTests : ResolverTestBase + { + [Test] + public void PickMoreGeneralOfTheTypes() + { + AssertType(typeof(object), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(string)), MakeResult(typeof(object)))); + AssertType(typeof(long), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(int)), MakeResult(typeof(long)))); + } + + [Test] + public void Null() + { + AssertType(typeof(string), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(string)), MakeConstant(null))); + AssertType(typeof(string), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeConstant(null), MakeResult(typeof(string)))); + } + + [Test] + public void DynamicInArguments() + { + AssertType(typeof(dynamic), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(dynamic)), MakeResult(typeof(double)))); + + AssertType(typeof(dynamic), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(double)), MakeResult(typeof(dynamic)))); + } + + [Test] + public void DynamicInCondition() + { + AssertType(typeof(double), resolver.ResolveConditional( + MakeResult(typeof(dynamic)), MakeResult(typeof(float)), MakeResult(typeof(double)))); + } + + [Test] + public void AllDynamic() + { + AssertType(typeof(dynamic), resolver.ResolveConditional( + MakeResult(typeof(dynamic)), MakeResult(typeof(dynamic)), MakeResult(typeof(dynamic)))); + } + + [Test] + public void ListOfDynamicAndListOfObject() + { + AssertError(typeof(List), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(List)), MakeResult(typeof(List)))); + + AssertError(typeof(List), resolver.ResolveConditional( + MakeResult(typeof(bool)), MakeResult(typeof(List)), MakeResult(typeof(List)))); + } + + [Test] + public void Constant() + { + AssertConstant(1L, resolver.ResolveConditional( + MakeConstant(true), MakeConstant(1), MakeConstant(2L))); + + AssertConstant(2L, resolver.ResolveConditional( + MakeConstant(false), MakeConstant(1), MakeConstant(2L))); + } + + [Test] + public void NotConstantIfFalsePortionNotConstant() + { + AssertType(typeof(long), resolver.ResolveConditional( + MakeConstant(true), MakeConstant(1), MakeResult(typeof(long)))); + } + } +} diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index 3c1e05fb0f..36691c5e2a 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -1,4 +1,4 @@ - + {63D3B27A-D966-4902-90B3-30290E1692F1} @@ -120,6 +120,7 @@ + diff --git a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index e1cfcf64a1..79eec56d9c 100644 --- a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -1085,7 +1085,9 @@ namespace ICSharpCode.NRefactory.CSharp queryFromClause.Type.AcceptVisitor(this, data); Space(); WriteIdentifier(queryFromClause.Identifier); + Space(); WriteKeyword("in", QueryFromClause.InKeywordRole); + Space(); queryFromClause.Expression.AcceptVisitor(this, data); return EndNode(queryFromClause); } diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index b3dfd30b57..072d6de850 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.Utils; @@ -652,8 +653,137 @@ namespace ICSharpCode.NRefactory.CSharp #region Constant Values IConstantValue ConvertConstantValue(ITypeReference targetType, AstNode expression) { - // TODO: implement ConvertConstantValue - return new SimpleConstantValue(targetType, null); + ConstantValueBuilder b = new ConstantValueBuilder(); + b.convertVisitor = this; + // TODO: initialize b.checkForOverflow based on the project's overflow setting + IConstantValue c = expression.AcceptVisitor(b, null); + if (c != null) + return new ConstantCast(targetType, c, b.checkForOverflow); + else + return c; + } + + sealed class ConstantValueBuilder : DepthFirstAstVisitor + { + internal TypeSystemConvertVisitor convertVisitor; + internal bool checkForOverflow; + + protected override IConstantValue VisitChildren(AstNode node, object data) + { + return null; + } + + public override IConstantValue VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression, object data) + { + return new SimpleConstantValue(KnownTypeReference.Object, null); + } + + public override IConstantValue VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) + { + TypeCode typeCode = Type.GetTypeCode(primitiveExpression.Value.GetType()); + return new SimpleConstantValue(typeCode.ToTypeReference(), primitiveExpression.Value); + } + + IList ConvertTypeArguments(AstNodeCollection types) + { + int count = types.Count; + if (count == 0) + return null; + ITypeReference[] result = new ITypeReference[count]; + int pos = 0; + foreach (AstType type in types) { + result[pos++] = convertVisitor.ConvertType(type); + } + return result; + } + + public override IConstantValue VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) + { + return new ConstantIdentifierReference(identifierExpression.Identifier, ConvertTypeArguments(identifierExpression.TypeArguments)); + } + + public override IConstantValue VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) + { + TypeReferenceExpression tre = memberReferenceExpression.Target as TypeReferenceExpression; + if (tre != null) { + // handle "int.MaxValue" + return new ConstantMemberReference( + convertVisitor.ConvertType(tre.Type), + memberReferenceExpression.MemberName, + ConvertTypeArguments(memberReferenceExpression.TypeArguments)); + } + IConstantValue v = memberReferenceExpression.Target.AcceptVisitor(this, data); + if (v == null) + return null; + return new ConstantMemberReference( + v, memberReferenceExpression.MemberName, + ConvertTypeArguments(memberReferenceExpression.TypeArguments)); + } + + public override IConstantValue VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) + { + return parenthesizedExpression.Expression.AcceptVisitor(this, data); + } + + public override IConstantValue VisitCastExpression(CastExpression castExpression, object data) + { + IConstantValue v = castExpression.Expression.AcceptVisitor(this, data); + if (v == null) + return null; + return new ConstantCast(convertVisitor.ConvertType(castExpression.Type), v, checkForOverflow); + } + + public override IConstantValue VisitCheckedExpression(CheckedExpression checkedExpression, object data) + { + bool oldCheckForOverflow = checkForOverflow; + try { + checkForOverflow = true; + return checkedExpression.Expression.AcceptVisitor(this, data); + } finally { + checkForOverflow = oldCheckForOverflow; + } + } + + public override IConstantValue VisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data) + { + bool oldCheckForOverflow = checkForOverflow; + try { + checkForOverflow = false; + return uncheckedExpression.Expression.AcceptVisitor(this, data); + } finally { + checkForOverflow = oldCheckForOverflow; + } + } + + public override IConstantValue VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data) + { + return new ConstantDefaultValue(convertVisitor.ConvertType(defaultValueExpression.Type)); + } + + public override IConstantValue VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) + { + IConstantValue v = unaryOperatorExpression.Expression.AcceptVisitor(this, data); + if (v == null) + return null; + switch (unaryOperatorExpression.Operator) { + case UnaryOperatorType.Not: + case UnaryOperatorType.BitNot: + case UnaryOperatorType.Minus: + case UnaryOperatorType.Plus: + return new ConstantUnaryOperator(unaryOperatorExpression.Operator, v, checkForOverflow); + default: + return null; + } + } + + public override IConstantValue VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) + { + IConstantValue left = binaryOperatorExpression.Left.AcceptVisitor(this, data); + IConstantValue right = binaryOperatorExpression.Right.AcceptVisitor(this, data); + if (left == null || right == null) + return null; + return new ConstantBinaryOperator(left, binaryOperatorExpression.Operator, right, checkForOverflow); + } } #endregion diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index fd43e18c4e..295c85a563 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -2043,7 +2043,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region ResolveConditional - public ResolveResult ResolveConditional(ResolveResult trueExpression, ResolveResult falseExpression) + public ResolveResult ResolveConditional(ResolveResult condition, ResolveResult trueExpression, ResolveResult falseExpression) { // C# 4.0 spec §7.14: Conditional operator @@ -2052,11 +2052,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Conversions c = new Conversions(context); bool isValid; IType resultType; - if (HasType(trueExpression) && HasType(falseExpression)) { + if (trueExpression.Type == SharedTypes.Dynamic || falseExpression.Type == SharedTypes.Dynamic) { + resultType = SharedTypes.Dynamic; + isValid = true; + } else if (HasType(trueExpression) && HasType(falseExpression)) { bool t2f = c.ImplicitConversion(trueExpression.Type, falseExpression.Type); bool f2t = c.ImplicitConversion(falseExpression.Type, trueExpression.Type); - resultType = (f2t && !t2f) ? falseExpression.Type : trueExpression.Type; - isValid = (t2f != f2t) || (t2f && f2t && c.IdentityConversion(trueExpression.Type, falseExpression.Type)); + resultType = (f2t && !t2f) ? trueExpression.Type : falseExpression.Type; + // The operator is valid: + // a) if there's a conversion in one direction but not the other + // b) if there are conversions in both directions, and the types are equivalent + isValid = (t2f != f2t) || (t2f && f2t && trueExpression.Type.Equals(falseExpression.Type)); } else if (HasType(trueExpression)) { resultType = trueExpression.Type; isValid = c.ImplicitConversion(falseExpression, resultType); @@ -2066,7 +2072,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } else { return ErrorResult; } - return isValid ? new ResolveResult(resultType) : new ErrorResolveResult(resultType); + if (isValid) { + if (condition.IsCompileTimeConstant && trueExpression.IsCompileTimeConstant && falseExpression.IsCompileTimeConstant) { + bool? val = condition.ConstantValue as bool?; + if (val == true) + return ResolveCast(resultType, trueExpression); + else if (val == false) + return ResolveCast(resultType, falseExpression); + } + return new ResolveResult(resultType); + } else { + return new ErrorResolveResult(resultType); + } } bool HasType(ResolveResult r) @@ -2087,5 +2104,46 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } #endregion + + #region ResolveDefaultValue + public ResolveResult ResolveDefaultValue(IType type) + { + return new ConstantResolveResult(type, GetDefaultValue(type)); + } + + public static object GetDefaultValue(IType type) + { + switch (ReflectionHelper.GetTypeCode(type)) { + case TypeCode.Boolean: + return false; + case TypeCode.Char: + return '\0'; + case TypeCode.SByte: + return (sbyte)0; + case TypeCode.Byte: + return (byte)0; + case TypeCode.Int16: + return (short)0; + case TypeCode.UInt16: + return (ushort)0; + case TypeCode.Int32: + return 0; + case TypeCode.UInt32: + return 0U; + case TypeCode.Int64: + return 0L; + case TypeCode.UInt64: + return 0UL; + case TypeCode.Single: + return 0f; + case TypeCode.Double: + return 0.0; + case TypeCode.Decimal: + return 0m; + default: + return null; + } + } + #endregion } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs new file mode 100644 index 0000000000..4f77484977 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs @@ -0,0 +1,391 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues +{ + // Contains representations for constant C# expressions. + // We use these instead of storing the full AST to reduce the memory usage. + + // The type system's SimpleConstantValue is used to represent PrimitiveExpressions. + + public abstract class ConstantExpression : Immutable, IConstantValue + { + public abstract ResolveResult Resolve(CSharpResolver resolver); + + public static ResolveResult Resolve(IConstantValue constantValue, CSharpResolver resolver) + { + ConstantExpression expr = constantValue as ConstantExpression; + if (expr != null) + return expr.Resolve(resolver); + else + return new ConstantResolveResult(constantValue.GetValueType(resolver.Context), constantValue.GetValue(resolver.Context)); + } + + public IType GetValueType(ITypeResolveContext context) + { + return Resolve(new CSharpResolver(context)).Type; + } + + public object GetValue(ITypeResolveContext context) + { + return Resolve(new CSharpResolver(context)).ConstantValue; + } + } + + public class ConstantCast : ConstantExpression, ISupportsInterning + { + ITypeReference targetType; + IConstantValue expression; + readonly bool checkForOverflow; + + public ConstantCast(ITypeReference targetType, IConstantValue expression, bool checkForOverflow) + { + if (targetType == null) + throw new ArgumentNullException("targetType"); + if (expression == null) + throw new ArgumentNullException("expression"); + this.targetType = targetType; + this.expression = expression; + this.checkForOverflow = checkForOverflow; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + ResolveResult rr = Resolve(expression, resolver); + resolver.CheckForOverflow = checkForOverflow; + return resolver.ResolveCast(targetType.Resolve(resolver.Context), rr); + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + targetType = provider.Intern(targetType); + expression = provider.Intern(expression); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + return targetType.GetHashCode() + expression.GetHashCode() * 1018829 + (checkForOverflow ? 614811 : 7125912); + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantCast cast = other as ConstantCast; + return cast != null + && this.targetType == cast.targetType && this.expression == cast.expression + && this.checkForOverflow == cast.checkForOverflow; + } + } + + public class ConstantIdentifierReference : ConstantExpression, ISupportsInterning + { + string identifier; + IList typeArguments; + + public ConstantIdentifierReference(string identifier, IList typeArguments = null) + { + if (identifier == null) + throw new ArgumentNullException("identifier"); + this.identifier = identifier; + this.typeArguments = typeArguments; + } + + + public override ResolveResult Resolve(CSharpResolver resolver) + { + return resolver.ResolveSimpleName(identifier, ResolveTypes(resolver, typeArguments)); + } + + internal static IList ResolveTypes(CSharpResolver resolver, IList typeArguments) + { + if (typeArguments == null) + return EmptyList.Instance; + IType[] types = new IType[typeArguments.Count]; + for (int i = 0; i < types.Length; i++) { + types[i] = typeArguments[i].Resolve(resolver.Context); + } + return types; + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + identifier = provider.Intern(identifier); + typeArguments = provider.InternList(typeArguments); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + int hashCode = identifier.GetHashCode(); + if (typeArguments != null) + hashCode ^= typeArguments.GetHashCode(); + return hashCode; + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantIdentifierReference cir = other as ConstantIdentifierReference; + return cir != null && + this.identifier == cir.identifier && this.typeArguments == cir.typeArguments; + } + } + + public class ConstantMemberReference : ConstantExpression, ISupportsInterning + { + ITypeReference targetType; + IConstantValue targetExpression; + string memberName; + IList typeArguments; + + public ConstantMemberReference(ITypeReference targetType, string memberName, IList typeArguments = null) + { + if (targetType == null) + throw new ArgumentNullException("targetType"); + if (memberName == null) + throw new ArgumentNullException("memberName"); + this.targetType = targetType; + this.memberName = memberName; + this.typeArguments = typeArguments; + } + + public ConstantMemberReference(IConstantValue targetExpression, string memberName, IList typeArguments = null) + { + if (targetExpression == null) + throw new ArgumentNullException("targetExpression"); + if (memberName == null) + throw new ArgumentNullException("memberName"); + this.targetExpression = targetExpression; + this.memberName = memberName; + this.typeArguments = typeArguments; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + ResolveResult rr; + if (targetType != null) + rr = new TypeResolveResult(targetType.Resolve(resolver.Context)); + else + rr = Resolve(targetExpression, resolver); + return resolver.ResolveMemberAccess(rr, memberName, ConstantIdentifierReference.ResolveTypes(resolver, typeArguments)); + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + targetType = provider.Intern(targetType); + targetExpression = provider.Intern(targetExpression); + memberName = provider.Intern(memberName); + typeArguments = provider.InternList(typeArguments); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + int hashCode; + if (targetType != null) + hashCode = targetType.GetHashCode(); + else + hashCode = targetExpression.GetHashCode(); + hashCode ^= memberName.GetHashCode(); + if (typeArguments != null) + hashCode ^= typeArguments.GetHashCode(); + return hashCode; + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantMemberReference cmr = other as ConstantMemberReference; + return cmr != null + && this.targetType == cmr.targetType && this.targetExpression == cmr.targetExpression + && this.memberName == cmr.memberName && this.typeArguments == cmr.typeArguments; + } + } + + public class ConstantDefaultValue : ConstantExpression, ISupportsInterning + { + ITypeReference type; + + public ConstantDefaultValue(ITypeReference type) + { + if (type == null) + throw new ArgumentNullException("type"); + this.type = type; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + return resolver.ResolveDefaultValue(type.Resolve(resolver.Context)); + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + type = provider.Intern(type); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + return type.GetHashCode(); + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantDefaultValue o = other as ConstantDefaultValue; + return o != null && this.type == o.type; + } + } + + public class ConstantUnaryOperator : ConstantExpression, ISupportsInterning + { + UnaryOperatorType operatorType; + IConstantValue expression; + bool checkForOverflow; + + public ConstantUnaryOperator(UnaryOperatorType operatorType, IConstantValue expression, bool checkForOverflow) + { + if (expression == null) + throw new ArgumentNullException("expression"); + this.operatorType = operatorType; + this.expression = expression; + this.checkForOverflow = checkForOverflow; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + ResolveResult rr = Resolve(expression, resolver); + resolver.CheckForOverflow = checkForOverflow; + return resolver.ResolveUnaryOperator(operatorType, rr); + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + expression = provider.Intern(expression); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + return expression.GetHashCode() * 811 + operatorType.GetHashCode() + (checkForOverflow ? 1717211 : 12751265); + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantUnaryOperator uop = other as ConstantUnaryOperator; + return uop != null + && this.operatorType == uop.operatorType + && this.expression == uop.expression + && this.checkForOverflow == uop.checkForOverflow; + } + } + + public class ConstantBinaryOperator : ConstantExpression, ISupportsInterning + { + IConstantValue left; + BinaryOperatorType operatorType; + IConstantValue right; + bool checkForOverflow; + + public ConstantBinaryOperator(IConstantValue left, BinaryOperatorType operatorType, IConstantValue right, bool checkForOverflow) + { + if (left == null) + throw new ArgumentNullException("left"); + if (right == null) + throw new ArgumentNullException("right"); + this.left = left; + this.operatorType = operatorType; + this.right = right; + this.checkForOverflow = checkForOverflow; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + ResolveResult lhs = Resolve(left, resolver); + ResolveResult rhs = Resolve(right, resolver); + resolver.CheckForOverflow = checkForOverflow; + return resolver.ResolveBinaryOperator(operatorType, lhs, rhs); + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + left = provider.Intern(left); + right = provider.Intern(right); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + return left.GetHashCode() * 811 + operatorType.GetHashCode() + + right.GetHashCode() * 91781 + (checkForOverflow ? 1261561 : 174811); + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantBinaryOperator bop = other as ConstantBinaryOperator; + return bop != null + && this.operatorType == bop.operatorType + && this.left == bop.left && this.right == bop.right + && this.checkForOverflow == bop.checkForOverflow; + } + } + + public class ConstantConditionalOperator : ConstantExpression, ISupportsInterning + { + IConstantValue condition, trueExpr, falseExpr; + + public ConstantConditionalOperator(IConstantValue condition, IConstantValue trueExpr, IConstantValue falseExpr) + { + if (condition == null) + throw new ArgumentNullException("condition"); + if (trueExpr == null) + throw new ArgumentNullException("trueExpr"); + if (falseExpr == null) + throw new ArgumentNullException("falseExpr"); + this.condition = condition; + this.trueExpr = trueExpr; + this.falseExpr = falseExpr; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + return resolver.ResolveConditional( + Resolve(condition, resolver), + Resolve(trueExpr, resolver), + Resolve(falseExpr, resolver) + ); + } + + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) + { + condition = provider.Intern(condition); + trueExpr = provider.Intern(trueExpr); + falseExpr = provider.Intern(falseExpr); + } + + int ISupportsInterning.GetHashCodeForInterning() + { + unchecked { + return condition.GetHashCode() * 182981713 + + trueExpr.GetHashCode() * 917517169 + + falseExpr.GetHashCode() * 611651; + } + } + + bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) + { + ConstantConditionalOperator coo = other as ConstantConditionalOperator; + return coo != null + && this.condition == coo.condition + && this.trueExpr == coo.trueExpr + && this.falseExpr == coo.falseExpr; + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 1403107ad0..3bcea943b3 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -567,9 +567,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override ResolveResult VisitConditionalExpression(ConditionalExpression conditionalExpression, object data) { if (resolverEnabled) { - Scan(conditionalExpression.Condition); - return resolver.ResolveConditional(Resolve(conditionalExpression.TrueExpression), - Resolve(conditionalExpression.FalseExpression)); + return resolver.ResolveConditional( + Resolve(conditionalExpression.Condition), + Resolve(conditionalExpression.TrueExpression), + Resolve(conditionalExpression.FalseExpression)); } else { ScanChildren(conditionalExpression); return null; @@ -579,7 +580,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override ResolveResult VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data) { if (resolverEnabled) { - return new ConstantResolveResult(ResolveType(defaultValueExpression.Type), null); + return resolver.ResolveDefaultValue(ResolveType(defaultValueExpression.Type)); } else { ScanChildren(defaultValueExpression); return null; diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 87bd59cb88..19c9669e60 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -1,4 +1,4 @@ - + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} @@ -97,6 +97,7 @@ +