#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.
 
 
 
 
 
 

525 lines
16 KiB

// 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 System.Linq;
using ICSharpCode.NRefactory.CSharp.Analysis;
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.
public class CSharpConstantValue : Immutable, IConstantValue, ISupportsInterning
{
ConstantExpression expression;
UsingScope parentUsingScope;
ITypeDefinition parentTypeDefinition;
public CSharpConstantValue(ConstantExpression expression, UsingScope parentUsingScope, ITypeDefinition parentTypeDefinition)
{
if (expression == null)
throw new ArgumentNullException("expression");
this.expression = expression;
this.parentUsingScope = parentUsingScope;
this.parentTypeDefinition = parentTypeDefinition;
}
CSharpResolver CreateResolver(ITypeResolveContext context)
{
// Because constants are evaluated by the compiler, we need to evaluate them in the resolve context
// of the project where they are defined, not in that where the constant value is used.
// TODO: how do we get the correct resolve context?
return new CSharpResolver(context) {
CheckForOverflow = false, // TODO: get project-wide overflow setting
CurrentTypeDefinition = parentTypeDefinition,
UsingScope = parentUsingScope
};
}
public IType GetValueType(ITypeResolveContext context)
{
CSharpResolver resolver = CreateResolver(context);
IType type = expression.Resolve(resolver).Type;
if (resolver.Context != context) {
// Retrieve the equivalent type in the new resolve context.
// E.g. if the constant is defined in a .NET 2.0 project, type might be Int32 from mscorlib 2.0.
// However, the calling project might be a .NET 4.0 project, so we need to return Int32 from mscorlib 4.0.
return type.AcceptVisitor(new MapTypeIntoNewContext(context));
}
return type;
}
public object GetValue(ITypeResolveContext context)
{
return expression.Resolve(CreateResolver(context)).ConstantValue;
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
expression = provider.Intern(expression);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return expression.GetHashCode()
^ (parentUsingScope != null ? parentUsingScope.GetHashCode() : 0)
^ (parentTypeDefinition != null ? parentTypeDefinition.GetHashCode() : 0);
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
CSharpConstantValue cv = other as CSharpConstantValue;
return cv != null
&& expression == cv.expression
&& parentUsingScope == cv.parentUsingScope
&& parentTypeDefinition == cv.parentTypeDefinition;
}
}
public abstract class ConstantExpression
{
public abstract ResolveResult Resolve(CSharpResolver resolver);
/// <summary>
/// Gets whether the returned value depends on the expression's context.
/// </summary>
public virtual bool DependsOnContext()
{
return true;
}
}
public sealed class PrimitiveConstantExpression : ConstantExpression, ISupportsInterning
{
ITypeReference type;
object value;
public PrimitiveConstantExpression(ITypeReference type, object value)
{
if (type == null)
throw new ArgumentNullException("type");
this.type = type;
this.value = value;
}
public override ResolveResult Resolve(CSharpResolver resolver)
{
return new ConstantResolveResult(type.Resolve(resolver.Context), value);
}
public override bool DependsOnContext()
{
// Depends on context unless the type is a known primitive type.
foreach (var knownTypeRef in KnownTypeReference.AllKnownTypeReferences) {
if (knownTypeRef == type)
return false;
}
return true;
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
type = provider.Intern(type);
value = provider.Intern(value);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return type.GetHashCode() ^ (value != null ? value.GetHashCode() : 0);
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
PrimitiveConstantExpression scv = other as PrimitiveConstantExpression;
return scv != null && type == scv.type && value == scv.value;
}
}
public sealed class ConstantCast : ConstantExpression, ISupportsInterning
{
ITypeReference targetType;
ConstantExpression expression;
public ConstantCast(ITypeReference targetType, ConstantExpression expression)
{
if (targetType == null)
throw new ArgumentNullException("targetType");
if (expression == null)
throw new ArgumentNullException("expression");
this.targetType = targetType;
this.expression = expression;
}
public override ResolveResult Resolve(CSharpResolver resolver)
{
return resolver.ResolveCast(targetType.Resolve(resolver.Context), expression.Resolve(resolver));
}
public override bool DependsOnContext()
{
return expression.DependsOnContext();
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
targetType = provider.Intern(targetType);
expression = provider.Intern(expression);
}
int ISupportsInterning.GetHashCodeForInterning()
{
unchecked {
return targetType.GetHashCode() + expression.GetHashCode() * 1018829;
}
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ConstantCast cast = other as ConstantCast;
return cast != null
&& this.targetType == cast.targetType && this.expression == cast.expression;
}
}
public sealed class ConstantIdentifierReference : ConstantExpression, ISupportsInterning
{
string identifier;
IList<ITypeReference> typeArguments;
public ConstantIdentifierReference(string identifier, IList<ITypeReference> 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<IType> ResolveTypes(CSharpResolver resolver, IList<ITypeReference> typeArguments)
{
if (typeArguments == null)
return EmptyList<IType>.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 sealed class ConstantMemberReference : ConstantExpression, ISupportsInterning
{
ITypeReference targetType;
ConstantExpression targetExpression;
string memberName;
IList<ITypeReference> typeArguments;
public ConstantMemberReference(ITypeReference targetType, string memberName, IList<ITypeReference> 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(ConstantExpression targetExpression, string memberName, IList<ITypeReference> 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 = targetExpression.Resolve(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 sealed class ConstantCheckedExpression : ConstantExpression, ISupportsInterning
{
bool checkForOverflow;
ConstantExpression expression;
public ConstantCheckedExpression(bool checkForOverflow, ConstantExpression expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
this.checkForOverflow = checkForOverflow;
this.expression = expression;
}
public override ResolveResult Resolve(CSharpResolver resolver)
{
bool oldCheckForOverflow = resolver.CheckForOverflow;
try {
resolver.CheckForOverflow = this.checkForOverflow;
return expression.Resolve(resolver);
} finally {
resolver.CheckForOverflow = oldCheckForOverflow;
}
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
expression = provider.Intern(expression);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return expression.GetHashCode() ^ (checkForOverflow ? 161851612 : 75163517);
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ConstantCheckedExpression cce = other as ConstantCheckedExpression;
return cce != null
&& this.expression == cce.expression
&& this.checkForOverflow == cce.checkForOverflow;
}
}
public sealed 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 sealed class ConstantUnaryOperator : ConstantExpression, ISupportsInterning
{
UnaryOperatorType operatorType;
ConstantExpression expression;
public ConstantUnaryOperator(UnaryOperatorType operatorType, ConstantExpression expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
this.operatorType = operatorType;
this.expression = expression;
}
public override ResolveResult Resolve(CSharpResolver resolver)
{
return resolver.ResolveUnaryOperator(operatorType, expression.Resolve(resolver));
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
expression = provider.Intern(expression);
}
int ISupportsInterning.GetHashCodeForInterning()
{
unchecked {
return expression.GetHashCode() * 811 + operatorType.GetHashCode();
}
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ConstantUnaryOperator uop = other as ConstantUnaryOperator;
return uop != null
&& this.operatorType == uop.operatorType
&& this.expression == uop.expression;
}
}
public sealed class ConstantBinaryOperator : ConstantExpression, ISupportsInterning
{
ConstantExpression left;
BinaryOperatorType operatorType;
ConstantExpression right;
public ConstantBinaryOperator(ConstantExpression left, BinaryOperatorType operatorType, ConstantExpression right)
{
if (left == null)
throw new ArgumentNullException("left");
if (right == null)
throw new ArgumentNullException("right");
this.left = left;
this.operatorType = operatorType;
this.right = right;
}
public override ResolveResult Resolve(CSharpResolver resolver)
{
ResolveResult lhs = left.Resolve(resolver);
ResolveResult rhs = right.Resolve(resolver);
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;
}
}
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;
}
}
public sealed class ConstantConditionalOperator : ConstantExpression, ISupportsInterning
{
ConstantExpression condition, trueExpr, falseExpr;
public ConstantConditionalOperator(ConstantExpression condition, ConstantExpression trueExpr, ConstantExpression 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(
condition.Resolve(resolver),
trueExpr.Resolve(resolver),
falseExpr.Resolve(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;
}
}
}