Browse Source

Merge remote-tracking branch 'upstream/master' into mansheng

newNRvisualizers
Mansheng Yang 14 years ago
parent
commit
a1cbcc20b9
  1. 2
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  2. 25
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  3. 73
      ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs
  4. 57
      ICSharpCode.NRefactory.CSharp/Resolver/DynamicMemberResolveResult.cs
  5. 29
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  6. 2
      ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
  7. 2
      ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
  8. 103
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs
  9. 15
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/MethodTests.cs
  10. 17
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs
  11. 2
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  12. 36
      ICSharpCode.NRefactory.Tests/TypeSystem/LazyLoadedCecilLoaderTests.cs
  13. 239
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  14. 6
      ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs
  15. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedEntity.cs
  16. 5
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

2
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -286,6 +286,8 @@ @@ -286,6 +286,8 @@
<Compile Include="Refactoring\Script.cs" />
<Compile Include="Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" />
<Compile Include="Resolver\DynamicInvocationResolveResult.cs" />
<Compile Include="Resolver\DynamicMemberResolveResult.cs" />
<Compile Include="Resolver\CSharpConversions.cs" />
<Compile Include="Resolver\CSharpAstResolver.cs" />
<Compile Include="Resolver\CSharpInvocationResolveResult.cs" />

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

@ -119,6 +119,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -119,6 +119,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
public CSharpResolver WithCheckForOverflow(bool checkForOverflow)
{
if (checkForOverflow == this.checkForOverflow)
return this;
return new CSharpResolver(compilation, conversions, context, checkForOverflow, isWithinLambdaExpression, currentTypeDefinitionCache, localVariableStack, objectInitializerStack);
}
@ -431,7 +433,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -431,7 +433,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// evaluate as (E)(~(U)x);
var U = compilation.FindType(expression.ConstantValue.GetType());
var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
return CheckErrorAndResolveCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
return CheckErrorAndResolveUncheckedCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
} else {
return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable);
}
@ -911,7 +913,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -911,7 +913,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
rhs = ResolveCast(elementType, rhs);
if (rhs.IsError)
return rhs;
return CheckErrorAndResolveCast(elementType, ResolveBinaryOperator(BinaryOperatorType.Subtract, lhs, rhs));
return CheckErrorAndResolveUncheckedCast(elementType, ResolveBinaryOperator(BinaryOperatorType.Subtract, lhs, rhs));
}
IType resultType = MakeNullable(elementType, isNullable);
return BinaryOperatorResolveResult(resultType, lhs, BinaryOperatorType.Subtract, rhs, isNullable);
@ -937,7 +939,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -937,7 +939,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
rhs = ResolveCast(elementType, rhs);
if (rhs.IsError)
return rhs;
return CheckErrorAndResolveCast(enumType, ResolveBinaryOperator(op, lhs, rhs));
return CheckErrorAndResolveUncheckedCast(enumType, ResolveBinaryOperator(op, lhs, rhs));
}
IType resultType = MakeNullable(enumType, isNullable);
return BinaryOperatorResolveResult(resultType, lhs, op, rhs, isNullable);
@ -1260,7 +1262,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1260,7 +1262,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (c == Conversion.IdentityConversion)
return rr;
else if (rr.IsCompileTimeConstant && c != Conversion.None)
else if (rr.IsCompileTimeConstant && c != Conversion.None && !c.IsUserDefined)
return ResolveCast(targetType, rr);
else
return new ConversionResolveResult(targetType, rr, c, checkForOverflow);
@ -1269,7 +1271,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1269,7 +1271,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ResolveResult ResolveCast(IType targetType, ResolveResult expression)
{
// C# 4.0 spec: §7.7.6 Cast expressions
if (expression.IsCompileTimeConstant) {
Conversion c = conversions.ExplicitConversion(expression, targetType);
if (expression.IsCompileTimeConstant && !c.IsUserDefined) {
TypeCode code = ReflectionHelper.GetTypeCode(targetType);
if (code >= TypeCode.Boolean && code <= TypeCode.Decimal && expression.ConstantValue != null) {
try {
@ -1293,7 +1296,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1293,7 +1296,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
}
Conversion c = conversions.ExplicitConversion(expression, targetType);
return new ConversionResolveResult(targetType, expression, c, checkForOverflow);
}
@ -1302,12 +1304,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1302,12 +1304,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Utils.CSharpPrimitiveCast.Cast(targetType, input, this.CheckForOverflow);
}
ResolveResult CheckErrorAndResolveCast(IType targetType, ResolveResult expression)
ResolveResult CheckErrorAndResolveUncheckedCast(IType targetType, ResolveResult expression)
{
if (expression.IsError)
return expression;
else
return ResolveCast(targetType, expression);
return WithCheckForOverflow(false).ResolveCast(targetType, expression);
}
#endregion
@ -1596,7 +1598,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1596,7 +1598,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
if (target.Type.Kind == TypeKind.Dynamic)
return new ResolveResult(SpecialType.Dynamic);
return new DynamicMemberResolveResult(target, identifier);
MemberLookup lookup = CreateMemberLookup(lookupMode);
ResolveResult result;
@ -1893,8 +1895,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1893,8 +1895,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
// C# 4.0 spec: §7.6.5
if (target.Type.Kind == TypeKind.Dynamic)
return new ResolveResult(SpecialType.Dynamic);
if (target.Type.Kind == TypeKind.Dynamic) {
return new DynamicInvocationResolveResult(target, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly());
}
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) {

73
ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs

@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents a single argument in a dynamic invocation.
/// </summary>
public class DynamicInvocationArgument {
/// <summary>
/// Parameter name, if the argument is named. Null otherwise.
/// </summary>
public readonly string Name;
/// <summary>
/// Value of the argument.
/// </summary>
public readonly ResolveResult Value;
public DynamicInvocationArgument(string name, ResolveResult value) {
Name = name;
Value = value;
}
}
/// <summary>
/// Represents the result of an invocation of a member of a dynamic object.
/// </summary>
public class DynamicInvocationResolveResult : ResolveResult
{
/// <summary>
/// Target of the invocation (a dynamic object).
/// </summary>
public readonly ResolveResult Target;
/// <summary>
/// Arguments for the call.
/// </summary>
public readonly IList<DynamicInvocationArgument> Arguments;
public DynamicInvocationResolveResult(ResolveResult target, IList<DynamicInvocationArgument> arguments) : base(SpecialType.Dynamic) {
this.Target = target;
this.Arguments = arguments ?? EmptyList<DynamicInvocationArgument>.Instance;
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "[Dynamic invocation ]");
}
}
}

