diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreateTests.cs similarity index 90% rename from ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreationTests.cs rename to ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreateTests.cs index 895c89abcc..a3d45f6c08 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ArrayCreateTests.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { [TestFixture] [Ignore("Parser produces incorrect positions")] - public class ArrayCreationTests : ResolverTestBase + public class ArrayCreateTests : ResolverTestBase { [Test] public void SimpleArrayCreation() @@ -100,5 +100,17 @@ class A { var result = Resolve(program); Assert.AreEqual("System.Int32[]", result.Type.ReflectionName); } + + [Test] + public void ArrayInitializerExpression2D() + { + string program = @"using System.Collections.Generic; +class A { + int[,] a = ${ { 1 }, { 2 } }$; +} +"; + var result = Resolve(program); + Assert.AreEqual("System.Int32[,]", result.Type.ReflectionName); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs index 4a91bcb3a6..4698fe27b1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs @@ -74,7 +74,7 @@ class SomeClass { #region Lambda In Initializer [Test] - public void LambdaInCollectionInitializerTest1() + public void LambdaInArrayInitializer1() { string program = @"using System; class TestClass { @@ -90,12 +90,12 @@ class TestClass { } [Test] - public void LambdaInCollectionInitializerTest2() + public void LambdaInArrayInitializer2() { - string program = @"using System; using System.Collections.Generic; + string program = @"using System; class TestClass { static void Main() { - a = new List> { + a = new Converter[] { i => $i$.ToString() }; } @@ -106,15 +106,13 @@ class TestClass { } [Test] - public void LambdaInCollectionInitializerTest3() + public void LambdaInArrayInitializer3() { string program = @"using System; class TestClass { - static void Main() { - a = new Converter[] { - i => $i$.ToString() - }; - } + Converter[] field = new Converter[] { + i => $i$.ToString() + }; } "; var lrr = Resolve(program); @@ -122,11 +120,11 @@ class TestClass { } [Test] - public void LambdaInCollectionInitializerTest4() + public void LambdaInArrayInitializer4() { string program = @"using System; class TestClass { - Converter[] field = new Converter[] { + Converter[] field = { i => $i$.ToString() }; } @@ -136,13 +134,48 @@ class TestClass { } [Test] - public void LambdaInCollectionInitializerTest5() + public void LambdaInCollectionInitializer1() { - string program = @"using System; + string program = @"using System; using System.Collections.Generic; class TestClass { - Converter[] field = { - i => $i$.ToString() - }; + static void Main() { + a = new List> { + i => $i$.ToString() + }; + } +} +"; + var lrr = Resolve(program); + Assert.AreEqual("System.Int32", lrr.Type.ReflectionName); + } + + [Test] + public void LambdaInCollectionInitializer2() + { + string program = @"using System; using System.Collections.Generic; +class TestClass { + static void Main() { + a = new Dictionary, Converter> { + { i => $i$.ToString(), i => i.ToString() } + }; + } +} +"; + var lrr = Resolve(program); + Assert.AreEqual("System.Char", lrr.Type.ReflectionName); + } + + + [Test] + public void LambdaInCollectionInitializer3() + { + string program = @"using System; using System.Collections.Generic; +class TestClass { + static void Main() { + a = new Dictionary, Converter> { + { i => i.ToString(), $i$ => i.ToString() } + }; + } } "; var lrr = Resolve(program); diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index 83daa9022c..5b247cae60 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -119,7 +119,7 @@ - + diff --git a/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs b/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs index ecc5210a1b..ee0a2180f5 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs @@ -445,9 +445,9 @@ namespace ICSharpCode.NRefactory.CSharp return VisitChildren (anonymousTypeCreateExpression, data); } - public virtual S VisitArrayCreateExpression (ArrayCreateExpression arrayObjectCreateExpression, T data) + public virtual S VisitArrayCreateExpression (ArrayCreateExpression arrayCreateExpression, T data) { - return VisitChildren (arrayObjectCreateExpression, data); + return VisitChildren (arrayCreateExpression, data); } public virtual S VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression, T data) diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index b5207f10a5..4474d8838f 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -995,15 +995,20 @@ namespace ICSharpCode.NRefactory.CSharp } } - public override ConstantExpression VisitArrayCreateExpression(ArrayCreateExpression arrayObjectCreateExpression, object data) + public override ConstantExpression VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data) { - var initializer = arrayObjectCreateExpression.Initializer; - if (isAttributeArgument && !initializer.IsNull) { + var initializer = arrayCreateExpression.Initializer; + // Attributes only allow one-dimensional arrays + if (isAttributeArgument && !initializer.IsNull && arrayCreateExpression.Arguments.Count < 2) { ITypeReference type; - if (arrayObjectCreateExpression.Type.IsNull) + if (arrayCreateExpression.Type.IsNull) { type = null; - else - type = convertVisitor.ConvertType(arrayObjectCreateExpression.Type); + } else { + type = convertVisitor.ConvertType(arrayCreateExpression.Type); + foreach (var spec in arrayCreateExpression.AdditionalArraySpecifiers.Reverse()) { + type = ArrayTypeReference.Create(type, spec.Dimensions); + } + } ConstantExpression[] elements = new ConstantExpression[initializer.Elements.Count]; int pos = 0; foreach (Expression expr in initializer.Elements) { diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index 1215f14cfc..9b6e3b553d 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -726,8 +726,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver cancellationToken.ThrowIfCancellationRequested(); if (SharedTypes.Dynamic.Equals(lhs.Type) || SharedTypes.Dynamic.Equals(rhs.Type)) { - lhs = Convert(lhs, SharedTypes.Dynamic, conversions.ImplicitConversion(lhs, SharedTypes.Dynamic)); - rhs = Convert(rhs, SharedTypes.Dynamic, conversions.ImplicitConversion(rhs, SharedTypes.Dynamic)); + lhs = Convert(lhs, SharedTypes.Dynamic); + rhs = Convert(rhs, SharedTypes.Dynamic); return new BinaryOperatorResolveResult(SharedTypes.Dynamic, lhs, op, rhs); } @@ -1744,6 +1744,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } + ResolveResult Convert(ResolveResult rr, IType targetType) + { + return Convert(rr, targetType, conversions.ImplicitConversion(rr, targetType)); + } + ResolveResult Convert(ResolveResult rr, ITypeReference targetType, Conversion c) { if (c == Conversion.IdentityConversion) @@ -2155,6 +2160,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region ResolveInvocation + /// + /// Resolves an invocation. + /// + /// The target of the invocation. Usually a MethodGroupResolveResult. + /// + /// Arguments passed to the method. + /// The resolver may mutate this array to wrap elements in s! + /// + /// + /// The argument names. Pass the null string for positional arguments. + /// + /// InvocationResolveResult or UnknownMethodResolveResult public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null) { // C# 4.0 spec: §7.6.5 @@ -2274,6 +2291,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region ResolveIndexer + /// + /// Resolves an indexer access. + /// + /// Target expression. + /// + /// Arguments passed to the indexer. + /// The resolver may mutate this array to wrap elements in s! + /// + /// + /// The argument names. Pass the null string for positional arguments. + /// + /// ArrayAccessResolveResult, InvocationResolveResult, or ErrorResolveResult public ResolveResult ResolveIndexer(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null) { cancellationToken.ThrowIfCancellationRequested(); @@ -2281,24 +2310,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver switch (target.Type.Kind) { case TypeKind.Dynamic: for (int i = 0; i < arguments.Length; i++) { - arguments[i] = Convert(arguments[i], SharedTypes.Dynamic, - conversions.ImplicitConversion(arguments[i], SharedTypes.Dynamic)); + arguments[i] = Convert(arguments[i], SharedTypes.Dynamic); } return new ArrayAccessResolveResult(SharedTypes.Dynamic, target, arguments); case TypeKind.Array: case TypeKind.Pointer: // §7.6.6.1 Array access / §18.5.3 Pointer element access - for (int i = 0; i < arguments.Length; i++) { - if (!(TryConvert(ref arguments[i], KnownTypeReference.Int32.Resolve(context)) || - TryConvert(ref arguments[i], KnownTypeReference.UInt32.Resolve(context)) || - TryConvert(ref arguments[i], KnownTypeReference.Int64.Resolve(context)) || - TryConvert(ref arguments[i], KnownTypeReference.UInt64.Resolve(context)))) - { - // conversion failed - arguments[i] = Convert(arguments[i], KnownTypeReference.Int32, Conversion.None); - } - } + AdjustArrayAccessArguments(arguments); return new ArrayAccessResolveResult(((TypeWithElementType)target.Type).ElementType, target, arguments); } @@ -2318,9 +2337,38 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return ErrorResult; } } + + /// + /// Converts all arguments to int,uint,long or ulong. + /// + void AdjustArrayAccessArguments(ResolveResult[] arguments) + { + for (int i = 0; i < arguments.Length; i++) { + if (!(TryConvert(ref arguments[i], KnownTypeReference.Int32.Resolve(context)) || + TryConvert(ref arguments[i], KnownTypeReference.UInt32.Resolve(context)) || + TryConvert(ref arguments[i], KnownTypeReference.Int64.Resolve(context)) || + TryConvert(ref arguments[i], KnownTypeReference.UInt64.Resolve(context)))) + { + // conversion failed + arguments[i] = Convert(arguments[i], KnownTypeReference.Int32, Conversion.None); + } + } + } #endregion #region ResolveObjectCreation + /// + /// Resolves an object creation. + /// + /// Type of the object to create. + /// + /// Arguments passed to the constructor. + /// The resolver may mutate this array to wrap elements in s! + /// + /// + /// The argument names. Pass the null string for positional arguments. + /// + /// InvocationResolveResult or ErrorResolveResult public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null) { cancellationToken.ThrowIfCancellationRequested(); @@ -2519,53 +2567,51 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } #endregion - } - - /// - /// Resolver logging helper. - /// Wraps System.Diagnostics.Debug so that resolver-specific logging can be enabled/disabled on demand. - /// (it's a huge amount of debug spew and slows down the resolver quite a bit) - /// - static class Log - { - [Conditional("DEBUG")] - internal static void WriteLine(string text) - { - Debug.WriteLine(text); - } - [Conditional("DEBUG")] - internal static void WriteLine(string format, params object[] args) - { - Debug.WriteLine(format, args); - } - - [Conditional("DEBUG")] - internal static void WriteCollection(string text, IEnumerable lines) - { - #if DEBUG - T[] arr = lines.ToArray(); - if (arr.Length == 0) { - Debug.WriteLine(text + ""); - } else { - Debug.WriteLine(text + (arr[0] != null ? arr[0].ToString() : "")); - for (int i = 1; i < arr.Length; i++) { - Debug.WriteLine(new string(' ', text.Length) + (arr[i] != null ? arr[i].ToString() : "")); + #region ResolveArrayCreation + /// + /// Resolves an array creation. + /// + /// + /// The array element type. + /// Pass null to resolve an implicitly-typed array creation. + /// + /// + /// The number of array dimensions. + /// + /// + /// The size arguments. May be null if no explicit size was given. + /// The resolver may mutate this array to wrap elements in s! + /// + /// + /// The initializer elements. May be null if no array initializer was specified. + /// The resolver may mutate this array to wrap elements in s! + /// + /// + /// Specifies whether to allow treating single-dimensional arrays like compile-time constants. + /// This is used for attribute arguments. + /// + public ResolveResult ResolveArrayCreation(IType elementType, int dimensions = 1, ResolveResult[] sizeArguments = null, ResolveResult[] initializerElements = null, bool allowArrayConstants = false) + { + if (sizeArguments != null && dimensions != Math.Max(1, sizeArguments.Length)) + throw new ArgumentException("dimensions and sizeArguments.Length don't match"); + if (elementType == null) { + TypeInference typeInference = new TypeInference(context, conversions); + bool success; + elementType = typeInference.GetBestCommonType(initializerElements, out success); + } + IType arrayType = new ArrayType(elementType, dimensions); + + if (sizeArguments != null) + AdjustArrayAccessArguments(sizeArguments); + + if (initializerElements != null) { + for (int i = 0; i < initializerElements.Length; i++) { + initializerElements[i] = Convert(initializerElements[i], elementType); } } - #endif - } - - [Conditional("DEBUG")] - public static void Indent() - { - Debug.Indent(); - } - - [Conditional("DEBUG")] - public static void Unindent() - { - Debug.Unindent(); + return new ArrayCreateResolveResult(arrayType, sizeArguments, initializerElements, allowArrayConstants); } + #endregion } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs index 9f778f870e..701384519b 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ConstantValues.cs @@ -617,37 +617,45 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver.ConstantValues public sealed class ConstantArrayCreation : ConstantExpression, ISupportsInterning { // type may be null when the element is being inferred - ITypeReference type; + ITypeReference elementType; IList arrayElements; public ConstantArrayCreation(ITypeReference type, IList arrayElements) { if (arrayElements == null) throw new ArgumentNullException("arrayElements"); - this.type = type; + this.elementType = type; this.arrayElements = arrayElements; } public override ResolveResult Resolve(CSharpResolver resolver) { - throw new NotImplementedException(); + ResolveResult[] elements = new ResolveResult[arrayElements.Count]; + for (int i = 0; i < elements.Length; i++) { + elements[i] = arrayElements[i].Resolve(resolver); + } + if (elementType != null) { + return resolver.ResolveArrayCreation(elementType.Resolve(resolver.Context), 1, null, elements, true); + } else { + return resolver.ResolveArrayCreation(null, 1, null, elements, true); + } } void ISupportsInterning.PrepareForInterning(IInterningProvider provider) { - type = provider.Intern(type); + elementType = provider.Intern(elementType); arrayElements = provider.InternList(arrayElements); } int ISupportsInterning.GetHashCodeForInterning() { - return (type != null ? type.GetHashCode() : 0) ^ arrayElements.GetHashCode(); + return (elementType != null ? elementType.GetHashCode() : 0) ^ arrayElements.GetHashCode(); } bool ISupportsInterning.EqualsForInterning(ISupportsInterning other) { ConstantArrayCreation cac = other as ConstantArrayCreation; - return cac != null && this.type == cac.type && this.arrayElements == cac.arrayElements; + return cac != null && this.elementType == cac.elementType && this.arrayElements == cac.arrayElements; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs b/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs new file mode 100644 index 0000000000..fe0a58bc02 --- /dev/null +++ b/ICSharpCode.NRefactory/CSharp/Resolver/Log.cs @@ -0,0 +1,78 @@ +// 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.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + /// + /// Resolver logging helper. + /// Wraps System.Diagnostics.Debug so that resolver-specific logging can be enabled/disabled on demand. + /// (it's a huge amount of debug spew and slows down the resolver quite a bit) + /// + static class Log + { + [Conditional("DEBUG")] + internal static void WriteLine(string text) + { + Debug.WriteLine(text); + } + + [Conditional("DEBUG")] + internal static void WriteLine(string format, params object[] args) + { + Debug.WriteLine(format, args); + } + + [Conditional("DEBUG")] + internal static void WriteCollection(string text, IEnumerable lines) + { + #if DEBUG + T[] arr = lines.ToArray(); + if (arr.Length == 0) { + Debug.WriteLine(text + ""); + } else { + Debug.WriteLine(text + (arr[0] != null ? arr[0].ToString() : "")); + for (int i = 1; i < arr.Length; i++) { + Debug.WriteLine(new string(' ', text.Length) + (arr[i] != null ? arr[i].ToString() : "")); + } + } + #endif + } + + [Conditional("DEBUG")] + public static void Indent() + { + Debug.Indent(); + } + + [Conditional("DEBUG")] + public static void Unindent() + { + Debug.Unindent(); + } + } +} diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs b/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs index 3328fca06c..cb443ec499 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/OperatorResolveResult.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.Resolver { @@ -127,4 +128,87 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return new [] { Array }.Concat(Indices); } } + + /// + /// Resolve result representing an array creation. + /// + public class ArrayCreateResolveResult : ResolveResult + { + /// + /// Gets the size arguments. + /// + public readonly ResolveResult[] SizeArguments; + + /// + /// Gets the initializer elements. + /// This field may be null if no initializer was specified. + /// + public readonly ResolveResult[] InitializerElements; + + readonly object[] constantArray; + + public ArrayCreateResolveResult(IType arrayType, ResolveResult[] sizeArguments, ResolveResult[] initializerElements, + bool allowArrayConstants) + : base(arrayType) + { + this.SizeArguments = sizeArguments; + this.InitializerElements = initializerElements; + if (allowArrayConstants) { + this.constantArray = MakeConstantArray(sizeArguments, initializerElements); + } + } + + static object[] MakeConstantArray(ResolveResult[] sizeArguments, ResolveResult[] initializerElements) + { + if (initializerElements == null) + return null; + + for (int i = 0; i < initializerElements.Length; i++) { + if (!initializerElements[i].IsCompileTimeConstant) + return null; + } + + if (sizeArguments != null && sizeArguments.Length > 0) { + if (sizeArguments.Length > 1) { + // 2D-arrays can't be constant + return null; + } + if (!sizeArguments[0].IsCompileTimeConstant) + return null; + + int expectedSize; + try { + expectedSize = (int)CSharpPrimitiveCast.Cast(TypeCode.Int32, sizeArguments[0].ConstantValue, true); + } catch (InvalidCastException) { + return null; + } catch (OverflowException) { + return null; + } + if (expectedSize != initializerElements.Length) + return null; + } + + object[] constants = new object[initializerElements.Length]; + for (int i = 0; i < initializerElements.Length; i++) { + constants[i] = initializerElements[i].ConstantValue; + } + return constants; + } + + public override object ConstantValue { + get { return constantArray; } + } + + public override bool IsCompileTimeConstant { + get { return constantArray != null; } + } + + public override IEnumerable GetChildResults() + { + if (SizeArguments != null && InitializerElements != null) + return SizeArguments.Concat(InitializerElements); + else + return SizeArguments ?? InitializerElements ?? Enumerable.Empty(); + } + } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs index 6372704d99..5101916095 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs @@ -89,7 +89,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { this.Member = member; this.IsExpandedForm = isExpanded; - this.Parameters = ((IParameterizedMember)member.MemberDefinition).Parameters; + if (this.IsGenericMethod) { + // For generic methods, go back to the original parameters + // (without any type parameter substitution, not even class type parameters) + // We'll re-substitute them as part of RunTypeInference(). + this.Parameters = ((IParameterizedMember)member.MemberDefinition).Parameters; + } else { + this.Parameters = member.Parameters; + } this.ParameterTypes = new IType[this.Parameters.Count]; } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 5082e4a05e..9e905b9d61 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -203,10 +203,21 @@ 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); - resolverBeforeDict.Add(node, resolverState); + // It's possible that we re-visit an expression that we scanned over earlier, + // so we might have to overwrite an existing state. + resolverBeforeDict[node] = resolverState; } void StoreResult(AstNode node, ResolveResult result) @@ -782,31 +793,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (!resolverEnabled) { return null; } - IType arrType; + + int dimensions = arrayCreateExpression.Arguments.Count; + ResolveResult[] sizeArguments; + if (dimensions == 0) { + dimensions = 1; + sizeArguments = null; + } else { + if (arrayCreateExpression.Arguments.All(e => e is EmptyExpression)) + sizeArguments = null; + else + sizeArguments = Resolve(arrayCreateExpression.Arguments); + } + + ResolveResult[] initializerElements; + if (arrayCreateExpression.Initializer.IsNull) + initializerElements = null; + else + initializerElements = Resolve(arrayCreateExpression.Initializer.Elements); + if (arrayCreateExpression.Type.IsNull) { - var elements = new List(); - foreach (var init in arrayCreateExpression.Initializer.Elements) { - var rr = Resolve(init); - if (!rr.IsError) - elements.Add(rr); - } - TypeInference typeInference = new TypeInference(resolver.Context, new Conversions(resolver.Context)); - bool success; - IType elementType = typeInference.GetBestCommonType(elements, out success); - arrType = new ArrayType(elementType, 1); + return resolver.ResolveArrayCreation(null, dimensions, sizeArguments, initializerElements); } else { - arrType = ResolveType(arrayCreateExpression.Type); + IType elementType = ResolveType(arrayCreateExpression.Type); foreach (var spec in arrayCreateExpression.AdditionalArraySpecifiers.Reverse()) { - arrType = new ArrayType(arrType, spec.Dimensions); - } - // HACK: find a better way to represent this in the AST - if (arrayCreateExpression.Arguments.Count == 0) { - arrType = new ArrayType(arrType, 1); - } else { - arrType = new ArrayType(arrType, arrayCreateExpression.Arguments.Count); + elementType = new ArrayType(elementType, spec.Dimensions); } + return resolver.ResolveArrayCreation(elementType, dimensions, sizeArguments, initializerElements); } - return new ResolveResult (arrType); } public override ResolveResult VisitAsExpression(AsExpression asExpression, object data) @@ -925,6 +939,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return null; } + public override ResolveResult VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression, object data) + { + // Usually, the parent expression takes care of handling NamedArgumentExpressions + // by calling GetArguments(). + if (resolverEnabled) { + return Resolve(namedArgumentExpression.Expression); + } else { + Scan(namedArgumentExpression.Expression); + return null; + } + } + public override ResolveResult VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression, object data) { if (resolverEnabled) { @@ -1728,7 +1754,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver while (undecidedLambdas.Count > 0) { LambdaBase lambda = undecidedLambdas[0]; AstNode parent = lambda.LambdaExpression.Parent; - while (ActsAsParenthsizedExpression(parent)) + while (ActsAsParenthesizedExpression(parent)) parent = parent.Parent; CSharpResolver storedResolver; if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) { @@ -1753,9 +1779,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Gets whether the node acts as a parenthesized expression, /// that is, it directly returns /// - static bool ActsAsParenthsizedExpression(AstNode node) + static bool ActsAsParenthesizedExpression(AstNode node) { - return node is ParenthesizedExpression || node is CheckedExpression || node is UncheckedExpression; + return node is ParenthesizedExpression || node is CheckedExpression || node is UncheckedExpression + || node is NamedArgumentExpression; } #endregion @@ -2314,11 +2341,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return errorResult; } - public override ResolveResult VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression, object data) - { - throw new NotImplementedException(); - } - #region Token Nodes public override ResolveResult VisitIdentifier(Identifier identifier, object data) { diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index cacee1a729..0f742b91a0 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -103,6 +103,7 @@ +