diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 1aa8d4b578..58c2b2ece1 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -2233,8 +2233,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public ResolveResult ResolveSizeOf(IType type) { IType int32 = compilation.FindType(KnownTypeCode.Int32); - int size; - switch (ReflectionHelper.GetTypeCode(type)) { + int? size = null; + var typeForConstant = (type.Kind == TypeKind.Enum) ? type.GetDefinition().EnumUnderlyingType : type; + + switch (ReflectionHelper.GetTypeCode(typeForConstant)) { case TypeCode.Boolean: case TypeCode.SByte: case TypeCode.Byte: @@ -2255,10 +2257,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver case TypeCode.Double: size = 8; break; - default: - return new ResolveResult(int32); } - return new ConstantResolveResult(int32, size); + return new SizeOfResolveResult(int32, type, size); } #endregion diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs index 79ed801716..4802837e36 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs @@ -488,4 +488,25 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues } } } + + /// + /// Used for sizeof() expressions in constants. + /// + [Serializable] + public sealed class SizeOfConstantValue : ConstantExpression + { + readonly ITypeReference type; + + public SizeOfConstantValue(ITypeReference type) + { + if (type == null) + throw new ArgumentNullException("type"); + this.type = type; + } + + public override ResolveResult Resolve(CSharpResolver resolver) + { + return resolver.ResolveSizeOf(type.Resolve(resolver.CurrentTypeResolveContext)); + } + } } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs index 94f5159151..be50d2e671 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs @@ -978,6 +978,10 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem return interningProvider.Intern( new PrimitiveConstantExpression(KnownTypeReference.Object, null)); } + + public override ConstantExpression VisitSizeOfExpression(SizeOfExpression sizeOfExpression) { + return new SizeOfConstantValue(sizeOfExpression.Type.ToTypeReference(NameLookupMode.Type, interningProvider)); + } public override ConstantExpression VisitPrimitiveExpression(PrimitiveExpression primitiveExpression) { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SizeOfTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SizeOfTests.cs new file mode 100644 index 0000000000..627d026fb9 --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/SizeOfTests.cs @@ -0,0 +1,122 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.Semantics; +using NUnit.Framework; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + [TestFixture] + public class SizeOfTests : ResolverTestBase + { + [Test] + public void SizeOfPrimitiveTypes() + { + foreach (var t in new[] { new { t = "sbyte", n = 1 }, + new { t = "byte", n = 1 }, + new { t = "short", n = 2 }, + new { t = "ushort", n = 2 }, + new { t = "int", n = 4 }, + new { t = "uint", n = 4 }, + new { t = "long", n = 8 }, + new { t = "ulong", n = 8 }, + new { t = "char", n = 2 }, + new { t = "float", n = 4 }, + new { t = "double", n = 8 }, + new { t = "bool", n = 1 } + }) { + string program = @"using System; + class TestClass { + static void Main() { + public int s = $sizeof(" + t.t + @")$; + } + }"; + var rr = Resolve(program); + Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32)); + Assert.IsFalse(rr.IsError); + Assert.AreEqual(t.n, rr.ConstantValue); + Assert.IsTrue(Type.GetType(rr.ReferencedType.FullName).IsPrimitive); + } + } + + [Test] + public void SizeOfEnum() + { + string program = @" +enum TestEnum {} +class TestClass { + static void Main() { + int s = $sizeof(TestEnum)$; + } +}"; + var rr = Resolve(program); + Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32)); + Assert.IsFalse(rr.IsError); + Assert.AreEqual(4, rr.ConstantValue); + Assert.AreEqual("TestEnum", rr.ReferencedType.Name); + + program = @" +enum TestEnum2 : short {} +class TestClass { + static void Main() { + int s = $sizeof(TestEnum2)$; + } +}"; + rr = Resolve(program); + Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32)); + Assert.IsFalse(rr.IsError); + Assert.AreEqual(2, rr.ConstantValue); + Assert.AreEqual("TestEnum2", rr.ReferencedType.Name); + } + + [Test] + public void SizeOfStructIsNotAConstant() + { + string program = @" +struct MyStruct {} +class TestClass { + static void Main() { + int s = $sizeof(MyStruct)$; + } +}"; + var rr = Resolve(program); + Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32)); + Assert.IsFalse(rr.IsError); + Assert.IsNull(rr.ConstantValue); + Assert.AreEqual("MyStruct", rr.ReferencedType.Name); + } + + [Test] + public void SizeOfReferenceTypeIsAnError() { + string program = @" +class MyClass {} +class TestClass { + static void Main() { + int s = $sizeof(MyClass)$; + } +}"; + var rr = Resolve(program); + Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32)); + Assert.IsTrue(rr.IsError); + Assert.IsNull(rr.ConstantValue); + Assert.AreEqual("MyClass", rr.ReferencedType.Name); + } + } +} diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index a01aff64e4..8185e9258e 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -233,6 +233,7 @@ + diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs index d233d0dd48..2b19b4887e 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs @@ -358,5 +358,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase public const double Cd = 42; public const float Cf = 42; public const decimal Cm = 42; + public const string S = "hello, world"; + + public const int SOsb = sizeof(sbyte); + public const int SOb = sizeof(byte); + public const int SOs = sizeof(short); + public const int SOus = sizeof(ushort); + public const int SOi = sizeof(int); + public const int SOui = sizeof(uint); + public const int SOl = sizeof(long); + public const int SOul = sizeof(ulong); + public const int SOc = sizeof(char); + public const int SOf = sizeof(float); + public const int SOd = sizeof(double); + public const int SObl = sizeof(bool); + public const int SOe = sizeof(MyEnum); } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index e4fafe3ae0..daa441f3ed 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -1263,6 +1263,21 @@ namespace ICSharpCode.NRefactory.TypeSystem AssertConstantField(type, "Cd", 42); AssertConstantField(type, "Cf", 42); AssertConstantField(type, "Cm", 42); + AssertConstantField(type, "S", "hello, world"); + + AssertConstantField(type, "SOsb", sizeof(sbyte)); + AssertConstantField(type, "SOb", sizeof(byte)); + AssertConstantField(type, "SOs", sizeof(short)); + AssertConstantField(type, "SOus", sizeof(ushort)); + AssertConstantField(type, "SOi", sizeof(int)); + AssertConstantField(type, "SOui", sizeof(uint)); + AssertConstantField(type, "SOl", sizeof(long)); + AssertConstantField(type, "SOul", sizeof(ulong)); + AssertConstantField(type, "SOc", sizeof(char)); + AssertConstantField(type, "SOf", sizeof(float)); + AssertConstantField(type, "SOd", sizeof(double)); + AssertConstantField(type, "SObl", sizeof(bool)); + AssertConstantField(type, "SOe", sizeof(MyEnum)); } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 4d509330fe..e415dbff55 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -111,6 +111,7 @@ + diff --git a/ICSharpCode.NRefactory/Semantics/SizeOfResolveResult.cs b/ICSharpCode.NRefactory/Semantics/SizeOfResolveResult.cs new file mode 100644 index 0000000000..a4c949bdd6 --- /dev/null +++ b/ICSharpCode.NRefactory/Semantics/SizeOfResolveResult.cs @@ -0,0 +1,66 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the 'typeof'. + /// + public class SizeOfResolveResult : ResolveResult + { + readonly IType referencedType; + readonly int? constantValue; + + public SizeOfResolveResult(IType int32, IType referencedType, int? constantValue) + : base(int32) + { + if (referencedType == null) + throw new ArgumentNullException("referencedType"); + this.referencedType = referencedType; + this.constantValue = constantValue; + } + + /// + /// The type referenced by the 'sizeof'. + /// + public IType ReferencedType { + get { return referencedType; } + } + + public override bool IsCompileTimeConstant { + get { + return constantValue != null; + } + } + + public override object ConstantValue { + get { + return constantValue; + } + } + + public override bool IsError { + get { + return referencedType.IsReferenceType != false; + } + } + } +}