57
ICSharpCode.NRefactory.CSharp/Resolver/DynamicMemberResolveResult.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents the result of an access to a member of a dynamic object.
/// </summary>
public class DynamicMemberResolveResult : ResolveResult
{
/// <summary>
/// Target of the member access (a dynamic object).
/// </summary>
public readonly ResolveResult Target;
/// <summary>
/// Name of the accessed member.
/// </summary>
public readonly string Member;
public DynamicMemberResolveResult(ResolveResult target, string member) : base(SpecialType.Dynamic) {
this.Target = target;
this.Member = member;
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "[Dynamic member '{0}']", Member);
}
public override IEnumerable<ResolveResult> GetChildResults() {
return new[] { Target };
}
}
}

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

@ -854,21 +854,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -854,21 +854,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
resolver.CurrentTypeResolveContext, propertyOrIndexerDeclaration.EntityType, name,
explicitInterfaceType, parameterTypeReferences: parameterTypeReferences);
}
// We need to use the property as current member so that indexer parameters can be resolved correctly.
resolver = resolver.WithCurrentMember(member);
var resolverWithPropertyAsMember = resolver;
for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) {
if (node.Role == PropertyDeclaration.GetterRole && member is IProperty) {
resolver = resolver.PushBlock();
resolver = resolver.WithCurrentMember(((IProperty)member).Getter);
Scan(node);
resolver = resolver.PopBlock();
}
else if (node.Role == PropertyDeclaration.SetterRole && member is IProperty) {
resolver = resolver.PushBlock();
resolver = resolverWithPropertyAsMember;
} else if (node.Role == PropertyDeclaration.SetterRole && member is IProperty) {
resolver = resolver.WithCurrentMember(((IProperty)member).Setter);
Scan(node);
resolver = resolver.PopBlock();
}
else {
resolver = resolverWithPropertyAsMember;
} else {
Scan(node);
}
}
@ -908,21 +907,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -908,21 +907,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
explicitInterfaceAstType.ToTypeReference());
}
}
resolver = resolver.WithCurrentMember(member);
var resolverWithEventAsMember = resolver;
for (AstNode node = eventDeclaration.FirstChild; node != null; node = node.NextSibling) {
if (node.Role == CustomEventDeclaration.AddAccessorRole && member is IEvent) {
resolver = resolver.PushBlock();
resolver = resolver.WithCurrentMember(((IEvent)member).AddAccessor);
Scan(node);
resolver = resolver.PopBlock();
}
else if (node.Role == CustomEventDeclaration.RemoveAccessorRole && member is IEvent) {
resolver = resolver.PushBlock();
resolver = resolverWithEventAsMember;
} else if (node.Role == CustomEventDeclaration.RemoveAccessorRole && member is IEvent) {
resolver = resolver.WithCurrentMember(((IEvent)member).RemoveAccessor);
Scan(node);
resolver = resolver.PopBlock();
}
else {
resolver = resolverWithEventAsMember;
} else {
Scan(node);
}
}

