1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
22
using ICSharpCode.NRefactory.CSharp.Analysis;
23
using ICSharpCode.NRefactory.CSharp.Resolver;
24
using ICSharpCode.NRefactory.Semantics;
25
using ICSharpCode.NRefactory.TypeSystem;
26
using ICSharpCode.NRefactory.TypeSystem.Implementation;
27
using ICSharpCode.NRefactory.Utils;
29
namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues
31
// Contains representations for constant C# expressions.
32
// We use these instead of storing the full AST to reduce the memory usage.
35
public abstract class ConstantExpression : IConstantValue
37
public abstract ResolveResult Resolve(CSharpResolver resolver);
39
public ResolveResult Resolve(ITypeResolveContext context)
41
var csContext = (CSharpTypeResolveContext)context;
42
if (context.CurrentAssembly != context.Compilation.MainAssembly) {
43
// The constant needs to be resolved in a different compilation.
44
IProjectContent pc = context.CurrentAssembly as IProjectContent;
46
ICompilation nestedCompilation = context.Compilation.SolutionSnapshot.GetCompilation(pc);
47
if (nestedCompilation != null) {
48
var nestedContext = MapToNestedCompilation(csContext, nestedCompilation);
49
ResolveResult rr = Resolve(new CSharpResolver(nestedContext));
50
return MapToNewContext(rr, context);
54
// Resolve in current context.
55
return Resolve(new CSharpResolver(csContext));
58
CSharpTypeResolveContext MapToNestedCompilation(CSharpTypeResolveContext context, ICompilation nestedCompilation)
60
var nestedContext = new CSharpTypeResolveContext(nestedCompilation.MainAssembly);
61
if (context.CurrentUsingScope != null) {
62
nestedContext = nestedContext.WithUsingScope(context.CurrentUsingScope.UnresolvedUsingScope.Resolve(nestedCompilation));
64
if (context.CurrentTypeDefinition != null) {
65
nestedContext = nestedContext.WithCurrentTypeDefinition(nestedCompilation.Import(context.CurrentTypeDefinition));
70
static ResolveResult MapToNewContext(ResolveResult rr, ITypeResolveContext newContext)
72
if (rr is TypeOfResolveResult) {
73
return new TypeOfResolveResult(
74
rr.Type.ToTypeReference().Resolve(newContext),
75
((TypeOfResolveResult)rr).ReferencedType.ToTypeReference().Resolve(newContext));
76
} else if (rr is ArrayCreateResolveResult) {
77
ArrayCreateResolveResult acrr = (ArrayCreateResolveResult)rr;
78
return new ArrayCreateResolveResult(
79
acrr.Type.ToTypeReference().Resolve(newContext),
80
MapToNewContext(acrr.SizeArguments, newContext),
81
MapToNewContext(acrr.InitializerElements, newContext));
82
} else if (rr.IsCompileTimeConstant) {
83
return new ConstantResolveResult(
84
rr.Type.ToTypeReference().Resolve(newContext),
88
return new ErrorResolveResult(rr.Type.ToTypeReference().Resolve(newContext));
92
static ResolveResult[] MapToNewContext(IList<ResolveResult> input, ITypeResolveContext newContext)
96
ResolveResult[] output = new ResolveResult[input.Count];
97
for (int i = 0; i < output.Length; i++) {
98
output[i] = MapToNewContext(input[i], newContext);
105
/// Used for constants that could not be converted to IConstantValue.
108
public sealed class ErrorConstantValue : IConstantValue
110
readonly ITypeReference type;
112
public ErrorConstantValue(ITypeReference type)
115
throw new ArgumentNullException("type");
119
public ResolveResult Resolve(ITypeResolveContext context)
121
return new ErrorResolveResult(type.Resolve(context));
126
/// Increments an integer <see cref="IConstantValue"/> by a fixed amount without changing the type.
129
public sealed class IncrementConstantValue : IConstantValue, ISupportsInterning
131
readonly IConstantValue baseValue;
132
readonly int incrementAmount;
134
public IncrementConstantValue(IConstantValue baseValue, int incrementAmount = 1)
136
if (baseValue == null)
137
throw new ArgumentNullException("baseValue");
138
IncrementConstantValue icv = baseValue as IncrementConstantValue;
140
this.baseValue = icv.baseValue;
141
this.incrementAmount = icv.incrementAmount + incrementAmount;
143
this.baseValue = baseValue;
144
this.incrementAmount = incrementAmount;
148
public ResolveResult Resolve(ITypeResolveContext context)
150
ResolveResult rr = baseValue.Resolve(context);
151
if (rr.IsCompileTimeConstant && rr.ConstantValue != null) {
152
object val = rr.ConstantValue;
153
TypeCode typeCode = Type.GetTypeCode(val.GetType());
154
if (typeCode >= TypeCode.SByte && typeCode <= TypeCode.UInt64) {
155
long intVal = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, val, false);
156
object newVal = CSharpPrimitiveCast.Cast(typeCode, unchecked(intVal + incrementAmount), false);
157
return new ConstantResolveResult(rr.Type, newVal);
160
return new ErrorResolveResult(rr.Type);
163
int ISupportsInterning.GetHashCodeForInterning()
166
return baseValue.GetHashCode() * 33 ^ incrementAmount;
170
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
172
IncrementConstantValue o = other as IncrementConstantValue;
173
return o != null && baseValue == o.baseValue && incrementAmount == o.incrementAmount;
178
/// C#'s equivalent to the SimpleConstantValue.
181
public sealed class PrimitiveConstantExpression : ConstantExpression, ISupportsInterning
183
readonly ITypeReference type;
184
readonly object value;
186
public ITypeReference Type {
190
public object Value {
191
get { return value; }
194
public PrimitiveConstantExpression(ITypeReference type, object value)
197
throw new ArgumentNullException("type");
202
public override ResolveResult Resolve(CSharpResolver resolver)
204
return new ConstantResolveResult(type.Resolve(resolver.CurrentTypeResolveContext), value);
207
int ISupportsInterning.GetHashCodeForInterning()
209
return type.GetHashCode() ^ (value != null ? value.GetHashCode() : 0);
212
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
214
PrimitiveConstantExpression scv = other as PrimitiveConstantExpression;
215
return scv != null && type == scv.type && value == scv.value;
220
public sealed class TypeOfConstantExpression : ConstantExpression
222
readonly ITypeReference type;
224
public ITypeReference Type {
228
public TypeOfConstantExpression(ITypeReference type)
233
public override ResolveResult Resolve(CSharpResolver resolver)
235
return resolver.ResolveTypeOf(type.Resolve(resolver.CurrentTypeResolveContext));
240
public sealed class ConstantCast : ConstantExpression, ISupportsInterning
242
readonly ITypeReference targetType;
243
readonly ConstantExpression expression;
245
public ConstantCast(ITypeReference targetType, ConstantExpression expression)
247
if (targetType == null)
248
throw new ArgumentNullException("targetType");
249
if (expression == null)
250
throw new ArgumentNullException("expression");
251
this.targetType = targetType;
252
this.expression = expression;
255
public override ResolveResult Resolve(CSharpResolver resolver)
257
return resolver.ResolveCast(targetType.Resolve(resolver.CurrentTypeResolveContext), expression.Resolve(resolver));
260
int ISupportsInterning.GetHashCodeForInterning()
263
return targetType.GetHashCode() + expression.GetHashCode() * 1018829;
267
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
269
ConstantCast cast = other as ConstantCast;
271
&& this.targetType == cast.targetType && this.expression == cast.expression;
276
public sealed class ConstantIdentifierReference : ConstantExpression
278
readonly string identifier;
279
readonly IList<ITypeReference> typeArguments;
281
public ConstantIdentifierReference(string identifier, IList<ITypeReference> typeArguments = null)
283
if (identifier == null)
284
throw new ArgumentNullException("identifier");
285
this.identifier = identifier;
286
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
289
public override ResolveResult Resolve(CSharpResolver resolver)
291
return resolver.ResolveSimpleName(identifier, typeArguments.Resolve(resolver.CurrentTypeResolveContext));
296
public sealed class ConstantMemberReference : ConstantExpression
298
readonly ITypeReference targetType;
299
readonly ConstantExpression targetExpression;
300
readonly string memberName;
301
readonly IList<ITypeReference> typeArguments;
303
public ConstantMemberReference(ITypeReference targetType, string memberName, IList<ITypeReference> typeArguments = null)
305
if (targetType == null)
306
throw new ArgumentNullException("targetType");
307
if (memberName == null)
308
throw new ArgumentNullException("memberName");
309
this.targetType = targetType;
310
this.memberName = memberName;
311
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
314
public ConstantMemberReference(ConstantExpression targetExpression, string memberName, IList<ITypeReference> typeArguments = null)
316
if (targetExpression == null)
317
throw new ArgumentNullException("targetExpression");
318
if (memberName == null)
319
throw new ArgumentNullException("memberName");
320
this.targetExpression = targetExpression;
321
this.memberName = memberName;
322
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
325
public override ResolveResult Resolve(CSharpResolver resolver)
328
if (targetType != null)
329
rr = new TypeResolveResult(targetType.Resolve(resolver.CurrentTypeResolveContext));
331
rr = targetExpression.Resolve(resolver);
332
return resolver.ResolveMemberAccess(rr, memberName, typeArguments.Resolve(resolver.CurrentTypeResolveContext));
337
public sealed class ConstantCheckedExpression : ConstantExpression
339
readonly bool checkForOverflow;
340
readonly ConstantExpression expression;
342
public ConstantCheckedExpression(bool checkForOverflow, ConstantExpression expression)
344
if (expression == null)
345
throw new ArgumentNullException("expression");
346
this.checkForOverflow = checkForOverflow;
347
this.expression = expression;
350
public override ResolveResult Resolve(CSharpResolver resolver)
352
return expression.Resolve(resolver.WithCheckForOverflow(checkForOverflow));
357
public sealed class ConstantDefaultValue : ConstantExpression, ISupportsInterning
359
readonly ITypeReference type;
361
public ConstantDefaultValue(ITypeReference type)
364
throw new ArgumentNullException("type");
368
public override ResolveResult Resolve(CSharpResolver resolver)
370
return resolver.ResolveDefaultValue(type.Resolve(resolver.CurrentTypeResolveContext));
373
int ISupportsInterning.GetHashCodeForInterning()
375
return type.GetHashCode();
378
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
380
ConstantDefaultValue o = other as ConstantDefaultValue;
381
return o != null && this.type == o.type;
386
public sealed class ConstantUnaryOperator : ConstantExpression
388
readonly UnaryOperatorType operatorType;
389
readonly ConstantExpression expression;
391
public ConstantUnaryOperator(UnaryOperatorType operatorType, ConstantExpression expression)
393
if (expression == null)
394
throw new ArgumentNullException("expression");
395
this.operatorType = operatorType;
396
this.expression = expression;
399
public override ResolveResult Resolve(CSharpResolver resolver)
401
return resolver.ResolveUnaryOperator(operatorType, expression.Resolve(resolver));
406
public sealed class ConstantBinaryOperator : ConstantExpression
408
readonly ConstantExpression left;
409
readonly BinaryOperatorType operatorType;
410
readonly ConstantExpression right;
412
public ConstantBinaryOperator(ConstantExpression left, BinaryOperatorType operatorType, ConstantExpression right)
415
throw new ArgumentNullException("left");
417
throw new ArgumentNullException("right");
419
this.operatorType = operatorType;
423
public override ResolveResult Resolve(CSharpResolver resolver)
425
ResolveResult lhs = left.Resolve(resolver);
426
ResolveResult rhs = right.Resolve(resolver);
427
return resolver.ResolveBinaryOperator(operatorType, lhs, rhs);
432
public sealed class ConstantConditionalOperator : ConstantExpression
434
readonly ConstantExpression condition, trueExpr, falseExpr;
436
public ConstantConditionalOperator(ConstantExpression condition, ConstantExpression trueExpr, ConstantExpression falseExpr)
438
if (condition == null)
439
throw new ArgumentNullException("condition");
440
if (trueExpr == null)
441
throw new ArgumentNullException("trueExpr");
442
if (falseExpr == null)
443
throw new ArgumentNullException("falseExpr");
444
this.condition = condition;
445
this.trueExpr = trueExpr;
446
this.falseExpr = falseExpr;
449
public override ResolveResult Resolve(CSharpResolver resolver)
451
return resolver.ResolveConditional(
452
condition.Resolve(resolver),
453
trueExpr.Resolve(resolver),
454
falseExpr.Resolve(resolver)
460
/// Represents an array creation (as used within an attribute argument)
463
public sealed class ConstantArrayCreation : ConstantExpression
465
// type may be null when the element is being inferred
466
readonly ITypeReference elementType;
467
readonly IList<ConstantExpression> arrayElements;
469
public ConstantArrayCreation(ITypeReference type, IList<ConstantExpression> arrayElements)
471
if (arrayElements == null)
472
throw new ArgumentNullException("arrayElements");
473
this.elementType = type;
474
this.arrayElements = arrayElements;
477
public override ResolveResult Resolve(CSharpResolver resolver)
479
ResolveResult[] elements = new ResolveResult[arrayElements.Count];
480
for (int i = 0; i < elements.Length; i++) {
481
elements[i] = arrayElements[i].Resolve(resolver);
483
int[] sizeArguments = { elements.Length };
484
if (elementType != null) {
485
return resolver.ResolveArrayCreation(elementType.Resolve(resolver.CurrentTypeResolveContext), sizeArguments, elements);
487
return resolver.ResolveArrayCreation(null, sizeArguments, elements);
493
/// Used for sizeof() expressions in constants.
496
public sealed class SizeOfConstantValue : ConstantExpression
498
readonly ITypeReference type;
500
public SizeOfConstantValue(ITypeReference type)
503
throw new ArgumentNullException("type");
507
public override ResolveResult Resolve(CSharpResolver resolver)
509
return resolver.ResolveSizeOf(type.Resolve(resolver.CurrentTypeResolveContext));