Browse Source

C# type system convert visitor: add support for attribute arguments.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
5d83bea67f
  1. 65
      ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs
  2. 109
      ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs

65
ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs

@ -159,6 +159,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -159,6 +159,8 @@ namespace ICSharpCode.NRefactory.CSharp
member.AcceptVisitor(this, data);
}
td.HasExtensionMethods = td.Methods.Any(m => m.IsExtensionMethod);
currentTypeDefinition = (DefaultTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition;
return td;
}
@ -745,25 +747,36 @@ namespace ICSharpCode.NRefactory.CSharp @@ -745,25 +747,36 @@ namespace ICSharpCode.NRefactory.CSharp
ConstantExpression c = expression.AcceptVisitor(b, null);
if (c == null)
return null;
// cast to the desired type
c = new ConstantCast(targetType, c);
if (c.DependsOnContext()) {
return new CSharpConstantValue(c, usingScope, currentTypeDefinition);
} else {
// If the expression does not depend on the context,
// we can resolve it immediately and store the value only.
return new SimpleConstantValue(targetType, c.Resolve(new CSharpResolver(MinimalResolveContext.Instance)).ConstantValue);
PrimitiveConstantExpression pc = c as PrimitiveConstantExpression;
if (pc != null && pc.Type == targetType) {
// Save memory by directly using a SimpleConstantValue.
return new SimpleConstantValue(targetType, pc.Value);
}
// cast to the desired type
return new CSharpConstantValue(new ConstantCast(targetType, c), usingScope, currentTypeDefinition);
}
IConstantValue ConvertAttributeArgument(Expression expression)
{
throw new NotImplementedException();
ConstantValueBuilder b = new ConstantValueBuilder();
b.convertVisitor = this;
b.isAttributeArgument = true;
ConstantExpression c = expression.AcceptVisitor(b, null);
if (c == null)
return null;
PrimitiveConstantExpression pc = c as PrimitiveConstantExpression;
if (pc != null) {
// Save memory by directly using a SimpleConstantValue.
return new SimpleConstantValue(pc.Type, pc.Value);
} else {
return new CSharpConstantValue(c, usingScope, currentTypeDefinition);
}
}
sealed class ConstantValueBuilder : DepthFirstAstVisitor<object, ConstantExpression>
{
internal TypeSystemConvertVisitor convertVisitor;
internal bool isAttributeArgument;
protected override ConstantExpression VisitChildren(AstNode node, object data)
{
@ -877,6 +890,40 @@ namespace ICSharpCode.NRefactory.CSharp @@ -877,6 +890,40 @@ namespace ICSharpCode.NRefactory.CSharp
return null;
return new ConstantBinaryOperator(left, binaryOperatorExpression.Operator, right);
}
static readonly GetClassTypeReference systemType = new GetClassTypeReference("System", "Type", 0);
public override ConstantExpression VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
{
if (isAttributeArgument) {
return new PrimitiveConstantExpression(systemType, convertVisitor.ConvertType(typeOfExpression.Type));
} else {
return null;
}
}
public override ConstantExpression VisitArrayCreateExpression(ArrayCreateExpression arrayObjectCreateExpression, object data)
{
var initializer = arrayObjectCreateExpression.Initializer;
if (isAttributeArgument && !initializer.IsNull) {
ITypeReference type;
if (arrayObjectCreateExpression.Type.IsNull)
type = null;
else
type = convertVisitor.ConvertType(arrayObjectCreateExpression.Type);
ConstantExpression[] elements = new ConstantExpression[initializer.Elements.Count];
int pos = 0;
foreach (Expression expr in initializer.Elements) {
ConstantExpression c = expr.AcceptVisitor(this, data);
if (c == null)
return null;
elements[pos++] = c;
}
return new ConstantArrayCreation(type, elements);
} else {
return null;
}
}
}
#endregion

109
ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs

@ -14,7 +14,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues @@ -14,7 +14,7 @@ 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
public sealed class CSharpConstantValue : Immutable, IConstantValue, ISupportsInterning
{
ConstantExpression expression;
UsingScope parentUsingScope;
@ -56,7 +56,33 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues @@ -56,7 +56,33 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues
public object GetValue(ITypeResolveContext context)
{
return expression.Resolve(CreateResolver(context)).ConstantValue;
CSharpResolver resolver = CreateResolver(context);
object val = expression.Resolve(resolver).ConstantValue;
if (resolver.Context != context) {
// If 'val' is a type or an array containing types, we need to map it to the new context.
val = MapToNewContext(val, context);
}
return val;
}
static object MapToNewContext(object val, ITypeResolveContext context)
{
IType type = val as IType;
if (type != null) {
return type.AcceptVisitor(new MapTypeIntoNewContext(context));
}
object[] arr = val as object[];
if (arr != null) {
object[] newArr = new object[arr.Length];
bool modified = false;
for (int i = 0; i < arr.Length; i++) {
newArr[i] = MapToNewContext(arr[i], context);
modified |= arr[i] != newArr[i];
}
if (modified)
return newArr;
}
return val;
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
@ -84,21 +110,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues @@ -84,21 +110,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues
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;
}
}
/// <summary>
/// C#'s equivalent to the SimpleConstantValue.
/// </summary>
public sealed class PrimitiveConstantExpression : ConstantExpression, ISupportsInterning
{
ITypeReference type;
object value;
public ITypeReference Type {
get { return type; }
}
public object Value {
get { return value; }
}
public PrimitiveConstantExpression(ITypeReference type, object value)
{
if (type == null)
@ -109,17 +138,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues @@ -109,17 +138,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues
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;
object val = value;
if (val is ITypeReference)
val = ((ITypeReference)val).Resolve(resolver.Context);
return new ConstantResolveResult(type.Resolve(resolver.Context), val);
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
@ -160,11 +182,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues @@ -160,11 +182,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues
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);
@ -522,4 +539,44 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues @@ -522,4 +539,44 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues
&& this.falseExpr == coo.falseExpr;
}
}
/// <summary>
/// Represents an array creation (as used within an attribute argument)
/// </summary>
public sealed class ConstantArrayCreation : ConstantExpression, ISupportsInterning
{
// type may be null when the element is being inferred
ITypeReference type;
IList<ConstantExpression> arrayElements;
public ConstantArrayCreation(ITypeReference type, IList<ConstantExpression> arrayElements)
{
if (arrayElements == null)
throw new ArgumentNullException("arrayElements");
this.type = type;
this.arrayElements = arrayElements;
}
public override ResolveResult Resolve(CSharpResolver resolver)
{
throw new NotImplementedException();
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
type = provider.Intern(type);
arrayElements = provider.InternList(arrayElements);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return (type != null ? type.GetHashCode() : 0) ^ arrayElements.GetHashCode();
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ConstantArrayCreation cac = other as ConstantArrayCreation;
return cac != null && this.type == cac.type && this.arrayElements == cac.arrayElements;
}
}
}

Loading…
Cancel
Save