Browse Source

Add C# resolver.

newNRvisualizers
Daniel Grunwald 16 years ago
parent
commit
db8619113e
  1. 30
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs
  2. 1
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  3. 388
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  4. 29
      ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs
  5. 43
      ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs
  6. 22
      ICSharpCode.NRefactory/CSharp/Resolver/ErrorResolveResult.cs
  7. 40
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs
  8. 4
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  9. 48
      ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs
  10. 62
      ICSharpCode.NRefactory/TypeSystem/NullableType.cs
  11. 2
      NRefactory.sln

30
ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// Copyright (c) 2010 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 NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
[TestFixture]
public class UnaryOperatorTests
{
[Test]
public void TestMethod()
{
//var a = ~new X();
char a = 'a';
++a;
a++;
float b= 1;
++b;
b++;
}
}
class X
{
//public static implicit operator int(X a) { return 0; }
public static implicit operator LoaderOptimization(X a) { return 0; }
}
}

1
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -44,6 +44,7 @@ @@ -44,6 +44,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CSharp\Resolver\ConversionsTest.cs" />
<Compile Include="CSharp\Resolver\UnaryOperatorTests.cs" />
<Compile Include="FormattingTests\TestBraceStlye.cs" />
<Compile Include="FormattingTests\TestFormattingBugs.cs" />
<Compile Include="FormattingTests\TestSpacingVisitor.cs" />

