From 7a2c59ae4a1bdfdffa93b8e6d0672808a561cba7 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 11 Aug 2011 16:57:32 +0200 Subject: [PATCH] Add GetMemberOptions. --- .../Expression/ArrayCreateExpressionTests.cs | 60 +++- .../CSharp/Resolver/LambdaTests.cs | 64 ++-- .../CSharp/Resolver/NameLookupTests.cs | 2 +- .../CSharp/Resolver/ResolverTestBase.cs | 6 +- .../Visitors/CSharpToVBConverterVisitor.cs | 3 +- .../CSharp/Analysis/ControlFlow.cs | 2 +- .../CSharp/Resolver/CSharpResolver.cs | 9 +- .../CSharp/Resolver/Conversions.cs | 17 +- .../Resolver/InvocationResolveResult.cs | 10 +- .../CSharp/Resolver/OperatorResolveResult.cs | 2 +- .../CSharp/Resolver/OverloadResolution.cs | 2 +- .../CSharp/Resolver/ResolveVisitor.cs | 104 ++++--- .../CSharp/Resolver/TypeInference.cs | 16 +- .../ICSharpCode.NRefactory.csproj | 1 + .../TypeSystem/ArrayType.cs | 14 +- .../TypeSystem/ByReferenceType.cs | 2 +- ICSharpCode.NRefactory/TypeSystem/IType.cs | 50 +++- .../Implementation/AbstractFreezable.cs | 6 +- .../TypeSystem/Implementation/AbstractType.cs | 26 +- .../Implementation/DefaultTypeDefinition.cs | 124 ++++++-- .../Implementation/DefaultTypeParameter.cs | 62 ++-- .../Implementation/GetMembersHelper.cs | 281 ++++++++++++++++++ .../TypeParameterSubstitution.cs | 10 +- .../Implementation/VoidTypeDefinition.cs | 14 +- .../TypeSystem/IntersectionType.cs | 25 +- .../TypeSystem/NullableType.cs | 6 +- .../TypeSystem/ParameterizedType.cs | 281 ++++-------------- .../TypeSystem/PointerType.cs | 2 +- ICSharpCode.NRefactory/Utils/EmptyList.cs | 90 +++++- .../Utils/ExtensionMethods.cs | 9 + 30 files changed, 861 insertions(+), 439 deletions(-) create mode 100644 ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs index 0f621f48ce..b12feae796 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs @@ -50,6 +50,37 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression }); } + [Test] + public void ArrayWithImplicitSize() + { + ParseUtilCSharp.AssertExpression( + "new int[] { 1 }", + new ArrayCreateExpression { + Type = new PrimitiveType("int"), + Initializer = new ArrayInitializerExpression { + Elements = { new PrimitiveExpression(1) } + } + }); + } + + [Test] + public void ArrayWithImplicitSize2D() + { + ParseUtilCSharp.AssertExpression( + "new int[,] { { 1 } }", + new ArrayCreateExpression { + Type = new PrimitiveType("int"), + Arguments = { new EmptyExpression(), new EmptyExpression() }, // TODO: can we improve the AST for this? + Initializer = new ArrayInitializerExpression { + Elements = { + new ArrayInitializerExpression { + Elements = { new PrimitiveExpression(1) } + } + } + } + }); + } + [Test] public void ImplicitlyTypedArrayCreateExpression() { @@ -63,9 +94,32 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression new PrimitiveExpression(100), new PrimitiveExpression(1000) } - } - }); - + }}); + } + + [Test] + public void ImplicitlyTypedArrayCreateExpression2D() + { + ParseUtilCSharp.AssertExpression( + "new [,] { { 1, 10 }, { 100, 1000 } }", + new ArrayCreateExpression { + Arguments = { new EmptyExpression(), new EmptyExpression() }, // TODO: can we improve the AST for this? + Initializer = new ArrayInitializerExpression { + Elements = { + new ArrayInitializerExpression { + Elements = { + new PrimitiveExpression(1), + new PrimitiveExpression(10) + } + }, + new ArrayInitializerExpression { + Elements = { + new PrimitiveExpression(100), + new PrimitiveExpression(1000) + } + } + } + }}); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs index 4698fe27b1..08d844b653 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs @@ -72,7 +72,7 @@ class SomeClass { Assert.AreEqual("System.String", lrr.Type.ReflectionName); } - #region Lambda In Initializer + #region Lambda In Array Initializer [Test] public void LambdaInArrayInitializer1() { @@ -83,8 +83,7 @@ class TestClass { i => $i$.ToString() }; } -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } @@ -99,8 +98,7 @@ class TestClass { i => $i$.ToString() }; } -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } @@ -113,8 +111,7 @@ class TestClass { Converter[] field = new Converter[] { i => $i$.ToString() }; -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } @@ -127,13 +124,42 @@ class TestClass { Converter[] field = { i => $i$.ToString() }; -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } [Test] + public void LambdaIn2DArrayInitializer() + { + string program = @"using System; +class TestClass { + static void Main() { + Converter[,] arr = { + { i => $i$.ToString() } + }; + } +}"; + var lrr = Resolve(program); + Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); + } + + [Test, Ignore("Fails due to parser problem")] + public void LambdaInInferred2DArrayInitializer() + { + string program = @"using System; +class TestClass { + static void Main() { + var c = new [,] { { null, (Converter)null }, { a => $a$.ToString(), b => b.ToString() }}; + } +}"; + var lrr = Resolve(program); + Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); + } + #endregion + + #region Lambda In Collection Initializer + [Test, Ignore("Parser doesn't support collection initializers yet")] public void LambdaInCollectionInitializer1() { string program = @"using System; using System.Collections.Generic; @@ -143,13 +169,12 @@ class TestClass { i => $i$.ToString() }; } -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } - [Test] + [Test, Ignore("Parser doesn't support collection initializers yet")] public void LambdaInCollectionInitializer2() { string program = @"using System; using System.Collections.Generic; @@ -159,14 +184,13 @@ class TestClass { { i => $i$.ToString(), i => i.ToString() } }; } -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Char", lrr.Type.ReflectionName); } - [Test] + [Test, Ignore("Parser doesn't support collection initializers yet")] public void LambdaInCollectionInitializer3() { string program = @"using System; using System.Collections.Generic; @@ -176,13 +200,13 @@ class TestClass { { i => i.ToString(), $i$ => i.ToString() } }; } -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } + #endregion - [Test] + [Test, Ignore("Parser doesn't support object initializers yet")] public void LambdaInObjectInitializerTest() { string program = @"using System; @@ -195,12 +219,10 @@ class X { } class Helper { public Converter F; -} -"; +}"; var lrr = Resolve(program); Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); } - #endregion [Test] public void LambdaExpressionInCastExpression() diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs index f80adf59af..9a30bf5ab4 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs @@ -843,7 +843,7 @@ class B Assert.AreEqual("B.x", mrr.Member.FullName); } - [Test] + [Test, Ignore("Parser produces incorrect positions")] public void SubstituteClassAndMethodTypeParametersAtOnce() { string program = @"class C { static void M(X a, T b) { $C.M$(b, a); } }"; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs index ce4e804ac5..332f59902b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs @@ -192,11 +192,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver AstLocation[] dollars = FindDollarSigns(code).ToArray(); Assert.AreEqual(2, dollars.Length, "Expected 2 dollar signs marking start+end of desired node"); - UsingScope rootUsingScope = resolver.UsingScope; - while (rootUsingScope.Parent != null) - rootUsingScope = rootUsingScope.Parent; + SetUp(); - ParsedFile parsedFile = new ParsedFile("test.cs", rootUsingScope); + ParsedFile parsedFile = new ParsedFile("test.cs", resolver.UsingScope); TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(parsedFile, resolver.UsingScope, null); cu.AcceptVisitor(convertVisitor, null); project.UpdateProjectContent(null, convertVisitor.ParsedFile); diff --git a/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs b/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs index 966e86f9e1..eee8d06377 100644 --- a/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs +++ b/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs @@ -2061,7 +2061,8 @@ namespace ICSharpCode.NRefactory.VB.Visitors .GetChildrenByRole(CSharp.AstNode.Roles.Constraint) .SingleOrDefault(c => c.TypeParameter == typeParameterDeclaration.Name); - ConvertNodes(constraint == null ? Enumerable.Empty() : constraint.BaseTypes, param.Constraints); + if (constraint != null) + ConvertNodes(constraint.BaseTypes, param.Constraints); // TODO : typeParameterDeclaration.Attributes get lost? //ConvertNodes(typeParameterDeclaration.Attributes diff --git a/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs b/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs index 5b371af588..a8f8edc147 100644 --- a/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs +++ b/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs @@ -111,7 +111,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis /// Gets the try-finally statements that this control flow edge is leaving. /// public IEnumerable TryFinallyStatements { - get { return jumpOutOfTryFinally ?? Enumerable.Empty(); } + get { return jumpOutOfTryFinally ?? EmptyList.Instance; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index 9b6e3b553d..545d2d77db 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -2203,7 +2203,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } IMethod invokeMethod = target.Type.GetDelegateInvokeMethod(); if (invokeMethod != null) { - return new ResolveResult(invokeMethod.ReturnType.Resolve(context)); + OverloadResolution or = new OverloadResolution(context, arguments, argumentNames); + or.AddCandidate(invokeMethod); + return new InvocationResolveResult( + target, invokeMethod, invokeMethod.ReturnType.Resolve(context), + or.GetArgumentsWithConversions(), or.BestCandidateErrors, + isExpandedForm: or.BestCandidateIsExpandedForm, + isDelegateInvocation: true, + argumentToParameterMap: or.GetArgumentToParameterMap()); } return ErrorResult; } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs b/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs index daefe18edb..b74c1a4114 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs @@ -549,13 +549,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // conversion from single-dimensional array S[] to IList: ParameterizedType toPT = toType as ParameterizedType; - if (fromArray.Dimensions == 1 && toPT != null && toPT.TypeArguments.Count == 1 + if (fromArray.Dimensions == 1 && toPT != null && toPT.TypeParameterCount == 1 && toPT.Namespace == "System.Collections.Generic" && (toPT.Name == "IList" || toPT.Name == "ICollection" || toPT.Name == "IEnumerable")) { // array covariance plays a part here as well (string[] is IList) - return IdentityConversion(fromArray.ElementType, toPT.TypeArguments[0]) - || ImplicitReferenceConversion(fromArray.ElementType, toPT.TypeArguments[0]); + return IdentityConversion(fromArray.ElementType, toPT.GetTypeArgument(0)) + || ImplicitReferenceConversion(fromArray.ElementType, toPT.GetTypeArgument(0)); } // conversion from any array to System.Array and the interfaces it implements: ITypeDefinition systemArray = context.GetTypeDefinition("System", "Array", 0, StringComparer.Ordinal); @@ -588,14 +588,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (def != null && def.Equals(t.GetDefinition())) { ParameterizedType ps = s as ParameterizedType; ParameterizedType pt = t as ParameterizedType; - if (ps != null && pt != null - && ps.TypeArguments.Count == pt.TypeArguments.Count - && ps.TypeArguments.Count == def.TypeParameters.Count) - { + if (ps != null && pt != null) { // C# 4.0 spec: §13.1.3.2 Variance Conversion for (int i = 0; i < def.TypeParameters.Count; i++) { - IType si = ps.TypeArguments[i]; - IType ti = pt.TypeArguments[i]; + IType si = ps.GetTypeArgument(i); + IType ti = pt.GetTypeArgument(i); if (IdentityConversion(si, ti)) continue; ITypeParameter xi = def.TypeParameters[i]; @@ -902,7 +899,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { ParameterizedType pt = type as ParameterizedType; if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Expression" && pt.Namespace == "System.Linq.Expressions") { - return pt.TypeArguments[0]; + return pt.GetTypeArgument(0); } else { return type; } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/InvocationResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/InvocationResolveResult.cs index e0f5ea7aa6..b504ec6d81 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/InvocationResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/InvocationResolveResult.cs @@ -39,6 +39,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// public readonly bool IsExtensionMethodInvocation; + /// + /// Gets whether this invocation is calling a delegate (without explicitly calling ".Invoke()"). + /// + public readonly bool IsDelegateInvocation; + /// /// Gets whether a params-Array is being used in its expanded form. /// @@ -70,8 +75,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver ResolveResult targetResult, IParameterizedMember member, IType returnType, IList arguments, OverloadResolutionErrors overloadResolutionErrors = OverloadResolutionErrors.None, - bool isExtensionMethodInvocation = false, bool isExpandedForm = false, + bool isExtensionMethodInvocation = false, + bool isExpandedForm = false, bool isLiftedOperatorInvocation = false, + bool isDelegateInvocation = false, IList argumentToParameterMap = null) : base(targetResult, member, returnType) { @@ -80,6 +87,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver this.IsExtensionMethodInvocation = isExtensionMethodInvocation; this.IsExpandedForm = isExpandedForm; this.IsLiftedOperatorInvocation = isLiftedOperatorInvocation; + this.IsDelegateInvocation = isDelegateInvocation; this.argumentToParameterMap = argumentToParameterMap; } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs index cb443ec499..5643680814 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs @@ -208,7 +208,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (SizeArguments != null && InitializerElements != null) return SizeArguments.Concat(InitializerElements); else - return SizeArguments ?? InitializerElements ?? Enumerable.Empty(); + return SizeArguments ?? InitializerElements ?? EmptyList.Instance; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs index 5101916095..0441b3475d 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs @@ -323,7 +323,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var typeParameters = newParameterizedType.GetDefinition().TypeParameters; for (int i = 0; i < typeParameters.Count; i++) { ITypeParameter tp = typeParameters[i]; - IType typeArg = newParameterizedType.TypeArguments[i]; + IType typeArg = newParameterizedType.GetTypeArgument(i); switch (typeArg.Kind) { // void, null, and pointers cannot be used as type arguments case TypeKind.Void: case TypeKind.Null: diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 9e905b9d61..76fafc807c 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -203,15 +203,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return result; } - ResolveResult[] Resolve(AstNodeCollection expressions) - { - ResolveResult[] results = new ResolveResult[expressions.Count]; - int pos = 0; - foreach (var node in expressions) - results[pos++] = Resolve(node); - return results; - } - void StoreState(AstNode node, CSharpResolver resolverState) { Debug.Assert(resolverState != null); @@ -489,7 +480,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } } - ResolveAndProcessConversion(variableInitializer.Initializer, result.Type); + ArrayInitializerExpression aie = variableInitializer.Initializer as ArrayInitializerExpression; + ArrayType arrayType = result.Type as ArrayType; + if (aie != null && arrayType != null) { + StoreState(aie, resolver.Clone()); + List list = new List(); + UnpackArrayInitializer(list, aie, arrayType.Dimensions); + ResolveResult[] initializerElements = list.ToArray(); + ResolveResult arrayCreation = resolver.ResolveArrayCreation(arrayType.ElementType, arrayType.Dimensions, null, initializerElements); + StoreResult(aie, arrayCreation); + ProcessConversionsInResult(arrayCreation); + } else { + ResolveAndProcessConversion(variableInitializer.Initializer, result.Type); + } return result; } else { ScanChildren(variableInitializer); @@ -800,17 +803,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver dimensions = 1; sizeArguments = null; } else { - if (arrayCreateExpression.Arguments.All(e => e is EmptyExpression)) + if (arrayCreateExpression.Arguments.All(e => e is EmptyExpression)) { sizeArguments = null; - else - sizeArguments = Resolve(arrayCreateExpression.Arguments); + } else { + sizeArguments = new ResolveResult[dimensions]; + int pos = 0; + foreach (var node in arrayCreateExpression.Arguments) + sizeArguments[pos++] = Resolve(node); + } } ResolveResult[] initializerElements; - if (arrayCreateExpression.Initializer.IsNull) + if (arrayCreateExpression.Initializer.IsNull) { initializerElements = null; - else - initializerElements = Resolve(arrayCreateExpression.Initializer.Elements); + } else { + List list = new List(); + UnpackArrayInitializer(list, arrayCreateExpression.Initializer, dimensions); + initializerElements = list.ToArray(); + } if (arrayCreateExpression.Type.IsNull) { return resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElements); @@ -823,6 +833,30 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } + void UnpackArrayInitializer(List list, ArrayInitializerExpression initializer, int dimensions) + { + Debug.Assert(dimensions >= 1); + if (dimensions > 1) { + foreach (var node in initializer.Elements) { + ArrayInitializerExpression aie = node as ArrayInitializerExpression; + if (aie != null) + UnpackArrayInitializer(list, aie, dimensions - 1); + else + list.Add(Resolve(node)); + } + } else { + foreach (var expr in initializer.Elements) + list.Add(Resolve(expr)); + } + } + + public override ResolveResult VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, object data) + { + // Array initializers are handled by their parent expression. + ScanChildren(arrayInitializerExpression); + return errorResult; + } + public override ResolveResult VisitAsExpression(AsExpression asExpression, object data) { if (resolverEnabled) { @@ -1754,8 +1788,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver while (undecidedLambdas.Count > 0) { LambdaBase lambda = undecidedLambdas[0]; AstNode parent = lambda.LambdaExpression.Parent; - while (ActsAsParenthesizedExpression(parent)) + // Continue going upwards until we find a node that can be resolved and provides + // an expected type. + while (parent is ParenthesizedExpression + || parent is CheckedExpression || parent is UncheckedExpression + || parent is NamedArgumentExpression || parent is ArrayInitializerExpression) + { parent = parent.Parent; + } CSharpResolver storedResolver; if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) { Log.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda..."); @@ -1774,16 +1814,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Log.Unindent(); Log.WriteLine("MergeUndecidedLambdas() finished."); } - - /// - /// Gets whether the node acts as a parenthesized expression, - /// that is, it directly returns - /// - static bool ActsAsParenthesizedExpression(AstNode node) - { - return node is ParenthesizedExpression || node is CheckedExpression || node is UncheckedExpression - || node is NamedArgumentExpression; - } #endregion #region AnalyzeLambda @@ -2073,16 +2103,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach) { - bool needsResolving; + bool typeNeedsResolving; if (mode == ResolveVisitorNavigationMode.ResolveAll) { - needsResolving = true; + typeNeedsResolving = true; } else { var modeForType = navigator.Scan(type); - needsResolving = (modeForType == ResolveVisitorNavigationMode.Resolve || modeForType == ResolveVisitorNavigationMode.ResolveAll); + typeNeedsResolving = (modeForType == ResolveVisitorNavigationMode.Resolve || modeForType == ResolveVisitorNavigationMode.ResolveAll); } if (initializerExpression != null && IsVar(type)) { var typeRef = new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); - if (needsResolving) { + if (typeNeedsResolving) { // Hack: I don't see a clean way to make the 'var' SimpleType resolve to the inferred type, // so we just do it here and store the result in the resolver cache. IType actualType = typeRef.Resolve(resolver.Context); @@ -2099,7 +2129,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // Perf: avoid duplicate resolving of the type (once as ITypeReference, once directly in ResolveVisitor) // if possible. By using ResolveType when we know we need to resolve the node anyways, the resolve cache // can take care of the duplicate call. - if (needsResolving) + if (typeNeedsResolving) return ResolveType(type); else return MakeTypeReference(type); @@ -2174,7 +2204,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (baseTypeDef.Namespace == "System.Collections.Generic" && baseTypeDef.TypeParameterCount == 1) { ParameterizedType pt = baseType as ParameterizedType; if (pt != null) { - return pt.TypeArguments[0]; + return pt.GetTypeArgument(0); } } else if (baseTypeDef.Namespace == "System.Collections" && baseTypeDef.TypeParameterCount == 0) { foundSimpleIEnumerable = true; @@ -2333,14 +2363,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } #endregion - public override ResolveResult VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, object data) - { - // TODO: array initializers are valid expressions if the parent node is a variable/field declaration - // that explicitly defines an array type - ScanChildren(arrayInitializerExpression); - return errorResult; - } - #region Token Nodes public override ResolveResult VisitIdentifier(Identifier identifier, object data) { diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs index 6f76b4ffe4..d389b1ab90 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs @@ -373,7 +373,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Expression" && pt.Namespace == "System.Linq.Expressions") { - t = pt.TypeArguments[0]; + t = pt.GetTypeArgument(0); } return t.GetDelegateInvokeMethod(); } @@ -577,7 +577,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { Log.Indent(); for (int i = 0; i < pU.TypeParameterCount; i++) { - MakeExactInference(pU.TypeArguments[i], pV.TypeArguments[i]); + MakeExactInference(pU.GetTypeArgument(i), pV.GetTypeArgument(i)); } Log.Unindent(); } @@ -620,7 +620,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver MakeLowerBoundInference(arrU.ElementType, arrV.ElementType); return; } else if (arrU != null && IsIEnumerableCollectionOrList(pV) && arrU.Dimensions == 1) { - MakeLowerBoundInference(arrU.ElementType, pV.TypeArguments[0]); + MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0)); return; } // Handle parameterized types: @@ -638,8 +638,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Log.Indent(); if (uniqueBaseType != null) { for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { - IType Ui = uniqueBaseType.TypeArguments[i]; - IType Vi = pV.TypeArguments[i]; + IType Ui = uniqueBaseType.GetTypeArgument(i); + IType Vi = pV.GetTypeArgument(i); if (Ui.IsReferenceType(context) == true) { // look for variance ITypeParameter Xi = pV.GetDefinition().TypeParameters[i]; @@ -704,7 +704,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver MakeUpperBoundInference(arrU.ElementType, arrV.ElementType); return; } else if (arrV != null && IsIEnumerableCollectionOrList(pU) && arrV.Dimensions == 1) { - MakeUpperBoundInference(pU.TypeArguments[0], arrV.ElementType); + MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType); return; } // Handle parameterized types: @@ -722,8 +722,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Log.Indent(); if (uniqueBaseType != null) { for (int i = 0; i < uniqueBaseType.TypeParameterCount; i++) { - IType Ui = pU.TypeArguments[i]; - IType Vi = uniqueBaseType.TypeArguments[i]; + IType Ui = pU.GetTypeArgument(i); + IType Vi = uniqueBaseType.GetTypeArgument(i); if (Ui.IsReferenceType(context) == true) { // look for variance ITypeParameter Xi = pU.GetDefinition().TypeParameters[i]; diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 0f742b91a0..46f5f2918c 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -249,6 +249,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs index e1a6135c65..86dc6884ad 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents an array type. /// - public class ArrayType : TypeWithElementType + public sealed class ArrayType : TypeWithElementType { readonly int dimensions; @@ -83,19 +83,21 @@ namespace ICSharpCode.NRefactory.TypeSystem return baseTypes; } - public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null) + public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return systemArray.Resolve(context).GetMethods(context, filter); + return systemArray.Resolve(context).GetMethods(context, filter, options); } static readonly DefaultParameter indexerParam = new DefaultParameter(KnownTypeReference.Int32, string.Empty); - public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null) + public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { ITypeDefinition arrayDef = systemArray.Resolve(context) as ITypeDefinition; if (arrayDef != null) { - foreach (IProperty p in arrayDef.GetProperties(context, filter)) { - yield return p; + if ((options & GetMemberOptions.IgnoreInheritedMembers) == 0) { + foreach (IProperty p in arrayDef.GetProperties(context, filter, options)) { + yield return p; + } } DefaultProperty indexer = new DefaultProperty(arrayDef, "Items") { EntityType = EntityType.Indexer, diff --git a/ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs b/ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs index e931e4ced8..8ae58c6e7c 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs @@ -21,7 +21,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; namespace ICSharpCode.NRefactory.TypeSystem { - public class ByReferenceType : TypeWithElementType + public sealed class ByReferenceType : TypeWithElementType { public ByReferenceType(IType elementType) : base(elementType) { diff --git a/ICSharpCode.NRefactory/TypeSystem/IType.cs b/ICSharpCode.NRefactory/TypeSystem/IType.cs index efcf77f4c4..a4ec551e0a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IType.cs @@ -145,7 +145,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Base.GetNestedTypes() = { Base`1+Nested`1[`0, unbound] } /// /// - IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); // Note that we cannot 'leak' the additional type parameter as we leak the normal type parameters, because // the index might collide. For example, @@ -170,7 +170,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// and thus 'leaked' to the caller in the same way the GetMembers() method does not specialize members /// from an and 'leaks' type parameters in member signatures. /// - IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null); + IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); /// /// Gets all instance constructors for this type. @@ -185,7 +185,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// and the appropriate will be returned. /// /// - IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers); /// /// Gets all methods that can be called on this type. @@ -212,7 +212,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// the ambiguity can be avoided. /// /// - IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); /// /// Gets all generic methods that can be called on this type with the specified type arguments. @@ -233,7 +233,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// and the other overload's remarks about ambiguous signatures apply here as well. /// /// - IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null); + IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); /// /// Gets all properties that can be called on this type. @@ -245,7 +245,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// For properties on parameterized types, type substitution will be performed on the property signature, /// and the appropriate will be returned. /// - IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); /// /// Gets all fields that can be accessed on this type. @@ -257,7 +257,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// For fields on parameterized types, type substitution will be performed on the field's return type, /// and the appropriate will be returned. /// - IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); /// /// Gets all events that can be accessed on this type. @@ -269,7 +269,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// For fields on parameterized types, type substitution will be performed on the event's return type, /// and the appropriate will be returned. /// - IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); /// /// Gets all members that can be called on this type. @@ -288,7 +288,25 @@ namespace ICSharpCode.NRefactory.TypeSystem /// method apply here as well. /// /// - IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null); + IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None); + } + + [Flags] + public enum GetMemberOptions + { + /// + /// No options specified - this is the default. + /// Members will be specialized, and inherited members will be included. + /// + None = 0x00, + /// + /// Do not specialize the returned members - directly return the definitions. + /// + ReturnMemberDefinitions = 0x01, + /// + /// Do not list inherited members - only list members defined directly on this type. + /// + IgnoreInheritedMembers = 0x02 } #if WITH_CONTRACTS @@ -319,49 +337,49 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } - IEnumerable IType.GetNestedTypes(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetNestedTypes(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); return null; } - IEnumerable IType.GetMethods(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetMethods(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); return null; } - IEnumerable IType.GetConstructors(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetConstructors(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); return null; } - IEnumerable IType.GetProperties(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetProperties(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); return null; } - IEnumerable IType.GetFields(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetFields(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); return null; } - IEnumerable IType.GetEvents(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetEvents(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); return null; } - IEnumerable IType.GetEvents(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetEvents(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { Contract.Requires(context != null); Contract.Ensures(Contract.Result>() != null); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs index 1dceb83720..b3f5996ee2 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs @@ -78,7 +78,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return new List(inputList); } - protected static ReadOnlyCollection FreezeList(IList list) where T : IFreezable + protected static IList FreezeList(IList list) where T : IFreezable { if (list == null || list.Count == 0) return EmptyList.Instance; @@ -89,7 +89,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return result; } - protected static ReadOnlyCollection FreezeList(IList list) + protected static IList FreezeList(IList list) { if (list == null || list.Count == 0) return EmptyList.Instance; @@ -97,7 +97,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return new ReadOnlyCollection(list.ToArray()); } - protected static ReadOnlyCollection FreezeList(IList list) + protected static IList FreezeList(IList list) { if (list == null || list.Count == 0) return EmptyList.Instance; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs index 060082cbeb..bc2a300b2b 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs @@ -77,52 +77,52 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return EmptyList.Instance; } - public virtual IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter) + public virtual IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) { return EmptyList.Instance; } - public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { return EmptyList.Instance; } - public virtual IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return GetMethods(context, filter).SafeCast() - .Concat(GetProperties(context, filter).SafeCast()) - .Concat(GetFields(context, filter).SafeCast()) - .Concat(GetEvents(context, filter).SafeCast()); + return GetMethods(context, filter, options).SafeCast() + .Concat(GetProperties(context, filter, options).SafeCast()) + .Concat(GetFields(context, filter, options).SafeCast()) + .Concat(GetEvents(context, filter, options).SafeCast()); } public override bool Equals(object obj) diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs index b29eb39979..f9c3eaa086 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs @@ -441,72 +441,142 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return this; } - public IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null) + #region GetMembers + public IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetNestedTypes(this, context, filter); + const GetMemberOptions opt = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; + if ((options & opt) == opt) { + ITypeDefinition compound = this.compoundTypeDefinition; + if (compound != this) + return compound.GetNestedTypes(context, filter, options); + + return ApplyFilter(this.NestedTypes, filter); + } else { + return GetMembersHelper.GetNestedTypes(this, context, filter, options); + } } - public IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetNestedTypes(this, typeArguments, context, filter); + return GetMembersHelper.GetNestedTypes(this, typeArguments, context, filter, options); } - public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetMethods(this, context, filter); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + ITypeDefinition compound = this.compoundTypeDefinition; + if (compound != this) + return compound.GetMethods(context, filter, options); + + return ApplyFilter(this.Methods, Utils.ExtensionMethods.And(m => !m.IsConstructor, filter)); + } else { + return GetMembersHelper.GetMethods(this, context, filter, options); + } } - public virtual IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetMethods(this, typeArguments, context, filter); + return GetMembersHelper.GetMethods(this, typeArguments, context, filter, options); } - public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) { - ITypeDefinition compound = this.compoundTypeDefinition; - if (compound != this) - return compound.GetConstructors(context, filter); - - List methods = new List(); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + ITypeDefinition compound = this.compoundTypeDefinition; + if (compound != this) + return compound.GetConstructors(context, filter, options); + + return GetConstructorsImpl(filter); + } else { + return GetMembersHelper.GetConstructors(this, context, filter, options); + } + } + + IEnumerable GetConstructorsImpl(Predicate filter) + { + bool foundCtor = false; foreach (IMethod m in this.Methods) { if (m.IsConstructor && !m.IsStatic) { - if (filter == null || filter(m)) - methods.Add(m); + foundCtor = true; + if (filter == null || filter(m)) { + yield return m; + } } } if (this.AddDefaultConstructorIfRequired) { - if (kind == TypeKind.Class && methods.Count == 0 && !this.IsStatic + if (kind == TypeKind.Class && !foundCtor && !this.IsStatic || kind == TypeKind.Enum || kind == TypeKind.Struct) { var m = DefaultMethod.CreateDefaultConstructor(this); if (filter == null || filter(m)) - methods.Add(m); + yield return m; } } - return methods; } - public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetProperties(this, context, filter); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + ITypeDefinition compound = this.compoundTypeDefinition; + if (compound != this) + return compound.GetProperties(context, filter, options); + + return ApplyFilter(this.Properties, filter); + } else { + return GetMembersHelper.GetProperties(this, context, filter, options); + } } - public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetFields(this, context, filter); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + ITypeDefinition compound = this.compoundTypeDefinition; + if (compound != this) + return compound.GetFields(context, filter, options); + + return ApplyFilter(this.Fields, filter); + } else { + return GetMembersHelper.GetFields(this, context, filter, options); + } } - public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetEvents(this, context, filter); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + ITypeDefinition compound = this.compoundTypeDefinition; + if (compound != this) + return compound.GetEvents(context, filter, options); + + return ApplyFilter(this.Events, filter); + } else { + return GetMembersHelper.GetEvents(this, context, filter, options); + } } - public virtual IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null) + public virtual IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetMembers(this, context, filter); + return GetMembersHelper.GetMembers(this, context, filter, options); } + static IEnumerable ApplyFilter(IList enumerable, Predicate filter) where T : class + { + if (enumerable.Count == 0) + return EmptyList.Instance; + if (filter == null) + return enumerable; + else + return ApplyFilterImpl(enumerable, filter); + } + + static IEnumerable ApplyFilterImpl(IList enumerable, Predicate filter) where T : class + { + foreach (T item in enumerable) + if (filter(item)) + yield return item; + } + #endregion + #region Equals / GetHashCode bool IEquatable.Equals(IType other) { diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs index cc37c190aa..ca234e5bd1 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeParameter.cs @@ -249,44 +249,66 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return c; } - public IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) { - if (HasDefaultConstructorConstraint || HasValueTypeConstraint) { - DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()); - if (filter(m)) - return new [] { m }; + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + if (HasDefaultConstructorConstraint || HasValueTypeConstraint) { + DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter()); + if (filter(m)) + return new [] { m }; + } + return EmptyList.Instance; + } else { + return GetMembersHelper.GetConstructors(this, context, filter, options); } - return EmptyList.Instance; } - public IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetMethods(this, context, FilterNonStatic(filter)); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetMethods(this, context, FilterNonStatic(filter), options); } - public IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetMethods(this, typeArguments, context, FilterNonStatic(filter)); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetMethods(this, typeArguments, context, FilterNonStatic(filter), options); } - public IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetProperties(this, context, FilterNonStatic(filter)); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetProperties(this, context, FilterNonStatic(filter), options); } - public IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetFields(this, context, FilterNonStatic(filter)); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetFields(this, context, FilterNonStatic(filter), options); } - public IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetEvents(this, context, FilterNonStatic(filter)); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetEvents(this, context, FilterNonStatic(filter), options); } - public IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return ParameterizedType.GetMembers(this, context, FilterNonStatic(filter)); + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) + return EmptyList.Instance; + else + return GetMembersHelper.GetMembers(this, context, FilterNonStatic(filter), options); } static Predicate FilterNonStatic(Predicate filter) where T : class, IMember @@ -297,12 +319,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return member => !member.IsStatic && filter(member); } - IEnumerable IType.GetNestedTypes(ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetNestedTypes(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - IEnumerable IType.GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter) + IEnumerable IType.GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs new file mode 100644 index 0000000000..a0aef1f95f --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/GetMembersHelper.cs @@ -0,0 +1,281 @@ +// 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.Linq; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// Provides helper methods for implementing GetMembers() on IType-implementations. + /// Note: GetMembersHelper will recursively call back into IType.GetMembers(), but only with + /// both GetMemberOptions.IgnoreInheritedMembers and GetMemberOptions.ReturnMemberDefinitions set, + /// and only the 'simple' overloads (not taking type arguments). + /// + /// Ensure that your IType implementation does not use the GetMembersHelper if both flags are set, + /// otherwise you'll get a StackOverflowException! + /// + static class GetMembersHelper + { + #region GetNestedTypes + public static IEnumerable GetNestedTypes(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + return GetNestedTypes(type, null, context, filter, options); + } + + public static IEnumerable GetNestedTypes(IType type, IList nestedTypeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetNestedTypesImpl(type, nestedTypeArguments, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetNestedTypesImpl(t, nestedTypeArguments, context, filter, options)); + } + } + + static IEnumerable GetNestedTypesImpl(IType outerType, IList nestedTypeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + ITypeDefinition outerTypeDef = outerType.GetDefinition(); + if (outerTypeDef == null) + yield break; + + int outerTypeParameterCount = outerTypeDef.TypeParameterCount; + ParameterizedType pt = outerType as ParameterizedType; + foreach (ITypeDefinition nestedType in outerTypeDef.NestedTypes) { + int totalTypeParameterCount = nestedType.TypeParameterCount; + if (nestedTypeArguments != null) { + if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) + continue; + } + if (!(filter == null || filter(nestedType))) + continue; + + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + yield return nestedType; + } else if (totalTypeParameterCount == 0 || (pt == null && totalTypeParameterCount == outerTypeParameterCount)) { + // The nested type has no new type parameters, and there are no type arguments + // to copy from the outer type + // -> we can directly return the nested type definition + yield return nestedType; + } else { + // We need to parameterize the nested type + IType[] newTypeArguments = new IType[totalTypeParameterCount]; + for (int i = 0; i < outerTypeParameterCount; i++) { + newTypeArguments[i] = pt != null ? pt.GetTypeArgument(i) : outerTypeDef.TypeParameters[i]; + } + for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { + if (nestedTypeArguments != null) + newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; + else + newTypeArguments[i] = SharedTypes.UnboundTypeArgument; + } + yield return new ParameterizedType(nestedType, newTypeArguments); + } + } + } + #endregion + + #region GetMethods + public static IEnumerable GetMethods(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + return GetMethods(type, null, context, filter, options); + } + + public static IEnumerable GetMethods(IType type, IList typeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if (typeArguments != null && typeArguments.Count > 0) { + filter = FilterTypeParameterCount(typeArguments.Count).And(filter); + } + + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetMethodsImpl(type, typeArguments, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetMethodsImpl(t, typeArguments, context, filter, options)); + } + } + + static Predicate FilterTypeParameterCount(int expectedTypeParameterCount) + { + return m => m.TypeParameters.Count == expectedTypeParameterCount; + } + + const GetMemberOptions declaredMembers = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; + + static IEnumerable GetMethodsImpl(IType baseType, IList methodTypeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredMethods = baseType.GetMethods(context, filter, options | declaredMembers); + + ParameterizedType pt = baseType as ParameterizedType; + if ((options & GetMemberOptions.ReturnMemberDefinitions) == 0 + && (pt != null || (methodTypeArguments != null && methodTypeArguments.Count > 0))) + { + TypeParameterSubstitution substitution = null; + foreach (IMethod m in declaredMethods) { + if (methodTypeArguments != null && methodTypeArguments.Count > 0) { + if (m.TypeParameters.Count != methodTypeArguments.Count) + continue; + } + if (substitution == null) { + if (pt != null) + substitution = pt.GetSubstitution(methodTypeArguments); + else + substitution = new TypeParameterSubstitution(null, methodTypeArguments); + } + yield return new SpecializedMethod(baseType, m, methodTypeArguments, substitution, context); + } + } else { + foreach (IMethod m in declaredMethods) { + yield return m; + } + } + } + #endregion + + #region GetConstructors + public static IEnumerable GetConstructors(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetConstructorsImpl(type, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetConstructorsImpl(t, context, filter, options)); + } + } + + static IEnumerable GetConstructorsImpl(IType baseType, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredCtors = baseType.GetConstructors(context, filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredCtors; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredCtors.Select(m => new SpecializedMethod(pt, m, null, substitution, context)); + } else { + return declaredCtors; + } + } + #endregion + + #region GetProperties + public static IEnumerable GetProperties(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetPropertiesImpl(type, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetPropertiesImpl(t, context, filter, options)); + } + } + + static IEnumerable GetPropertiesImpl(IType baseType, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredProperties = baseType.GetProperties(context, filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredProperties; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredProperties.Select(m => new SpecializedProperty(pt, m, substitution, context)); + } else { + return declaredProperties; + } + } + #endregion + + #region GetFields + public static IEnumerable GetFields(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetFieldsImpl(type, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetFieldsImpl(t, context, filter, options)); + } + } + + static IEnumerable GetFieldsImpl(IType baseType, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredFields = baseType.GetFields(context, filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredFields; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredFields.Select(m => new SpecializedField(pt, m, substitution, context)); + } else { + return declaredFields; + } + } + #endregion + + #region GetEvents + public static IEnumerable GetEvents(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetEventsImpl(type, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetEventsImpl(t, context, filter, options)); + } + } + + static IEnumerable GetEventsImpl(IType baseType, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + IEnumerable declaredEvents = baseType.GetEvents(context, filter, options | declaredMembers); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { + return declaredEvents; + } + + ParameterizedType pt = baseType as ParameterizedType; + if (pt != null) { + var substitution = pt.GetSubstitution(); + return declaredEvents.Select(m => new SpecializedEvent(pt, m, substitution, context)); + } else { + return declaredEvents; + } + } + #endregion + + #region GetMembers + public static IEnumerable GetMembers(IType type, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { + return GetMembersImpl(type, context, filter, options); + } else { + return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetMembersImpl(t, context, filter, options)); + } + } + + static IEnumerable GetMembersImpl(IType baseType, ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + foreach (var m in GetMethodsImpl(baseType, null, context, filter, options)) + yield return m; + foreach (var m in GetPropertiesImpl(baseType, context, filter, options)) + yield return m; + foreach (var m in GetFieldsImpl(baseType, context, filter, options)) + yield return m; + foreach (var m in GetEventsImpl(baseType, context, filter, options)) + yield return m; + } + #endregion + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs index bdd1571f34..cacfadd857 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterSubstitution.cs @@ -72,10 +72,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation bool first = true; if (classTypeArguments != null) { for (int i = 0; i < classTypeArguments.Count; i++) { - if (first) { - first = false; - b.Append(", "); - } + if (first) first = false; else b.Append(", "); b.Append('`'); b.Append(i); b.Append(" -> "); @@ -84,10 +81,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } if (methodTypeArguments != null) { for (int i = 0; i < methodTypeArguments.Count; i++) { - if (first) { - first = false; - b.Append(", "); - } + if (first) first = false; else b.Append(", "); b.Append("``"); b.Append(i); b.Append(" -> "); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs index 3e9c2c9f21..e8ec0a12c3 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/VoidTypeDefinition.cs @@ -34,37 +34,37 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation this.IsSealed = true; } - public override IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - public override IEnumerable GetEvents(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetEvents(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - public override IEnumerable GetFields(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetFields(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - public override IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter) + public override IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } - public override IEnumerable GetMembers(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetMembers(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { return EmptyList.Instance; } diff --git a/ICSharpCode.NRefactory/TypeSystem/IntersectionType.cs b/ICSharpCode.NRefactory/TypeSystem/IntersectionType.cs index 4289366ac2..3e0251845a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IntersectionType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IntersectionType.cs @@ -123,29 +123,34 @@ namespace ICSharpCode.NRefactory.TypeSystem return types; } - public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetMethods(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { - return ParameterizedType.GetMethods(this, context, FilterNonStatic(filter)); + return GetMembersHelper.GetMethods(this, context, FilterNonStatic(filter), options); } - public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter, GetMemberOptions options) { - return ParameterizedType.GetProperties(this, context, FilterNonStatic(filter)); + return GetMembersHelper.GetMethods(this, typeArguments, context, filter, options); } - public override IEnumerable GetFields(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetProperties(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { - return ParameterizedType.GetFields(this, context, FilterNonStatic(filter)); + return GetMembersHelper.GetProperties(this, context, FilterNonStatic(filter), options); } - public override IEnumerable GetEvents(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetFields(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { - return ParameterizedType.GetEvents(this, context, FilterNonStatic(filter)); + return GetMembersHelper.GetFields(this, context, FilterNonStatic(filter), options); } - public override IEnumerable GetMembers(ITypeResolveContext context, Predicate filter) + public override IEnumerable GetEvents(ITypeResolveContext context, Predicate filter, GetMemberOptions options) { - return ParameterizedType.GetMembers(this, context, FilterNonStatic(filter)); + return GetMembersHelper.GetEvents(this, context, FilterNonStatic(filter), options); + } + + public override IEnumerable GetMembers(ITypeResolveContext context, Predicate filter, GetMemberOptions options) + { + return GetMembersHelper.GetMembers(this, context, FilterNonStatic(filter), options); } static Predicate FilterNonStatic(Predicate filter) where T : class, IMember diff --git a/ICSharpCode.NRefactory/TypeSystem/NullableType.cs b/ICSharpCode.NRefactory/TypeSystem/NullableType.cs index cf86685955..16ad7be8cb 100644 --- a/ICSharpCode.NRefactory/TypeSystem/NullableType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/NullableType.cs @@ -34,7 +34,7 @@ namespace ICSharpCode.NRefactory.TypeSystem if (type == null) throw new ArgumentNullException("type"); ParameterizedType pt = type as ParameterizedType; - return pt != null && pt.TypeArguments.Count == 1 && pt.FullName == "System.Nullable"; + return pt != null && pt.TypeParameterCount == 1 && pt.FullName == "System.Nullable"; } public static bool IsNonNullableValueType(IType type, ITypeResolveContext context) @@ -51,8 +51,8 @@ namespace ICSharpCode.NRefactory.TypeSystem if (type == null) throw new ArgumentNullException("type"); ParameterizedType pt = type as ParameterizedType; - if (pt != null && pt.TypeArguments.Count == 1 && pt.FullName == "System.Nullable") - return pt.TypeArguments[0]; + if (pt != null && pt.TypeParameterCount == 1 && pt.FullName == "System.Nullable") + return pt.GetTypeArgument(0); else return type; } diff --git a/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs b/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs index 7f7e77b715..9cd4f872e8 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs @@ -94,7 +94,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } public int TypeParameterCount { - get { return genericType.TypeParameterCount; } + get { return typeArguments.Length; } } public string FullName { @@ -136,6 +136,14 @@ namespace ICSharpCode.NRefactory.TypeSystem } } + /// + /// Same as 'parameterizedType.TypeArguments[index]', but is a bit more efficient. + /// + internal IType GetTypeArgument(int index) + { + return typeArguments[index]; + } + public ITypeDefinition GetDefinition() { return genericType.GetDefinition(); @@ -169,7 +177,7 @@ namespace ICSharpCode.NRefactory.TypeSystem /// of this parameterized type, /// and also substitutes method type parameters with the specified method type arguments. /// - public TypeVisitor GetSubstitution(IList methodTypeArguments) + public TypeParameterSubstitution GetSubstitution(IList methodTypeArguments) { return new TypeParameterSubstitution(typeArguments, methodTypeArguments); } @@ -180,259 +188,76 @@ namespace ICSharpCode.NRefactory.TypeSystem return genericType.GetBaseTypes(context).Select(t => t.AcceptVisitor(substitution)); } - public IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null) - { - return GetNestedTypes(this, context, filter); - } - - public IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null) - { - return GetNestedTypes(this, typeArguments, context, filter); - } - - internal static IEnumerable GetNestedTypes(IType type, ITypeResolveContext context, Predicate filter) - { - return GetNestedTypes(type, null, context, filter); - } - - internal static IEnumerable GetNestedTypes(IType type, IList nestedTypeArguments, ITypeResolveContext context, Predicate filter) - { - return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetNestedTypesInternal(t, nestedTypeArguments, context, filter)); - } - - static IEnumerable GetNestedTypesInternal(IType baseType, IList nestedTypeArguments, ITypeResolveContext context, Predicate filter) - { - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef == null) - yield break; - - int outerTypeParameterCount = baseTypeDef.TypeParameterCount; - ParameterizedType pt = baseType as ParameterizedType; - foreach (ITypeDefinition nestedType in baseTypeDef.NestedTypes) { - int totalTypeParameterCount = nestedType.TypeParameterCount; - if (nestedTypeArguments != null) { - if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) - continue; - } - if (!(filter == null || filter(nestedType))) - continue; - - if (totalTypeParameterCount == 0 || (pt == null && totalTypeParameterCount == outerTypeParameterCount)) { - // The nested type has no new type parameters, and there are no type arguments - // to copy from the outer type - // -> we can directly return the nested type definition - yield return nestedType; - } else { - // We need to parameterize the nested type - IType[] newTypeArguments = new IType[totalTypeParameterCount]; - for (int i = 0; i < outerTypeParameterCount; i++) { - newTypeArguments[i] = pt != null ? pt.typeArguments[i] : baseTypeDef.TypeParameters[i]; - } - for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { - if (nestedTypeArguments != null) - newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; - else - newTypeArguments[i] = SharedTypes.UnboundTypeArgument; - } - yield return new ParameterizedType(nestedType, newTypeArguments); - } - } - } - - public IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null) - { - var substitution = GetSubstitution(); - List methods = genericType.GetConstructors(context, filter).ToList(); - for (int i = 0; i < methods.Count; i++) { - methods[i] = new SpecializedMethod(this, methods[i], null, substitution, context); - } - return methods; - } - - public IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null) - { - return GetMethods(this, context, filter); - } - - public IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return GetMethods(this, typeArguments, context, filter); - } - - internal static IEnumerable GetMethods(IType type, ITypeResolveContext context, Predicate filter) - { - return GetMethods(type, null, context, filter); - } - - internal static IEnumerable GetMethods(IType type, IList typeArguments, ITypeResolveContext context, Predicate filter) - { - Predicate newFilter; - if (filter == null) - newFilter = m => !m.IsConstructor; + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetNestedTypes(context, filter, options); else - newFilter = m => !m.IsConstructor && filter(m); - return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetMethodsInternal(t, typeArguments, context, newFilter)); - } - - static IEnumerable GetMethodsInternal(IType baseType, IList methodTypeArguments, ITypeResolveContext context, Predicate filter) - { - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef == null) - yield break; - - ParameterizedType pt = baseType as ParameterizedType; - if (pt != null || (methodTypeArguments != null && methodTypeArguments.Count > 0)) { - TypeVisitor substitution = null; - foreach (IMethod m in baseTypeDef.Methods) { - if (methodTypeArguments != null && methodTypeArguments.Count > 0) { - if (m.TypeParameters.Count != methodTypeArguments.Count) - continue; - } - if (!(filter == null || filter(m))) - continue; - if (substitution == null) { - substitution = new TypeParameterSubstitution(pt != null ? pt.typeArguments : null, methodTypeArguments); - } - yield return new SpecializedMethod(baseType, m, methodTypeArguments, substitution, context); - } - } else { - foreach (IMethod m in baseTypeDef.Methods) { - if (filter == null || filter(m)) - yield return m; - } - } - } - - public IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null) - { - return GetProperties(this, context, filter); - } - - internal static IEnumerable GetProperties(IType type, ITypeResolveContext context, Predicate filter) - { - return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetPropertiesInternal(t, context, filter)); - } - - static IEnumerable GetPropertiesInternal(IType baseType, ITypeResolveContext context, Predicate filter) - { - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef == null) - yield break; - - ParameterizedType pt = baseType as ParameterizedType; - if (pt != null) { - TypeParameterSubstitution substitution = null; - foreach (IProperty p in baseTypeDef.Properties) { - if (!(filter == null || filter(p))) - continue; - if (substitution == null) { - substitution = pt.GetSubstitution(); - } - yield return new SpecializedProperty(pt, p, substitution, context); - } - } else { - foreach (IProperty p in baseTypeDef.Properties) { - if (filter == null || filter(p)) - yield return p; - } - } - } - - public IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null) - { - return GetFields(this, context, filter); + return GetMembersHelper.GetNestedTypes(this, context, filter, options); } - internal static IEnumerable GetFields(IType type, ITypeResolveContext context, Predicate filter) + public IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetFieldsInternal(t, context, filter)); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetNestedTypes(typeArguments, context, filter, options); + else + return GetMembersHelper.GetNestedTypes(this, typeArguments, context, filter, options); } - static IEnumerable GetFieldsInternal(IType baseType, ITypeResolveContext context, Predicate filter) + public IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) { - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef == null) - yield break; - - ParameterizedType pt = baseType as ParameterizedType; - if (pt != null) { - TypeParameterSubstitution substitution = null; - foreach (IField f in baseTypeDef.Fields) { - if (!(filter == null || filter(f))) - continue; - if (substitution == null) { - substitution = pt.GetSubstitution(); - } - yield return new SpecializedField(pt, f, substitution, context); - } - } else { - foreach (IField f in baseTypeDef.Fields) { - if (filter == null || filter(f)) - yield return f; - } - } + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetConstructors(context, filter, options); + else + return GetMembersHelper.GetConstructors(this, context, filter, options); } - public IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return GetEvents(this, context, filter); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetMethods(context, filter, options); + else + return GetMembersHelper.GetMethods(this, context, filter, options); } - internal static IEnumerable GetEvents(IType type, ITypeResolveContext context, Predicate filter) + public IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetEventsInternal(t, context, filter)); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetMethods(typeArguments, context, filter, options); + else + return GetMembersHelper.GetMethods(this, typeArguments, context, filter, options); } - static IEnumerable GetEventsInternal(IType baseType, ITypeResolveContext context, Predicate filter) + public IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef == null) - yield break; - - ParameterizedType pt = baseType as ParameterizedType; - if (pt != null) { - TypeParameterSubstitution substitution = null; - foreach (IEvent e in baseTypeDef.Events) { - if (!(filter == null || filter(e))) - continue; - if (substitution == null) { - substitution = pt.GetSubstitution(); - } - yield return new SpecializedEvent(pt, e, substitution, context); - } - } else { - foreach (IEvent e in baseTypeDef.Events) { - if (filter == null || filter(e)) - yield return e; - } - } + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetProperties(context, filter, options); + else + return GetMembersHelper.GetProperties(this, context, filter, options); } - public IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null) + public IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - return GetMembers(this, context, filter); + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetFields(context, filter, options); + else + return GetMembersHelper.GetFields(this, context, filter, options); } - internal static IEnumerable GetMembers(IType type, ITypeResolveContext context, Predicate filter) + public IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - Predicate methodFilter; - if (filter == null) - methodFilter = m => !m.IsConstructor; + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetEvents(context, filter, options); else - methodFilter = m => !m.IsConstructor && filter(m); - return type.GetNonInterfaceBaseTypes(context).SelectMany(t => GetMembersInternal(t, context, filter)); + return GetMembersHelper.GetEvents(this, context, filter, options); } - static IEnumerable GetMembersInternal(IType baseType, ITypeResolveContext context, Predicate filter) + public IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { - foreach (var m in GetMethodsInternal(baseType, null, context, filter)) - yield return m; - foreach (var m in GetPropertiesInternal(baseType, context, filter)) - yield return m; - foreach (var m in GetFieldsInternal(baseType, context, filter)) - yield return m; - foreach (var m in GetEventsInternal(baseType, context, filter)) - yield return m; + if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) + return genericType.GetMembers(context, filter, options); + else + return GetMembersHelper.GetMembers(this, context, filter, options); } public override bool Equals(object obj) diff --git a/ICSharpCode.NRefactory/TypeSystem/PointerType.cs b/ICSharpCode.NRefactory/TypeSystem/PointerType.cs index ba70e36a8c..2b2a54d6d7 100644 --- a/ICSharpCode.NRefactory/TypeSystem/PointerType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/PointerType.cs @@ -22,7 +22,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; namespace ICSharpCode.NRefactory.TypeSystem { - public class PointerType : TypeWithElementType + public sealed class PointerType : TypeWithElementType { public PointerType(IType elementType) : base(elementType) { diff --git a/ICSharpCode.NRefactory/Utils/EmptyList.cs b/ICSharpCode.NRefactory/Utils/EmptyList.cs index b195631495..4022223a83 100644 --- a/ICSharpCode.NRefactory/Utils/EmptyList.cs +++ b/ICSharpCode.NRefactory/Utils/EmptyList.cs @@ -17,12 +17,98 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.ObjectModel; namespace ICSharpCode.NRefactory { - static class EmptyList + sealed class EmptyList : IList, IEnumerator { - public static readonly ReadOnlyCollection Instance = new ReadOnlyCollection(new T[0]); + public static readonly IList Instance = new EmptyList(); + + private EmptyList() {} + + T IList.this[int index] { + get { throw new IndexOutOfRangeException(); } + set { throw new IndexOutOfRangeException(); } + } + + int ICollection.Count { + get { return 0; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + int IList.IndexOf(T item) + { + return -1; + } + + void IList.Insert(int index, T item) + { + throw new NotSupportedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + + void ICollection.Add(T item) + { + throw new NotSupportedException(); + } + + void ICollection.Clear() + { + } + + bool ICollection.Contains(T item) + { + return false; + } + + void ICollection.CopyTo(T[] array, int arrayIndex) + { + } + + bool ICollection.Remove(T item) + { + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this; + } + + T IEnumerator.Current { + get { return default(T); } + } + + object IEnumerator.Current { + get { return default(T); } + } + + void IDisposable.Dispose() + { + } + + bool IEnumerator.MoveNext() + { + return false; + } + + void IEnumerator.Reset() + { + } } } diff --git a/ICSharpCode.NRefactory/Utils/ExtensionMethods.cs b/ICSharpCode.NRefactory/Utils/ExtensionMethods.cs index 72ab7a91eb..dd7d29c414 100644 --- a/ICSharpCode.NRefactory/Utils/ExtensionMethods.cs +++ b/ICSharpCode.NRefactory/Utils/ExtensionMethods.cs @@ -31,5 +31,14 @@ namespace ICSharpCode.NRefactory.Utils foreach (T item in input) target.Add(item); } + + public static Predicate And(this Predicate filter1, Predicate filter2) + { + if (filter1 == null) + return filter2; + if (filter2 == null) + return filter1; + return m => filter1(m) && filter2(m); + } } }