1
ļ»æ// Copyright (c) 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
IConstantValue baseValue;
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
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
165
baseValue = provider.Intern(baseValue);
168
int ISupportsInterning.GetHashCodeForInterning()
171
return baseValue.GetHashCode() * 33 ^ incrementAmount;
175
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
177
IncrementConstantValue o = other as IncrementConstantValue;
178
return o != null && baseValue == o.baseValue && incrementAmount == o.incrementAmount;
183
/// C#'s equivalent to the SimpleConstantValue.
186
public sealed class PrimitiveConstantExpression : ConstantExpression, ISupportsInterning
191
public ITypeReference Type {
195
public object Value {
196
get { return value; }
199
public PrimitiveConstantExpression(ITypeReference type, object value)
202
throw new ArgumentNullException("type");
207
public override ResolveResult Resolve(CSharpResolver resolver)
209
return new ConstantResolveResult(type.Resolve(resolver.CurrentTypeResolveContext), value);
212
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
214
type = provider.Intern(type);
215
value = provider.Intern(value);
218
int ISupportsInterning.GetHashCodeForInterning()
220
return type.GetHashCode() ^ (value != null ? value.GetHashCode() : 0);
223
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
225
PrimitiveConstantExpression scv = other as PrimitiveConstantExpression;
226
return scv != null && type == scv.type && value == scv.value;
231
public sealed class TypeOfConstantExpression : ConstantExpression, ISupportsInterning
235
public ITypeReference Type {
239
public TypeOfConstantExpression(ITypeReference type)
244
public override ResolveResult Resolve(CSharpResolver resolver)
246
return resolver.ResolveTypeOf(type.Resolve(resolver.CurrentTypeResolveContext));
249
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
251
type = provider.Intern(type);
254
int ISupportsInterning.GetHashCodeForInterning()
256
return type.GetHashCode();
259
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
261
TypeOfConstantExpression o = other as TypeOfConstantExpression;
262
return o != null && type == o.type;
267
public sealed class ConstantCast : ConstantExpression, ISupportsInterning
269
ITypeReference targetType;
270
ConstantExpression expression;
272
public ConstantCast(ITypeReference targetType, ConstantExpression expression)
274
if (targetType == null)
275
throw new ArgumentNullException("targetType");
276
if (expression == null)
277
throw new ArgumentNullException("expression");
278
this.targetType = targetType;
279
this.expression = expression;
282
public override ResolveResult Resolve(CSharpResolver resolver)
284
return resolver.ResolveCast(targetType.Resolve(resolver.CurrentTypeResolveContext), expression.Resolve(resolver));
287
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
289
targetType = provider.Intern(targetType);
290
expression = provider.Intern(expression);
293
int ISupportsInterning.GetHashCodeForInterning()
296
return targetType.GetHashCode() + expression.GetHashCode() * 1018829;
300
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
302
ConstantCast cast = other as ConstantCast;
304
&& this.targetType == cast.targetType && this.expression == cast.expression;
309
public sealed class ConstantIdentifierReference : ConstantExpression, ISupportsInterning
312
IList<ITypeReference> typeArguments;
314
public ConstantIdentifierReference(string identifier, IList<ITypeReference> typeArguments = null)
316
if (identifier == null)
317
throw new ArgumentNullException("identifier");
318
this.identifier = identifier;
319
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
322
public override ResolveResult Resolve(CSharpResolver resolver)
324
return resolver.ResolveSimpleName(identifier, typeArguments.Resolve(resolver.CurrentTypeResolveContext));
327
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
329
identifier = provider.Intern(identifier);
330
typeArguments = provider.InternList(typeArguments);
333
int ISupportsInterning.GetHashCodeForInterning()
336
return identifier.GetHashCode() ^ typeArguments.GetHashCode();
340
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
342
ConstantIdentifierReference cir = other as ConstantIdentifierReference;
343
return cir != null &&
344
this.identifier == cir.identifier && this.typeArguments == cir.typeArguments;
349
public sealed class ConstantMemberReference : ConstantExpression, ISupportsInterning
351
ITypeReference targetType;
352
ConstantExpression targetExpression;
354
IList<ITypeReference> typeArguments;
356
public ConstantMemberReference(ITypeReference targetType, string memberName, IList<ITypeReference> typeArguments = null)
358
if (targetType == null)
359
throw new ArgumentNullException("targetType");
360
if (memberName == null)
361
throw new ArgumentNullException("memberName");
362
this.targetType = targetType;
363
this.memberName = memberName;
364
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
367
public ConstantMemberReference(ConstantExpression targetExpression, string memberName, IList<ITypeReference> typeArguments = null)
369
if (targetExpression == null)
370
throw new ArgumentNullException("targetExpression");
371
if (memberName == null)
372
throw new ArgumentNullException("memberName");
373
this.targetExpression = targetExpression;
374
this.memberName = memberName;
375
this.typeArguments = typeArguments ?? EmptyList<ITypeReference>.Instance;
378
public override ResolveResult Resolve(CSharpResolver resolver)
381
if (targetType != null)
382
rr = new TypeResolveResult(targetType.Resolve(resolver.CurrentTypeResolveContext));
384
rr = targetExpression.Resolve(resolver);
385
return resolver.ResolveMemberAccess(rr, memberName, typeArguments.Resolve(resolver.CurrentTypeResolveContext));
388
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
390
targetType = provider.Intern(targetType);
391
targetExpression = provider.Intern(targetExpression);
392
memberName = provider.Intern(memberName);
393
typeArguments = provider.InternList(typeArguments);
396
int ISupportsInterning.GetHashCodeForInterning()
400
if (targetType != null)
401
hashCode = targetType.GetHashCode();
403
hashCode = targetExpression.GetHashCode();
404
hashCode ^= memberName.GetHashCode();
405
hashCode ^= typeArguments.GetHashCode();
410
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
412
ConstantMemberReference cmr = other as ConstantMemberReference;
414
&& this.targetType == cmr.targetType && this.targetExpression == cmr.targetExpression
415
&& this.memberName == cmr.memberName && this.typeArguments == cmr.typeArguments;
420
public sealed class ConstantCheckedExpression : ConstantExpression, ISupportsInterning
422
bool checkForOverflow;
423
ConstantExpression expression;
425
public ConstantCheckedExpression(bool checkForOverflow, ConstantExpression expression)
427
if (expression == null)
428
throw new ArgumentNullException("expression");
429
this.checkForOverflow = checkForOverflow;
430
this.expression = expression;
433
public override ResolveResult Resolve(CSharpResolver resolver)
435
return expression.Resolve(resolver.WithCheckForOverflow(checkForOverflow));
438
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
440
expression = provider.Intern(expression);
443
int ISupportsInterning.GetHashCodeForInterning()
445
return expression.GetHashCode() ^ (checkForOverflow ? 161851612 : 75163517);
448
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
450
ConstantCheckedExpression cce = other as ConstantCheckedExpression;
452
&& this.expression == cce.expression
453
&& this.checkForOverflow == cce.checkForOverflow;
458
public sealed class ConstantDefaultValue : ConstantExpression, ISupportsInterning
462
public ConstantDefaultValue(ITypeReference type)
465
throw new ArgumentNullException("type");
469
public override ResolveResult Resolve(CSharpResolver resolver)
471
return resolver.ResolveDefaultValue(type.Resolve(resolver.CurrentTypeResolveContext));
474
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
476
type = provider.Intern(type);
479
int ISupportsInterning.GetHashCodeForInterning()
481
return type.GetHashCode();
484
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
486
ConstantDefaultValue o = other as ConstantDefaultValue;
487
return o != null && this.type == o.type;
492
public sealed class ConstantUnaryOperator : ConstantExpression, ISupportsInterning
494
UnaryOperatorType operatorType;
495
ConstantExpression expression;
497
public ConstantUnaryOperator(UnaryOperatorType operatorType, ConstantExpression expression)
499
if (expression == null)
500
throw new ArgumentNullException("expression");
501
this.operatorType = operatorType;
502
this.expression = expression;
505
public override ResolveResult Resolve(CSharpResolver resolver)
507
return resolver.ResolveUnaryOperator(operatorType, expression.Resolve(resolver));
510
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
512
expression = provider.Intern(expression);
515
int ISupportsInterning.GetHashCodeForInterning()
518
return expression.GetHashCode() * 811 + operatorType.GetHashCode();
522
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
524
ConstantUnaryOperator uop = other as ConstantUnaryOperator;
526
&& this.operatorType == uop.operatorType
527
&& this.expression == uop.expression;
532
public sealed class ConstantBinaryOperator : ConstantExpression, ISupportsInterning
534
ConstantExpression left;
535
BinaryOperatorType operatorType;
536
ConstantExpression right;
538
public ConstantBinaryOperator(ConstantExpression left, BinaryOperatorType operatorType, ConstantExpression right)
541
throw new ArgumentNullException("left");
543
throw new ArgumentNullException("right");
545
this.operatorType = operatorType;
549
public override ResolveResult Resolve(CSharpResolver resolver)
551
ResolveResult lhs = left.Resolve(resolver);
552
ResolveResult rhs = right.Resolve(resolver);
553
return resolver.ResolveBinaryOperator(operatorType, lhs, rhs);
556
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
558
left = provider.Intern(left);
559
right = provider.Intern(right);
562
int ISupportsInterning.GetHashCodeForInterning()
565
return left.GetHashCode() * 811 + operatorType.GetHashCode() + right.GetHashCode() * 91781;
569
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
571
ConstantBinaryOperator bop = other as ConstantBinaryOperator;
573
&& this.operatorType == bop.operatorType
574
&& this.left == bop.left && this.right == bop.right;
579
public sealed class ConstantConditionalOperator : ConstantExpression, ISupportsInterning
581
ConstantExpression condition, trueExpr, falseExpr;
583
public ConstantConditionalOperator(ConstantExpression condition, ConstantExpression trueExpr, ConstantExpression falseExpr)
585
if (condition == null)
586
throw new ArgumentNullException("condition");
587
if (trueExpr == null)
588
throw new ArgumentNullException("trueExpr");
589
if (falseExpr == null)
590
throw new ArgumentNullException("falseExpr");
591
this.condition = condition;
592
this.trueExpr = trueExpr;
593
this.falseExpr = falseExpr;
596
public override ResolveResult Resolve(CSharpResolver resolver)
598
return resolver.ResolveConditional(
599
condition.Resolve(resolver),
600
trueExpr.Resolve(resolver),
601
falseExpr.Resolve(resolver)
605
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
607
condition = provider.Intern(condition);
608
trueExpr = provider.Intern(trueExpr);
609
falseExpr = provider.Intern(falseExpr);
612
int ISupportsInterning.GetHashCodeForInterning()
615
return condition.GetHashCode() * 182981713
616
+ trueExpr.GetHashCode() * 917517169
617
+ falseExpr.GetHashCode() * 611651;
621
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
623
ConstantConditionalOperator coo = other as ConstantConditionalOperator;
625
&& this.condition == coo.condition
626
&& this.trueExpr == coo.trueExpr
627
&& this.falseExpr == coo.falseExpr;
632
/// Represents an array creation (as used within an attribute argument)
635
public sealed class ConstantArrayCreation : ConstantExpression, ISupportsInterning
637
// type may be null when the element is being inferred
638
ITypeReference elementType;
639
IList<ConstantExpression> arrayElements;
641
public ConstantArrayCreation(ITypeReference type, IList<ConstantExpression> arrayElements)
643
if (arrayElements == null)
644
throw new ArgumentNullException("arrayElements");
645
this.elementType = type;
646
this.arrayElements = arrayElements;
649
public override ResolveResult Resolve(CSharpResolver resolver)
651
ResolveResult[] elements = new ResolveResult[arrayElements.Count];
652
for (int i = 0; i < elements.Length; i++) {
653
elements[i] = arrayElements[i].Resolve(resolver);
655
if (elementType != null) {
656
return resolver.ResolveArrayCreation(elementType.Resolve(resolver.CurrentTypeResolveContext), 1, null, elements);
658
return resolver.ResolveArrayCreation(null, 1, null, elements);
662
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
664
elementType = provider.Intern(elementType);
665
arrayElements = provider.InternList(arrayElements);
668
int ISupportsInterning.GetHashCodeForInterning()
670
return (elementType != null ? elementType.GetHashCode() : 0) ^ arrayElements.GetHashCode();
673
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
675
ConstantArrayCreation cac = other as ConstantArrayCreation;
676
return cac != null && this.elementType == cac.elementType && this.arrayElements == cac.arrayElements;