388
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -0,0 +1,388 @@ @@ -0,0 +1,388 @@
// Copyright (c) 2010 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.Globalization;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Contains the main resolver logic.
/// </summary>
public class CSharpResolver
{
static readonly ResolveResult ErrorResult = new ErrorResolveResult(SharedTypes.UnknownType);
static readonly ResolveResult DynamicResult = new ResolveResult(SharedTypes.Dynamic);
readonly ITypeResolveContext context;
/// <summary>
/// Gets/Sets whether the current context is <c>checked</c>.
/// </summary>
public bool IsCheckedContext { get; set; }
public CSharpResolver(ITypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
#region class OperatorMethod
class OperatorMethod : Immutable, IMethod
{
IList<IParameter> parameters = new List<IParameter>();
public IList<IParameter> Parameters {
get { return parameters; }
}
public ITypeReference ReturnType {
get; set;
}
IList<IAttribute> IMethod.ReturnTypeAttributes {
get { return EmptyList<IAttribute>.Instance; }
}
IList<ITypeParameter> IMethod.TypeParameters {
get { return EmptyList<ITypeParameter>.Instance; }
}
bool IMethod.IsExtensionMethod {
get { return false; }
}
bool IMethod.IsConstructor {
get { return false; }
}
bool IMethod.IsDestructor {
get { return false; }
}
bool IMethod.IsOperator {
get { return true; }
}
ITypeDefinition IEntity.DeclaringTypeDefinition {
get { return null; }
}
ITypeDefinition IMember.DeclaringTypeDefinition {
get { return null; }
}
IType IMember.DeclaringType {
get { return null; }
}
IMember IMember.MemberDefinition {
get { return null; }
}
IList<IExplicitInterfaceImplementation> IMember.InterfaceImplementations {
get { return EmptyList<IExplicitInterfaceImplementation>.Instance; }
}
bool IMember.IsVirtual {
get { return false; }
}
bool IMember.IsOverride {
get { return false; }
}
bool IMember.IsOverridable {
get { return false; }
}
EntityType IEntity.EntityType {
get { return EntityType.Operator; }
}
DomRegion IEntity.Region {
get { return DomRegion.Empty; }
}
DomRegion IEntity.BodyRegion {
get { return DomRegion.Empty; }
}
IList<IAttribute> IEntity.Attributes {
get { return EmptyList<IAttribute>.Instance; }
}
string IEntity.Documentation {
get { return null; }
}
Accessibility IEntity.Accessibility {
get { return Accessibility.Public; }
}
bool IEntity.IsStatic {
get { return true; }
}
bool IEntity.IsAbstract {
get { return false; }
}
bool IEntity.IsSealed {
get { return false; }
}
bool IEntity.IsShadowing {
get { return false; }
}
bool IEntity.IsSynthetic {
get { return true; }
}
IProjectContent IEntity.ProjectContent {
get { return null; }
}
string INamedElement.FullName {
get { return "operator"; }
}
string INamedElement.Name {
get { return "operator"; }
}
string INamedElement.Namespace {
get { return string.Empty; }
}
string INamedElement.DotNetName {
get { return "operator"; }
}
}
#endregion
#region ResolveUnaryOperator
public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
{
if (expression.Type == SharedTypes.Dynamic)
return DynamicResult;
// C# 4.0 spec: §7.3.3 Unary operator overload resolution
string overloadableOperatorName = GetOverloadableOperatorName(op);
if (overloadableOperatorName == null) {
switch (op) {
case UnaryOperatorType.Dereference:
PointerType p = expression.Type as PointerType;
if (p != null)
return new ResolveResult(p.ElementType);
else
return ErrorResult;
case UnaryOperatorType.AddressOf:
return new ResolveResult(new PointerType(expression.Type));
default:
throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
}
}
// If the type is nullable, get the underlying type:
IType type = NullableType.GetUnderlyingType(expression.Type);
bool isNullable = type != null;
if (!isNullable)
type = expression.Type;
// the operator is overloadable:
// TODO: implicit support for user operators
//var candidateSet = GetUnaryOperatorCandidates();
UnaryOperatorMethod[] methodGroup;
switch (op) {
case UnaryOperatorType.Increment:
case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostIncrement:
case UnaryOperatorType.PostDecrement:
// C# 4.0 spec: §7.6.9 Postfix increment and decrement operators
// C# 4.0 spec: §7.7.5 Prefix increment and decrement operators
TypeCode code = ReflectionHelper.GetTypeCode(type);
if (type.IsEnum() || (code >= TypeCode.SByte && code <= TypeCode.Decimal))
return new ResolveResult(expression.Type);
else
return ErrorResult;
case UnaryOperatorType.Plus:
methodGroup = unaryPlusOperators;
break;
case UnaryOperatorType.Minus:
methodGroup = IsCheckedContext ? checkedUnaryMinusOperators : uncheckedUnaryMinusOperators;
break;
case UnaryOperatorType.Not:
methodGroup = logicalNegationOperator;
break;
case UnaryOperatorType.BitNot:
if (type.IsEnum()) {
if (expression.IsCompileTimeConstant && expression.ConstantValue != null) {
// evaluate as (E)(~(U)x);
var U = expression.ConstantValue.GetType().ToTypeReference().Resolve(context);
var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
return ResolveCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
} else {
return new ResolveResult(expression.Type);
}
} else {
methodGroup = bitwiseComplementOperators;
break;
}
default:
throw new InvalidOperationException();
}
throw new NotImplementedException();
}
object GetUserUnaryOperatorCandidates()
{
// C# 4.0 spec: §7.3.5 Candidate user-defined operators
throw new NotImplementedException();
}
static string GetOverloadableOperatorName(UnaryOperatorType op)
{
switch (op) {
case UnaryOperatorType.Not:
return "op_LogicalNot";
case UnaryOperatorType.BitNot:
return "op_OnesComplement";
case UnaryOperatorType.Minus:
return "op_UnaryNegation";
case UnaryOperatorType.Plus:
return "op_UnaryPlus";
case UnaryOperatorType.Increment:
case UnaryOperatorType.PostIncrement:
return "op_Increment";
case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostDecrement:
return "op_Decrement";
default:
return null;
}
}
abstract class UnaryOperatorMethod : OperatorMethod
{
public abstract object Invoke(object input);
}
sealed class LambdaUnaryOperatorMethod<T> : UnaryOperatorMethod
{
readonly Func<T, T> func;
public LambdaUnaryOperatorMethod(Func<T, T> func)
{
this.func = func;
}
public override object Invoke(object input)
{
return func((T)input);
}
}
sealed class LiftedUnaryOperatorMethod : UnaryOperatorMethod
{
UnaryOperatorMethod baseMethod;
public LiftedUnaryOperatorMethod(UnaryOperatorMethod baseMethod)
{
this.baseMethod = baseMethod;
this.ReturnType = NullableType.Create(baseMethod.ReturnType);
this.Parameters.Add(new DefaultParameter(NullableType.Create(baseMethod.Parameters[0].Type), string.Empty));
}
public override object Invoke(object input)
{
if (input == null)
return null;
else
return baseMethod.Invoke(input);
}
}
static UnaryOperatorMethod[] Lift(params UnaryOperatorMethod[] methods)
{
UnaryOperatorMethod[] lifted = new UnaryOperatorMethod[methods.Length * 2];
methods.CopyTo(lifted, 0);
for (int i = 0; i < methods.Length; i++) {
lifted[methods.Length + i] = new LiftedUnaryOperatorMethod(methods[i]);
}
return lifted;
}
// C# 4.0 spec: §7.7.1 Unary plus operator
static readonly UnaryOperatorMethod[] unaryPlusOperators = Lift(
new LambdaUnaryOperatorMethod<int>(i => +i),
new LambdaUnaryOperatorMethod<uint>(i => +i),
new LambdaUnaryOperatorMethod<long>(i => +i),
new LambdaUnaryOperatorMethod<ulong>(i => +i),
new LambdaUnaryOperatorMethod<float>(i => +i),
new LambdaUnaryOperatorMethod<double>(i => +i),
new LambdaUnaryOperatorMethod<decimal>(i => +i)
);
// C# 4.0 spec: §7.7.2 Unary minus operator
static readonly UnaryOperatorMethod[] uncheckedUnaryMinusOperators = Lift(
new LambdaUnaryOperatorMethod<int>(i => unchecked(-i)),
new LambdaUnaryOperatorMethod<long>(i => unchecked(-i)),
new LambdaUnaryOperatorMethod<float>(i => -i),
new LambdaUnaryOperatorMethod<double>(i => -i),
new LambdaUnaryOperatorMethod<decimal>(i => -i)
);
static readonly UnaryOperatorMethod[] checkedUnaryMinusOperators = Lift(
new LambdaUnaryOperatorMethod<int>(i => checked(-i)),
new LambdaUnaryOperatorMethod<long>(i => checked(-i)),
new LambdaUnaryOperatorMethod<float>(i => -i),
new LambdaUnaryOperatorMethod<double>(i => -i),
new LambdaUnaryOperatorMethod<decimal>(i => -i)
);
// C# 4.0 spec: §7.7.3 Logical negation operator
static readonly UnaryOperatorMethod[] logicalNegationOperator = Lift(new LambdaUnaryOperatorMethod<bool>(b => !b));
// C# 4.0 spec: §7.7.4 Bitwise complement operator
static readonly UnaryOperatorMethod[] bitwiseComplementOperators = Lift(
new LambdaUnaryOperatorMethod<int>(i => ~i),
new LambdaUnaryOperatorMethod<uint>(i => ~i),
new LambdaUnaryOperatorMethod<long>(i => ~i),
new LambdaUnaryOperatorMethod<ulong>(i => ~i)
);
#endregion
#region ResolveCast
public ResolveResult ResolveCast(IType targetType, ResolveResult expression)
{
if (expression.IsError)
return new ErrorResolveResult(targetType);
// C# 4.0 spec: §7.7.6 Cast expressions
if (expression.IsCompileTimeConstant) {
TypeCode code = ReflectionHelper.GetTypeCode(targetType);
if (code >= TypeCode.Boolean && code <= TypeCode.Decimal) {
try {
return new ConstantResolveResult(targetType, Convert.ChangeType(expression.ConstantValue, code, CultureInfo.InvariantCulture));
} catch (InvalidCastException) {
return new ErrorResolveResult(targetType);
}
} else if (code == TypeCode.String) {
if (expression.ConstantValue == null || expression.ConstantValue is string)
return new ConstantResolveResult(targetType, expression.ConstantValue);
else
return new ErrorResolveResult(targetType);
} else if (targetType.IsEnum()) {
throw new NotImplementedException();
}
}
return new ResolveResult(targetType);
}
#endregion
}
}