2
ICSharpCode.NRefactory.ConsistencyCheck/Program.cs

@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
solution.AllFiles.Count(),
solution.Projects.Count);
//using (new Timer("ID String test... ")) TypeSystemTests.IDStringConsistencyCheck(solution);
using (new Timer("ID String test... ")) TypeSystemTests.IDStringConsistencyCheck(solution);
using (new Timer("Resolve unresolved members... ")) TypeSystemTests.ResolvedUnresolvedMembers(solution);
//RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest);
RunTestOnAllFiles("Resolver test", ResolverTest.RunTest);

2
ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
if (CSharpAstResolver.IsUnresolvableNode(node))
throw new InvalidOperationException("Resolved unresolvable node");
if (!ParenthesizedExpression.ActsAsParenthesizedExpression(node))
if (!resolveResults.Add(result))
if (!resolveResults.Add(result) && result != ErrorResolveResult.UnknownError)
throw new InvalidOperationException("Duplicate resolve result");
if (result.IsError && !allowErrors) {

103
ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver {
[TestFixture]
public class DynamicTests : ResolverTestBase {
[Test]
public void AccessToDynamicMember() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
$obj.SomeProperty$ = 10;
}
}";
var rr = Resolve<DynamicMemberResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj");
Assert.That(rr.Member, Is.EqualTo("SomeProperty"));
}
[Test]
public void DynamicInvocation() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0;
string b = null;
$obj.SomeMethod(a, b)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod"));
Assert.That(rr.Arguments.Count, Is.EqualTo(2));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a");
Assert.That(rr.Arguments[1].Name, Is.Null);
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "b");
}
[Test]
public void DynamicInvocationWithNamedArguments() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0, x = 0;
string b = null;
$obj.SomeMethod(x, param1: a, param2: b)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)rr.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod"));
Assert.That(rr.Arguments.Count, Is.EqualTo(3));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "x");
Assert.That(rr.Arguments[1].Name, Is.EqualTo("param1"));
Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "a");
Assert.That(rr.Arguments[2].Name, Is.EqualTo("param2"));
Assert.That(rr.Arguments[2].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[2].Value).Variable.Name == "b");
}
[Test]
public void TwoDynamicInvocationsInARow() {
string program = @"using System;
class TestClass {
void F() {
dynamic obj = null;
int a = 0, b = 0;
$obj.SomeMethod(a)(b)$;
}
}";
var rr = Resolve<DynamicInvocationResolveResult>(program);
Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic));
Assert.That(rr.Target, Is.InstanceOf<DynamicInvocationResolveResult>());
var innerInvocation = (DynamicInvocationResolveResult)rr.Target;
Assert.That(innerInvocation.Target, Is.InstanceOf<DynamicMemberResolveResult>());
var dynamicMember = (DynamicMemberResolveResult)innerInvocation.Target;
Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj");
Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod"));
Assert.That(innerInvocation.Arguments.Count, Is.EqualTo(1));
Assert.That(innerInvocation.Arguments[0].Name, Is.Null);
Assert.That(innerInvocation.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)innerInvocation.Arguments[0].Value).Variable.Name == "a");
Assert.That(rr.Arguments.Count, Is.EqualTo(1));
Assert.That(rr.Arguments[0].Name, Is.Null);
Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "b");
}
}
}