29
ICSharpCode.NRefactory/CSharp/Resolver/ConstantResolveResult.cs

@ -1,22 +1,29 @@ @@ -1,22 +1,29 @@

// Copyright (c) 2010 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
public class ConstantResolveResult
/// <summary>
/// ResolveResult representing a compile-time constant.
/// </summary>
public class ConstantResolveResult : ResolveResult
{
public IType Type { get; set; }
public object Value { get; set; }
object constantValue;
public ConstantResolveResult(IType type, object value)
public ConstantResolveResult(IType type, object constantValue) : base(type)
{
if (type == null)
throw new ArgumentNullException("type");
if (value == null)
throw new ArgumentNullException("value");
this.Type = type;
this.Value = value;
this.constantValue = constantValue;
}
public override bool IsCompileTimeConstant {
get { return true; }
}
public override object ConstantValue {
get { return constantValue; }
}
}
}

43
ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs

@ -26,12 +26,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -26,12 +26,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
#region ImplicitConversion
public bool ImplicitConversion(ConstantResolveResult resolveResult, IType toType)
public bool ImplicitConversion(ResolveResult resolveResult, IType toType)
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
ConstantResolveResult crr = resolveResult as ConstantResolveResult;
if (crr != null && (ImplicitEnumerationConversion(crr, toType) || ImplicitConstantExpressionConversion(crr, toType)))
if (resolveResult.IsCompileTimeConstant && (ImplicitEnumerationConversion(resolveResult, toType) || ImplicitConstantExpressionConversion(resolveResult, toType)))
return true;
return ImplicitConversion(resolveResult.Type, toType);
}
@ -126,14 +125,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -126,14 +125,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ImplicitEnumerationConversion
bool ImplicitEnumerationConversion(ConstantResolveResult rr, IType toType)
bool ImplicitEnumerationConversion(ResolveResult rr, IType toType)
{
// C# 4.0 spec: §6.1.3
TypeCode constantType = ReflectionHelper.GetTypeCode(rr.Type);
if (constantType >= TypeCode.SByte && constantType <= TypeCode.Decimal && Convert.ToDecimal(rr.Value) == 0) {
toType = UnpackNullable(toType) ?? toType;
ITypeDefinition toDef = toType.GetDefinition();
return toDef.ClassType == ClassType.Enum;
if (constantType >= TypeCode.SByte && constantType <= TypeCode.Decimal && Convert.ToDecimal(rr.ConstantValue) == 0) {
toType = NullableType.GetUnderlyingType(toType) ?? toType;
return toType.IsEnum();
}
return false;
}
@ -143,30 +141,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -143,30 +141,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool ImplicitNullableConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.4
IType t = UnpackNullable(toType);
IType t = NullableType.GetUnderlyingType(toType);
if (t != null) {
IType s = UnpackNullable(fromType) ?? fromType;
IType s = NullableType.GetUnderlyingType(fromType) ?? fromType;
return IdentityConversion(s, t) || ImplicitNumericConversion(s, t);
} else {
return false;
}
}
static IType UnpackNullable(IType type)
{
ParameterizedType pt = type as ParameterizedType;
if (pt != null && pt.TypeArguments.Count == 1 && pt.FullName == "System.Nullable")
return pt.TypeArguments[0];
else
return null;
}
#endregion
#region NullLiteralConversion
bool NullLiteralConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.5
return fromType == SharedTypes.Null && (UnpackNullable(toType) != null);
return fromType == SharedTypes.Null && NullableType.IsNullable(toType);
// This function only handles the conversion from the null literal to nullable value types,
// reference types are handled by ImplicitReferenceConversion instead.
}
@ -271,7 +260,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -271,7 +260,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool BoxingConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.7
fromType = UnpackNullable(fromType) ?? fromType;
fromType = NullableType.GetUnderlyingType(fromType) ?? fromType;
return fromType.IsReferenceType == false && toType.IsReferenceType == true && IsSubtypeOf(fromType, toType);
}
#endregion
@ -285,16 +274,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -285,16 +274,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ImplicitConstantExpressionConversion
bool ImplicitConstantExpressionConversion(ConstantResolveResult rr, IType toType)
bool ImplicitConstantExpressionConversion(ResolveResult rr, IType toType)
{
// C# 4.0 spec: §6.1.9
TypeCode fromTypeCode = ReflectionHelper.GetTypeCode(rr.Type);
TypeCode toTypeCode = ReflectionHelper.GetTypeCode(UnpackNullable(toType) ?? toType);
TypeCode toTypeCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(toType) ?? toType);
if (fromTypeCode == TypeCode.Int64) {
long val = (long)rr.Value;
long val = (long)rr.ConstantValue;
return val >= 0 && toTypeCode == TypeCode.UInt64;
} else if (fromTypeCode == TypeCode.Int32) {
int val = (int)rr.Value;
int val = (int)rr.ConstantValue;
switch (toTypeCode) {
case TypeCode.SByte:
return val >= SByte.MinValue && val <= SByte.MaxValue;
@ -321,10 +310,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -321,10 +310,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Gets the better conversion (C# 4.0 spec, §7.5.3.3)
/// </summary>
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
public int BetterConversion(ConstantResolveResult rr, IType t1, IType t2)
public int BetterConversion(ResolveResult resolveResult, IType t1, IType t2)
{
// TODO: implement the special logic for anonymous functions
return BetterConversion(rr.Type, t1, t2);
return BetterConversion(resolveResult.Type, t1, t2);
}
/// <summary>

22
ICSharpCode.NRefactory/CSharp/Resolver/ErrorResolveResult.cs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
// Copyright (c) 2010 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents a resolve error.
/// </summary>
public class ErrorResolveResult : ResolveResult
{
public ErrorResolveResult(IType type) : base(type)
{
}
public override bool IsError {
get { return true; }
}
}
}

40
ICSharpCode.NRefactory/CSharp/Resolver/ResolveResult.cs

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
// Copyright (c) 2010 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 ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents the result of resolving an expression.
/// </summary>
public class ResolveResult
{
IType type;
public ResolveResult(IType type)
{
if (type == null)
throw new ArgumentNullException("type");
this.type = type;
}
public IType Type {
get { return type; }
}
public virtual bool IsCompileTimeConstant {
get { return false; }
}
public virtual object ConstantValue {
get { return null; }
}
public virtual bool IsError {
get { return false; }
}
}
}

4
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -141,6 +141,9 @@ @@ -141,6 +141,9 @@
<Compile Include="CSharp\Parser\mcs\roottypes.cs" />
<Compile Include="CSharp\Resolver\ConstantResolveResult.cs" />
<Compile Include="CSharp\Resolver\Conversions.cs" />
<Compile Include="CSharp\Resolver\CSharpResolver.cs" />
<Compile Include="CSharp\Resolver\ErrorResolveResult.cs" />
<Compile Include="CSharp\Resolver\ResolveResult.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeSystem\Accessibility.cs" />
<Compile Include="TypeSystem\AmbiguousType.cs" />
@ -198,6 +201,7 @@ @@ -198,6 +201,7 @@
<Compile Include="TypeSystem\ITypeParameter.cs" />
<Compile Include="TypeSystem\ITypeReference.cs" />
<Compile Include="TypeSystem\ITypeResolveContext.cs" />
<Compile Include="TypeSystem\NullableType.cs" />
<Compile Include="TypeSystem\ParameterizedType.cs" />
<Compile Include="TypeSystem\TypeVisitor.cs" />
<Compile Include="TypeSystem\IVariable.cs" />

48
ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs

@ -13,6 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -13,6 +13,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary>
public static class ExtensionMethods
{
#region GetAllBaseTypes
/// <summary>
/// Gets all base types.
/// </summary>
@ -52,5 +53,52 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -52,5 +53,52 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (def != null)
activeTypeDefinitions.Pop();
}
#endregion
#region IsOpen / IsUnbound
sealed class TypeClassificationVisitor : TypeVisitor
{
internal bool isOpen;
public override IType VisitTypeParameter(ITypeParameter type)
{
isOpen = true;
return base.VisitTypeParameter(type);
}
}
/// <summary>
/// Gets whether the type is an open type (contains type parameters).
/// </summary>
public static bool IsOpen(this IType type)
{
if (type == null)
throw new ArgumentNullException("type");
TypeClassificationVisitor v = new TypeClassificationVisitor();
type.AcceptVisitor(v);
return v.isOpen;
}
/// <summary>
/// Gets whether the type is unbound.
/// </summary>
public static bool IsUnbound(this IType type)
{
if (type == null)
throw new ArgumentNullException("type");
return type is ITypeDefinition && type.TypeParameterCount > 0;
}
/// <summary>
/// Gets whether the type is an enumeration type.
/// </summary>
public static bool IsEnum(this IType type)
{
if (type == null)
throw new ArgumentNullException("type");
ITypeDefinition def = type.GetDefinition();
return def != null && def.ClassType == ClassType.Enum;
}
#endregion
}
}