15
ICSharpCode.NRefactory.Tests/CSharp/Resolver/MethodTests.cs

@ -126,6 +126,21 @@ class TestClass { @@ -126,6 +126,21 @@ class TestClass {
Assert.IsTrue(ReferenceEquals(value1, value2));
}
[Test]
public void ResolveParameterDeclarationInIndexer()
{
string code = @"using System;
class TestClass {
int[,] myField;
int this[$int i$, int j] {
get { return myField[i, j]; }
set { myField[i, j] = value; }
}
}";
var rr = Resolve<LocalResolveResult>(code);
Assert.IsTrue(rr.IsParameter);
}
[Test]
public void ParameterIdentityInEventAdder()
{

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

@ -257,5 +257,22 @@ class Test { @@ -257,5 +257,22 @@ class Test {
Assert.IsFalse(irr.IsError);
Assert.IsTrue(irr.IsLiftedOperator);
}
[Test]
public void UShortEnumNegation()
{
string program = @"
class Test {
enum UShortEnum : ushort { Three = 3 }
static void Inc() {
checked { // even in checked context, the implicit cast back to enum is unchecked
var a = $~UShortEnum.Three$;
}
}
}";
var rr = Resolve<ConstantResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(unchecked( (ushort)~3 ), rr.ConstantValue);
}
}
}

2
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -190,6 +190,7 @@ @@ -190,6 +190,7 @@
<Compile Include="CSharp\Resolver\CastTests.cs" />
<Compile Include="CSharp\Resolver\ComTests.cs" />
<Compile Include="CSharp\Resolver\ConditionalOperatorTests.cs" />
<Compile Include="CSharp\Resolver\DynamicTests.cs" />
<Compile Include="CSharp\Resolver\ExtensionMethodTests.cs" />
<Compile Include="CSharp\Resolver\FindReferencesTest.cs" />
<Compile Include="CSharp\Resolver\InvocationTests.cs" />
@ -221,6 +222,7 @@ @@ -221,6 +222,7 @@
<Compile Include="TypeSystem\CecilLoaderTests.cs" />
<Compile Include="TypeSystem\GetAllBaseTypesTest.cs" />
<Compile Include="TypeSystem\GetMembersTests.cs" />
<Compile Include="TypeSystem\LazyLoadedCecilLoaderTests.cs" />
<Compile Include="TypeSystem\ReflectionHelperTests.cs" />
<Compile Include="TypeSystem\SerializedCecilLoaderTests.cs" />
<Compile Include="TypeSystem\StructureTests.cs" />

36
ICSharpCode.NRefactory.Tests/TypeSystem/LazyLoadedCecilLoaderTests.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// 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.Implementation;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.TypeSystem
{
[TestFixture]
public class LazyLoadedCecilLoaderTests : TypeSystemTests
{
[TestFixtureSetUp]
public void FixtureSetUp()
{
CecilLoader loader = new CecilLoader() { IncludeInternalMembers = true, LazyLoad = true };
IUnresolvedAssembly pc = loader.LoadAssemblyFile(typeof(TestCase.SimplePublicClass).Assembly.Location);
base.compilation = new SimpleCompilation(pc, CecilLoaderTests.Mscorlib);
}
}
}

239
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -47,6 +47,16 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -47,6 +47,16 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary>
public bool IncludeInternalMembers { get; set; }
/// <summary>
/// Specifies whether to use lazy loading. The default is false.
/// If this property is set to true, the CecilLoader will not copy all the relevant information
/// out of the Cecil object model, but will maintain references to the Cecil objects.
/// This speeds up the loading process and avoids loading unnecessary information, but it causes
/// the Cecil objects to stay in memory (which can significantly increase memory usage).
/// It also prevents serialization of the Cecil-loaded type system.
/// </summary>
public bool LazyLoad { get; set; }
/// <summary>
/// Gets/Sets the documentation provider that is used to retrieve the XML documentation for all members.
/// </summary>
@ -137,7 +147,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -137,7 +147,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
this.CancellationToken.ThrowIfCancellationRequested();
if (this.IncludeInternalMembers || (td.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public) {
string name = td.Name;
if (name.Length == 0 || name[0] == '<')
if (name.Length == 0)
continue;
var t = CreateTopLevelTypeDefinition(td);
@ -166,6 +176,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -166,6 +176,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// This causes ReadTypeReference() to use <see cref="DefaultAssemblyReference.CurrentAssembly"/> for references
/// in that module.
/// </summary>
[CLSCompliant(false)]
public void SetCurrentModule(ModuleDefinition module)
{
this.currentModule = module;
@ -1449,65 +1460,76 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1449,65 +1460,76 @@ namespace ICSharpCode.NRefactory.TypeSystem
{
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(typeDefinition.Name);
var td = new DefaultUnresolvedTypeDefinition(typeDefinition.Namespace, name);
InitTypeParameters(typeDefinition, td);
if (typeDefinition.HasGenericParameters)
InitTypeParameters(typeDefinition, td.TypeParameters);
return td;
}
static void InitTypeParameters(TypeDefinition typeDefinition, DefaultUnresolvedTypeDefinition td)
static void InitTypeParameters(TypeDefinition typeDefinition, IList<IUnresolvedTypeParameter> typeParameters)
{
// Type parameters are initialized within the constructor so that the class can be put into the type storage
// before the rest of the initialization runs - this allows it to be available for early binding as soon as possible.
for (int i = 0; i < typeDefinition.GenericParameters.Count; i++) {
if (typeDefinition.GenericParameters[i].Position != i)
throw new InvalidOperationException("g.Position != i");
td.TypeParameters.Add(new DefaultUnresolvedTypeParameter(
typeParameters.Add(new DefaultUnresolvedTypeParameter(
EntityType.TypeDefinition, i, typeDefinition.GenericParameters[i].Name));
}
}
void InitTypeDefinition(TypeDefinition typeDefinition, DefaultUnresolvedTypeDefinition td)
void InitTypeParameterConstraints(TypeDefinition typeDefinition, IList<IUnresolvedTypeParameter> typeParameters)
{
InitTypeModifiers(typeDefinition, td);
if (typeDefinition.HasGenericParameters) {
for (int i = 0; i < typeDefinition.GenericParameters.Count; i++) {
AddConstraints((DefaultUnresolvedTypeParameter)td.TypeParameters[i], typeDefinition.GenericParameters[i]);
for (int i = 0; i < typeParameters.Count; i++) {
AddConstraints((DefaultUnresolvedTypeParameter)typeParameters[i], typeDefinition.GenericParameters[i]);
}
}
InitNestedTypes(typeDefinition, td); // nested types can be initialized only after generic parameters were created
void InitTypeDefinition(TypeDefinition typeDefinition, DefaultUnresolvedTypeDefinition td)
{
td.Kind = GetTypeKind(typeDefinition);
InitTypeModifiers(typeDefinition, td);
InitTypeParameterConstraints(typeDefinition, td.TypeParameters);
// nested types can be initialized only after generic parameters were created
InitNestedTypes(typeDefinition, td, td.NestedTypes);
AddAttributes(typeDefinition, td);
td.HasExtensionMethods = HasExtensionAttribute(typeDefinition);
InitBaseTypes(typeDefinition, td.BaseTypes);
td.AddDefaultConstructorIfRequired = (td.Kind == TypeKind.Struct || td.Kind == TypeKind.Enum);
InitMembers(typeDefinition, td, td.Members);
if (HasCecilReferences)
typeSystemTranslationTable[td] = typeDefinition;
if (this.InterningProvider != null) {
td.ApplyInterningProvider(this.InterningProvider);
}
td.Freeze();
}
void InitBaseTypes(TypeDefinition typeDefinition, IList<ITypeReference> baseTypes)
{
// set base classes
if (typeDefinition.IsEnum) {
foreach (FieldDefinition enumField in typeDefinition.Fields) {
if (!enumField.IsStatic) {
td.BaseTypes.Add(ReadTypeReference(enumField.FieldType));
baseTypes.Add(ReadTypeReference(enumField.FieldType));
break;
}
}
} else {
if (typeDefinition.BaseType != null) {
td.BaseTypes.Add(ReadTypeReference(typeDefinition.BaseType));
baseTypes.Add(ReadTypeReference(typeDefinition.BaseType));
}
if (typeDefinition.HasInterfaces) {
foreach (TypeReference iface in typeDefinition.Interfaces) {
td.BaseTypes.Add(ReadTypeReference(iface));
}
baseTypes.Add(ReadTypeReference(iface));
}
}
InitMembers(typeDefinition, td);
if (HasCecilReferences)
typeSystemTranslationTable[td] = typeDefinition;
if (this.InterningProvider != null) {
td.ApplyInterningProvider(this.InterningProvider);
}
td.Freeze();
}
void InitNestedTypes(TypeDefinition typeDefinition, DefaultUnresolvedTypeDefinition td)
void InitNestedTypes(TypeDefinition typeDefinition, IUnresolvedTypeDefinition declaringTypeDefinition, IList<IUnresolvedTypeDefinition> nestedTypes)
{
if (!typeDefinition.HasNestedTypes)
return;
@ -1522,33 +1544,35 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1522,33 +1544,35 @@ namespace ICSharpCode.NRefactory.TypeSystem
int pos = name.LastIndexOf('/');
if (pos > 0)
name = name.Substring(pos + 1);
if (name.Length == 0 || name[0] == '<')
continue;
name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name);
var nestedType = new DefaultUnresolvedTypeDefinition(td, name);
InitTypeParameters(nestedTypeDef, nestedType);
td.NestedTypes.Add(nestedType);
var nestedType = new DefaultUnresolvedTypeDefinition(declaringTypeDefinition, name);
InitTypeParameters(nestedTypeDef, nestedType.TypeParameters);
nestedTypes.Add(nestedType);
InitTypeDefinition(nestedTypeDef, nestedType);
}
}
}
static void InitTypeModifiers(TypeDefinition typeDefinition, DefaultUnresolvedTypeDefinition td)
static TypeKind GetTypeKind(TypeDefinition typeDefinition)
{
// set classtype
if (typeDefinition.IsInterface) {
td.Kind = TypeKind.Interface;
return TypeKind.Interface;
} else if (typeDefinition.IsEnum) {
td.Kind = TypeKind.Enum;
return TypeKind.Enum;
} else if (typeDefinition.IsValueType) {
td.Kind = TypeKind.Struct;
return TypeKind.Struct;
} else if (IsDelegate(typeDefinition)) {
td.Kind = TypeKind.Delegate;
return TypeKind.Delegate;
} else if (IsModule(typeDefinition)) {
td.Kind = TypeKind.Module;
return TypeKind.Module;
} else {
td.Kind = TypeKind.Class;
return TypeKind.Class;
}
}
static void InitTypeModifiers(TypeDefinition typeDefinition, AbstractUnresolvedEntity td)
{
td.IsSealed = typeDefinition.IsSealed;
td.IsAbstract = typeDefinition.IsAbstract;
switch (typeDefinition.Attributes & TypeAttributes.VisibilityMask) {
@ -1598,9 +1622,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1598,9 +1622,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
return false;
}
void InitMembers(TypeDefinition typeDefinition, DefaultUnresolvedTypeDefinition td)
void InitMembers(TypeDefinition typeDefinition, IUnresolvedTypeDefinition td, IList<IUnresolvedMember> members)
{
td.AddDefaultConstructorIfRequired = (td.Kind == TypeKind.Struct || td.Kind == TypeKind.Enum);
if (typeDefinition.HasMethods) {
foreach (MethodDefinition method in typeDefinition.Methods) {
if (IsVisible(method.Attributes) && !IsAccessor(method.SemanticsAttributes)) {
@ -1611,14 +1634,14 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1611,14 +1634,14 @@ namespace ICSharpCode.NRefactory.TypeSystem
else if (method.Name.StartsWith("op_", StringComparison.Ordinal))
type = EntityType.Operator;
}
td.Members.Add(ReadMethod(method, td, type));
members.Add(ReadMethod(method, td, type));
}
}
}
if (typeDefinition.HasFields) {
foreach (FieldDefinition field in typeDefinition.Fields) {
if (IsVisible(field.Attributes) && !field.IsSpecialName) {
td.Members.Add(ReadField(field, td));
members.Add(ReadField(field, td));
}
}
}
@ -1634,14 +1657,14 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1634,14 +1657,14 @@ namespace ICSharpCode.NRefactory.TypeSystem
bool setterVisible = property.SetMethod != null && IsVisible(property.SetMethod.Attributes);
if (getterVisible || setterVisible) {
EntityType type = property.Name == defaultMemberName ? EntityType.Indexer : EntityType.Property;
td.Members.Add(ReadProperty(property, td, type));
members.Add(ReadProperty(property, td, type));
}
}
}
if (typeDefinition.HasEvents) {
foreach (EventDefinition ev in typeDefinition.Events) {
if (ev.AddMethod != null && IsVisible(ev.AddMethod.Attributes)) {
td.Members.Add(ReadEvent(ev, td));
members.Add(ReadEvent(ev, td));
}
}
}
@ -1653,6 +1676,140 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1653,6 +1676,140 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
#endregion
#region Lazy-Loaded Type Definition
sealed class LazyCecilTypeDefinition : AbstractUnresolvedEntity, IUnresolvedTypeDefinition
{
readonly CecilLoader loader;
readonly string namespaceName;
readonly TypeDefinition cecilTypeDef;
readonly TypeKind kind;
readonly IList<IUnresolvedTypeParameter> typeParameters;
IList<ITypeReference> baseTypes;
IList<IUnresolvedTypeDefinition> nestedTypes;
IList<IUnresolvedMember> members;
public LazyCecilTypeDefinition(CecilLoader loader, TypeDefinition typeDefinition)
{
this.loader = loader;
this.cecilTypeDef = typeDefinition;
this.EntityType = EntityType.TypeDefinition;
this.namespaceName = cecilTypeDef.Namespace;
this.Name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(cecilTypeDef.Name);
var tps = new List<IUnresolvedTypeParameter>();
InitTypeParameters(cecilTypeDef, tps);
this.typeParameters = FreezableHelper.FreezeList(tps);
this.kind = GetTypeKind(typeDefinition);
InitTypeModifiers(typeDefinition, this);
loader.InitTypeParameterConstraints(typeDefinition, typeParameters);
loader.AddAttributes(typeDefinition, this);
flags[FlagHasExtensionMethods] = HasExtensionAttribute(typeDefinition);
if (loader.HasCecilReferences)
loader.typeSystemTranslationTable[this] = typeDefinition;
if (loader.InterningProvider != null) {
this.ApplyInterningProvider(loader.InterningProvider);
}
this.Freeze();
}
public override string Namespace {
get { return namespaceName; }
set { throw new NotSupportedException(); }
}
public TypeKind Kind {
get { return kind; }
}
public IList<IUnresolvedTypeParameter> TypeParameters {
get { return typeParameters; }
}
public IList<ITypeReference> BaseTypes {
get {
var result = LazyInit.VolatileRead(ref this.baseTypes);
if (result != null) {
return result;
} else {
result = new List<ITypeReference>();
loader.InitBaseTypes(cecilTypeDef, result);
return LazyInit.GetOrSet(ref this.baseTypes, FreezableHelper.FreezeList(result));
}
}
}
public IList<IUnresolvedTypeDefinition> NestedTypes {
get {
var result = LazyInit.VolatileRead(ref this.nestedTypes);
if (result != null) {
return result;
} else {
result = new List<IUnresolvedTypeDefinition>();
loader.InitNestedTypes(cecilTypeDef, this, result);
return LazyInit.GetOrSet(ref this.nestedTypes, FreezableHelper.FreezeList(result));
}
}
}
public IList<IUnresolvedMember> Members {
get {
var result = LazyInit.VolatileRead(ref this.members);
if (result != null) {
return result;
} else {
result = new List<IUnresolvedMember>();
loader.InitMembers(cecilTypeDef, this, result);
return LazyInit.GetOrSet(ref this.members, FreezableHelper.FreezeList(result));
}
}
}
public IEnumerable<IUnresolvedMethod> Methods {
get { return Members.OfType<IUnresolvedMethod>(); }
}
public IEnumerable<IUnresolvedProperty> Properties {
get { return Members.OfType<IUnresolvedProperty>(); }
}
public IEnumerable<IUnresolvedField> Fields {
get { return Members.OfType<IUnresolvedField>(); }
}
public IEnumerable<IUnresolvedEvent> Events {
get { return Members.OfType<IUnresolvedEvent>(); }
}
public bool AddDefaultConstructorIfRequired {
get { return kind == TypeKind.Struct || kind == TypeKind.Enum; }
}
public bool? HasExtensionMethods {
get { return flags[FlagHasExtensionMethods]; }
// we always return true or false, never null.
// FlagHasNoExtensionMethods is unused in LazyCecilTypeDefinition
}
public IType Resolve(ITypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException("context");
if (context.CurrentAssembly == null)
throw new ArgumentException("An ITypeDefinition cannot be resolved in a context without a current assembly.");
return context.CurrentAssembly.GetTypeDefinition(this)
?? (IType)new UnknownType(this.Namespace, this.Name, this.TypeParameters.Count);
}
public ITypeResolveContext CreateResolveContext(ITypeResolveContext parentContext)
{
return parentContext;
}
}
#endregion
#region Read Method
[CLSCompliant(false)]
public IUnresolvedMethod ReadMethod(MethodDefinition method, IUnresolvedTypeDefinition parentType, EntityType methodType = EntityType.Method)

6
ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs

@ -48,6 +48,12 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -48,6 +48,12 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// </summary>
bool? HasExtensionMethods { get; }
/// <summary>
/// Gets whether this unresolved type definition causes the addition of a default constructor
/// if no other constructor is present.
/// </summary>
bool AddDefaultConstructorIfRequired { get; }
/// <summary>
/// Looks up the resolved type definition from the <paramref name="context"/> corresponding to this unresolved
/// type definition.

2
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedEntity.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
internal const ushort FlagShadowing = 0x0008;
internal const ushort FlagSynthetic = 0x0010;
internal const ushort FlagStatic = 0x0020;
// flags for DefaultUnresolvedTypeDefinition
// flags for DefaultUnresolvedTypeDefinition/LazyCecilTypeDefinition
internal const ushort FlagAddDefaultConstructorIfRequired = 0x0040;
internal const ushort FlagHasExtensionMethods = 0x0080;
internal const ushort FlagHasNoExtensionMethods = 0x0100;

5
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -322,10 +322,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -322,10 +322,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
DefaultUnresolvedTypeDefinition dutd = part as DefaultUnresolvedTypeDefinition;
if (dutd != null) {
addDefaultConstructorIfRequired |= dutd.AddDefaultConstructorIfRequired;
}
addDefaultConstructorIfRequired |= part.AddDefaultConstructorIfRequired;
}
if (addDefaultConstructorIfRequired) {
TypeKind kind = this.Kind;

Loading…
Cancel
Save