62
ICSharpCode.NRefactory/TypeSystem/NullableType.cs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
// Copyright (c) 2010 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 ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{
/// <summary>
/// Static helper methods for working with nullable types.
/// </summary>
public static class NullableType
{
/// <summary>
/// Gets whether the specified type is a nullable type.
/// </summary>
public static bool IsNullable(IType type)
{
return GetUnderlyingType(type) != null;
}
/// <summary>
/// Returns the element type, if <paramref name="type"/> is a nullable type.
/// Otherwise, returns null.
/// </summary>
public static IType GetUnderlyingType(IType type)
{
ParameterizedType pt = type as ParameterizedType;
if (pt != null && pt.TypeArguments.Count == 1 && pt.FullName == "System.Nullable")
return pt.TypeArguments[0];
else
return null;
}
/// <summary>
/// Creates a nullable type.
/// </summary>
public static IType Create(IType elementType, ITypeResolveContext context)
{
if (elementType == null)
throw new ArgumentNullException("elementType");
if (context == null)
throw new ArgumentNullException("context");
ITypeDefinition nullable = context.GetClass("System.Nullable", 1, StringComparer.Ordinal);
if (nullable != null)
return new ParameterizedType(nullable, new [] { elementType });
else
return SharedTypes.UnknownType;
}
static readonly ITypeReference NullableReference = new GetClassTypeReference("System.Nullable", 1);
/// <summary>
/// Creates a nullable type reference.
/// </summary>
public static ITypeReference Create(ITypeReference elementType)
{
return new ParameterizedTypeReference(NullableReference, new [] { elementType });
}
}
}

2
NRefactory.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.0.0.6721
# SharpDevelop 4.0.0.6745
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DC98210E-1646-483B-819A-2BB8272461E4}"
ProjectSection(SolutionItems) = postProject
README = README

Loading…
Cancel
Save