diff --git a/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs b/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs index fdcc4d717c..fa3ca39144 100644 --- a/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs +++ b/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs @@ -721,7 +721,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis } DefiniteAssignmentStatus afterTrue = conditionalExpression.TrueExpression.AcceptVisitor(this, beforeTrue); - DefiniteAssignmentStatus afterFalse = conditionalExpression.TrueExpression.AcceptVisitor(this, beforeFalse); + DefiniteAssignmentStatus afterFalse = conditionalExpression.FalseExpression.AcceptVisitor(this, beforeFalse); return MergeStatus(CleanSpecialValues(afterTrue), CleanSpecialValues(afterFalse)); } } diff --git a/ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs b/ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs index b141ba0626..a48b924974 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs @@ -62,7 +62,7 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildrenByRole(MemberRole); } } - string[] conditionals = null; + IList conditionalSymbols = null; List errors = new List (); @@ -76,12 +76,12 @@ namespace ICSharpCode.NRefactory.CSharp /// the conditional symbols at the start of the first token in the file - including the ones defined /// in the source file. /// - public string[] Conditionals { + public IList ConditionalSymbols { get { - return conditionals ?? new string[0]; + return conditionalSymbols ?? EmptyList.Instance; } internal set { - conditionals = value; + conditionalSymbols = value; } } diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 9987259490..146eb09e71 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -41,7 +41,7 @@ TRACE;FULL_AST - none + PdbOnly full diff --git a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs index 9c72e7cf4b..440aadea6e 100644 --- a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs +++ b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs @@ -3469,6 +3469,73 @@ namespace ICSharpCode.NRefactory.CSharp return result; } #endregion + + #region XmlDoc + public DocumentationReference ConvertXmlDoc(DocumentationBuilder doc) + { + DocumentationReference result = new DocumentationReference(); + if (doc.ParsedName != null) { + if (doc.ParsedName.Name == "") { + result.EntityType = EntityType.Indexer; + } else { + result.MemberName = doc.ParsedName.Name; + } + if (doc.ParsedName.Left != null) { + result.DeclaringType = ConvertToType(doc.ParsedName.Left); + } else if (doc.ParsedBuiltinType != null) { + result.DeclaringType = ConvertToType(doc.ParsedBuiltinType); + } + if (doc.ParsedName.TypeParameters != null) { + for (int i = 0; i < doc.ParsedName.TypeParameters.Count; i++) { + result.TypeArguments.Add(ConvertToType(doc.ParsedName.TypeParameters[i])); + } + } + } else if (doc.ParsedBuiltinType != null) { + result.EntityType = EntityType.TypeDefinition; + result.DeclaringType = ConvertToType(doc.ParsedBuiltinType); + } + if (doc.ParsedParameters != null) { + result.HasParameterList = true; + result.Parameters.AddRange(doc.ParsedParameters.Select(ConvertXmlDocParameter)); + } + if (doc.ParsedOperator != null) { + result.EntityType = EntityType.Operator; + result.OperatorType = (OperatorType)doc.ParsedOperator; + if (result.OperatorType == OperatorType.Implicit || result.OperatorType == OperatorType.Explicit) { + var returnTypeParam = result.Parameters.LastOrNullObject(); + returnTypeParam.Remove(); // detach from parameter list + var returnType = returnTypeParam.Type; + returnType.Remove(); + result.ConversionOperatorReturnType = returnType; + } + if (result.Parameters.Count == 0) { + // reset HasParameterList if necessary + result.HasParameterList = false; + } + } + return result; + } + + ParameterDeclaration ConvertXmlDocParameter(DocumentationParameter p) + { + ParameterDeclaration result = new ParameterDeclaration(); + switch (p.Modifier) { + case Parameter.Modifier.OUT: + result.ParameterModifier = ParameterModifier.Out; + break; + case Parameter.Modifier.REF: + result.ParameterModifier = ParameterModifier.Ref; + break; + case Parameter.Modifier.PARAMS: + result.ParameterModifier = ParameterModifier.Params; + break; + } + if (p.Type != null) { + result.Type = ConvertToType(p.Type); + } + return result; + } + #endregion } public CSharpParser () @@ -3671,7 +3738,7 @@ namespace ICSharpCode.NRefactory.CSharp } conversionVisitor.Unit.FileName = fileName; - conversionVisitor.Unit.Conditionals = top.Conditionals.ToArray (); + conversionVisitor.Unit.ConditionalSymbols = top.Conditionals.ToArray (); return conversionVisitor.Unit; } @@ -3733,8 +3800,13 @@ namespace ICSharpCode.NRefactory.CSharp if (cu == null) return Enumerable.Empty (); var td = cu.Children.FirstOrDefault () as TypeDeclaration; - if (td != null) - return td.Members; + if (td != null) { + var members = td.Members.ToArray(); + // detach members from parent + foreach (var m in members) + m.Remove(); + return members; + } return Enumerable.Empty (); } @@ -3743,8 +3815,13 @@ namespace ICSharpCode.NRefactory.CSharp string code = "void M() { " + Environment.NewLine + reader.ReadToEnd () + "}"; var members = ParseTypeMembers (new StringReader (code), lineModifier - 1); var method = members.FirstOrDefault () as MethodDeclaration; - if (method != null && method.Body != null) - return method.Body.Statements; + if (method != null && method.Body != null) { + var statements = method.Body.Statements.ToArray(); + // detach statements from parent + foreach (var st in statements) + st.Remove(); + return statements; + } return Enumerable.Empty (); } @@ -3753,8 +3830,11 @@ namespace ICSharpCode.NRefactory.CSharp string code = reader.ReadToEnd () + " a;"; var members = ParseTypeMembers (new StringReader (code)); var field = members.FirstOrDefault () as FieldDeclaration; - if (field != null) - return field.ReturnType; + if (field != null) { + AstType type = field.ReturnType; + type.Remove(); + return type; + } return AstType.Null; } @@ -3763,8 +3843,11 @@ namespace ICSharpCode.NRefactory.CSharp var es = ParseStatements (new StringReader ("tmp = " + Environment.NewLine + reader.ReadToEnd () + ";"), -1).FirstOrDefault () as ExpressionStatement; if (es != null) { AssignmentExpression ae = es.Expression as AssignmentExpression; - if (ae != null) - return ae.Right; + if (ae != null) { + Expression expr = ae.Right; + expr.Remove(); + return expr; + } } return Expression.Null; } @@ -3780,12 +3863,39 @@ namespace ICSharpCode.NRefactory.CSharp public DocumentationReference ParseDocumentationReference (string cref) { + // see Mono.CSharp.DocumentationBuilder.HandleXrefCommon if (cref == null) throw new ArgumentNullException ("cref"); + + // Additional symbols for < and > are allowed for easier XML typing cref = cref.Replace ('{', '<').Replace ('}', '>'); - // TODO: add support for parsing cref attributes - // (documentation_parsing production, see DocumentationBuilder.HandleXrefCommon) - throw new NotImplementedException (); + + lock (parseLock) { + errorReportPrinter = new ErrorReportPrinter(""); + var ctx = new CompilerContext(compilerSettings.ToMono(), errorReportPrinter); + ctx.Settings.TabSize = 1; + var stream = new MemoryStream(Encoding.Unicode.GetBytes(cref)); + var reader = new SeekableStreamReader(stream, Encoding.Unicode); + var file = new SourceFile("", "", 0); + Location.Initialize(new List (new [] { file })); + var module = new ModuleContainer(ctx); + module.DocumentationBuilder = new DocumentationBuilder(); + var source_file = new CompilationSourceFile (module); + var report = new Report (ctx, errorReportPrinter); + var parser = new Mono.CSharp.CSharpParser (reader, source_file, report); + parser.Lexer.putback_char = Tokenizer.DocumentationXref; + parser.Lexer.parsing_generic_declaration_doc = true; + parser.parse (); + if (report.Errors > 0) { +// Report.Warning (1584, 1, mc.Location, "XML comment on `{0}' has syntactically incorrect cref attribute `{1}'", +// mc.GetSignatureForError (), cref); + } + + ConversionVisitor conversionVisitor = new ConversionVisitor (false, parser.LocationsBag); + DocumentationReference docRef = conversionVisitor.ConvertXmlDoc(module.DocumentationBuilder); + CompilerCallableEntryPoint.Reset(); + return docRef; + } } } } diff --git a/ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs b/ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs index e988178c43..683e4c292b 100644 --- a/ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs +++ b/ICSharpCode.NRefactory.CSharp/Parser/mcs/doc.cs @@ -56,6 +56,11 @@ namespace Mono.CSharp XmlDocumentation = new XmlDocument (); XmlDocumentation.PreserveWhitespace = false; } + + internal DocumentationBuilder() + { + // for NRefactory CSharpParser.ParseDocumentationReference + } Report Report { get { diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs index a22011fb7f..d45ba6c7ca 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs @@ -471,7 +471,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver bool IdentityOrVarianceConversion(IType s, IType t, int subtypeCheckNestingDepth) { ITypeDefinition def = s.GetDefinition(); - if (def != null && def.Equals(t.GetDefinition())) { + if (def != null) { + if (!def.Equals(t.GetDefinition())) + return false; ParameterizedType ps = s as ParameterizedType; ParameterizedType pt = t as ParameterizedType; if (ps != null && pt != null) { @@ -499,8 +501,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return false; // only of of them is parameterized, or counts don't match? -> not valid conversion } return true; + } else { + // not type definitions? we still need to check for equal types (e.g. s and t might be type parameters) + return s.Equals(t); } - return false; } #endregion diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index cc0ba36f0d..20d34852fb 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -1900,15 +1900,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver // C# 4.0 spec: §7.6.5 if (target.Type.Kind == TypeKind.Dynamic) { - return new DynamicInvocationResolveResult(target, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly()); + return new DynamicInvocationResolveResult(target, DynamicInvocationType.Invocation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly()); } MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; if (mgrr != null) { + if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) { + // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable method. + var or2 = CreateOverloadResolution(arguments, argumentNames, mgrr.TypeArguments.ToArray()); + var applicableMethods = mgrr.MethodsGroupedByDeclaringType.SelectMany(m => m, (x, m) => new { x.DeclaringType, Method = m }).Where(x => OverloadResolution.IsApplicable(or2.AddCandidate(x.Method))).ToList(); + + if (applicableMethods.Count > 1) { + ResolveResult actualTarget; + if (applicableMethods.All(x => x.Method.IsStatic) && !(mgrr.TargetResult is TypeResolveResult)) + actualTarget = new TypeResolveResult(mgrr.TargetType); + else + actualTarget = mgrr.TargetResult; + + var l = new List(); + foreach (var m in applicableMethods) { + if (l.Count == 0 || l[l.Count - 1].DeclaringType != m.DeclaringType) + l.Add(new MethodListWithDeclaringType(m.DeclaringType)); + l[l.Count - 1].Add(m.Method); + } + return new DynamicInvocationResolveResult(new MethodGroupResolveResult(actualTarget, mgrr.MethodName, l, mgrr.TypeArguments), DynamicInvocationType.Invocation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly()); + } + } + OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, checkForOverflow: checkForOverflow, conversions: conversions); if (or.BestCandidate != null) { if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeResolveResult)) - return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetResult.Type)); + return or.CreateResolveResult(new TypeResolveResult(mgrr.TargetType)); else return or.CreateResolveResult(mgrr.TargetResult); } else { @@ -2043,10 +2065,7 @@ 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], SpecialType.Dynamic); - } - return new ArrayAccessResolveResult(SpecialType.Dynamic, target, arguments); + return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly()); case TypeKind.Array: case TypeKind.Pointer: @@ -2056,9 +2075,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // §7.6.6.2 Indexer access - OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); + MemberLookup lookup = CreateMemberLookup(); var indexers = lookup.LookupIndexers(target.Type); + + if (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic)) { + // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable indexer. + var or2 = CreateOverloadResolution(arguments, argumentNames, null); + var applicableIndexers = indexers.SelectMany(x => x).Where(m => OverloadResolution.IsApplicable(or2.AddCandidate(m))).ToList(); + + if (applicableIndexers.Count > 1) { + return new DynamicInvocationResolveResult(target, DynamicInvocationType.Indexing, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly()); + } + } + + OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); or.AddMethodLists(indexers); if (or.BestCandidate != null) { return or.CreateResolveResult(target); @@ -2109,16 +2140,35 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList initializerStatements = null) { if (type.Kind == TypeKind.Delegate && arguments.Length == 1) { - return Convert(arguments[0], type); + ResolveResult input = arguments[0]; + IMethod invoke = input.Type.GetDelegateInvokeMethod(); + if (invoke != null) { + input = new MethodGroupResolveResult( + input, invoke.Name, + methods: new[] { new MethodListWithDeclaringType(invoke.DeclaringType) { invoke } }, + typeArguments: EmptyList.Instance + ); + } + return Convert(input, type); } OverloadResolution or = CreateOverloadResolution(arguments, argumentNames); MemberLookup lookup = CreateMemberLookup(); + var allApplicable = (arguments.Any(a => a.Type.Kind == TypeKind.Dynamic) ? new List() : null); foreach (IMethod ctor in type.GetConstructors()) { - if (lookup.IsAccessible(ctor, allowProtectedAccess)) - or.AddCandidate(ctor); + if (lookup.IsAccessible(ctor, allowProtectedAccess)) { + var orErrors = or.AddCandidate(ctor); + if (allApplicable != null && OverloadResolution.IsApplicable(orErrors)) + allApplicable.Add(ctor); + } else or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible); } + + if (allApplicable != null && allApplicable.Count > 1) { + // If we have dynamic arguments, we need to represent the invocation as a dynamic invocation if there is more than one applicable constructor. + return new DynamicInvocationResolveResult(new MethodGroupResolveResult(null, allApplicable[0].Name, new[] { new MethodListWithDeclaringType(type, allApplicable) }, null), DynamicInvocationType.ObjectCreation, arguments.Select((a, i) => new DynamicInvocationArgument(argumentNames != null ? argumentNames[i] : null, a)).ToList().AsReadOnly(), initializerStatements); + } + if (or.BestCandidate != null) { return or.CreateResolveResult(null, initializerStatements); } else { diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs b/ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs index 6139be02c0..b720d68b74 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/DynamicInvocationResolveResult.cs @@ -45,24 +45,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } + public enum DynamicInvocationType { + /// + /// The invocation is a normal invocation ( 'a(b)' ). + /// + Invocation, + + /// + /// The invocation is an indexing ( 'a[b]' ). + /// + Indexing, + + /// + /// The invocation is an object creation ( 'new a(b)' ). Also used when invoking a base constructor ( ' : base(a) ' ) and chaining constructors ( ' : this(a) '). + /// + ObjectCreation, + } + /// /// Represents the result of an invocation of a member of a dynamic object. /// public class DynamicInvocationResolveResult : ResolveResult { /// - /// Target of the invocation (a dynamic object). + /// Target of the invocation. Can be a dynamic expression or a . /// public readonly ResolveResult Target; + /// + /// Type of the invocation. + /// + public readonly DynamicInvocationType InvocationType; + /// /// Arguments for the call. /// public readonly IList Arguments; - public DynamicInvocationResolveResult(ResolveResult target, IList arguments) : base(SpecialType.Dynamic) { - this.Target = target; - this.Arguments = arguments ?? EmptyList.Instance; + /// + /// Gets the list of initializer statements that are appplied to the result of this invocation. + /// This is used to represent object and collection initializers. + /// With the initializer statements, the is used + /// to refer to the result of this invocation. + /// Initializer statements can only exist if the is . + /// + public readonly IList InitializerStatements; + + public DynamicInvocationResolveResult(ResolveResult target, DynamicInvocationType invocationType, IList arguments, IList initializerStatements = null) : base(SpecialType.Dynamic) { + this.Target = target; + this.InvocationType = invocationType; + this.Arguments = arguments ?? EmptyList.Instance; + this.InitializerStatements = initializerStatements ?? EmptyList.Instance; } public override string ToString() diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs index 57c748f3c8..39571f2918 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs @@ -29,10 +29,32 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; namespace ICSharpCode.NRefactory.CSharp.Resolver { + /// + /// A method list that belongs to a declaring type. + /// public class MethodListWithDeclaringType : List { readonly IType declaringType; + /// + /// The declaring type. + /// + /// + /// Not all methods in this list necessarily have this as their declaring type. + /// For example, this program: + /// + /// class Base { + /// public virtual void M() {} + /// } + /// class Derived : Base { + /// public override void M() {} + /// public void M(int i) {} + /// } + /// + /// results in two lists: + /// new MethodListWithDeclaringType(Base) { Derived.M() }, + /// new MethodListWithDeclaringType(Derived) { Derived.M(int) } + /// public IType DeclaringType { get { return declaringType; } } @@ -64,8 +86,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList methods, IList typeArguments) : base(SpecialType.UnknownType) { - if (targetResult == null) - throw new ArgumentNullException("targetResult"); if (methods == null) throw new ArgumentNullException("methods"); this.targetResult = targetResult; @@ -85,7 +105,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Gets the type of the reference to the target object. /// public IType TargetType { - get { return targetResult.Type; } + get { return targetResult != null ? targetResult.Type : SpecialType.UnknownType; } } /// diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index f160fcbc60..bf8331d7d8 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -938,6 +938,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver ScanChildren(parameterDeclaration); if (resolverEnabled) { string name = parameterDeclaration.Name; + + if (parameterDeclaration.Parent is DocumentationReference) { + // create a dummy parameter + IType type = ResolveType(parameterDeclaration.Type); + switch (parameterDeclaration.ParameterModifier) { + case ParameterModifier.Ref: + case ParameterModifier.Out: + type = new ByReferenceType(type); + break; + } + return new LocalResolveResult(new DefaultParameter( + type, name, + isRef: parameterDeclaration.ParameterModifier == ParameterModifier.Ref, + isOut: parameterDeclaration.ParameterModifier == ParameterModifier.Out, + isParams: parameterDeclaration.ParameterModifier == ParameterModifier.Params)); + } + // Look in lambda parameters: foreach (IParameter p in resolver.LocalVariables.OfType()) { if (p.Name == name) @@ -1479,12 +1496,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames, false, initializerStatements); if (arguments.Length == 1 && rr.Type.Kind == TypeKind.Delegate) { - // process conversion in case it's a delegate creation - ProcessConversionResult(objectCreateExpression.Arguments.Single(), rr as ConversionResolveResult); - // wrap the result so that the delegate creation is not handled as a reference - // to the target method - otherwise FindReferencedEntities would produce two results for - // the same delegate creation. - return WrapResult(rr); + // Apply conversion to argument if it directly wraps the argument + // (but not when creating a delegate from a delegate, as then there would be a MGRR for .Invoke in between) + // This is necessary for lambda type inference. + var crr = rr as ConversionResolveResult; + if (crr != null && crr.Input == arguments[0]) { + ProcessConversionResult(objectCreateExpression.Arguments.Single(), crr); + + // wrap the result so that the delegate creation is not handled as a reference + // to the target method - otherwise FindReferencedEntities would produce two results for + // the same delegate creation. + return WrapResult(rr); + } else { + return rr; + } } else { // process conversions in all other cases ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as CSharpInvocationResolveResult); @@ -3847,7 +3872,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #region Documentation Reference ResolveResult IAstVisitor.VisitDocumentationReference(DocumentationReference documentationReference) { - throw new NotImplementedException(); + // Resolve child nodes: + ITypeDefinition declaringTypeDef; + if (documentationReference.DeclaringType.IsNull) + declaringTypeDef = resolver.CurrentTypeDefinition; + else + declaringTypeDef = ResolveType(documentationReference.DeclaringType).GetDefinition(); + IType[] typeArguments = documentationReference.TypeArguments.Select(ResolveType).ToArray(); + IType conversionOperatorReturnType = ResolveType(documentationReference.ConversionOperatorReturnType); + IParameter[] parameters = documentationReference.Parameters.Select(ResolveXmlDocParameter).ToArray(); + + if (documentationReference.EntityType == EntityType.TypeDefinition) { + if (declaringTypeDef != null) + return new TypeResolveResult(declaringTypeDef); + else + return errorResult; + } + + if (documentationReference.EntityType == EntityType.None) { + // might be a type, member or ctor + string memberName = documentationReference.MemberName; + ResolveResult rr; + if (documentationReference.DeclaringType.IsNull) { + rr = resolver.LookupSimpleNameOrTypeName(memberName, typeArguments, NameLookupMode.Expression); + } else { + var target = Resolve(documentationReference.DeclaringType); + rr = resolver.ResolveMemberAccess(target, memberName, typeArguments); + } + // reduce to definition: + if (rr.IsError) { + return rr; + } else if (rr is TypeResolveResult) { + var typeDef = rr.Type.GetDefinition(); + if (typeDef == null) + return errorResult; + if (documentationReference.HasParameterList) { + var ctors = typeDef.GetConstructors(options: GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions); + return FindByParameters(ctors, parameters); + } else { + return new TypeResolveResult(typeDef); + } + } else if (rr is MemberResolveResult) { + var mrr = (MemberResolveResult)rr; + return new MemberResolveResult(null, mrr.Member.MemberDefinition); + } else if (rr is MethodGroupResolveResult) { + var mgrr = (MethodGroupResolveResult)rr; + var methods = mgrr.MethodsGroupedByDeclaringType.Reverse() + .SelectMany(ml => ml.Select(m => (IParameterizedMember)m.MemberDefinition)); + return FindByParameters(methods, parameters); + } + return rr; + } + + // Indexer or operator + if (declaringTypeDef == null) + return errorResult; + if (documentationReference.EntityType == EntityType.Indexer) { + var indexers = declaringTypeDef.Properties.Where(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation); + return FindByParameters(indexers, parameters); + } else if (documentationReference.EntityType == EntityType.Operator) { + var opType = documentationReference.OperatorType; + string memberName = OperatorDeclaration.GetName(opType); + var methods = declaringTypeDef.Methods.Where(m => m.IsOperator && m.Name == memberName); + if (opType == OperatorType.Implicit || opType == OperatorType.Explicit) { + // conversion operator + foreach (var method in methods) { + if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) { + if (method.ReturnType.Equals(conversionOperatorReturnType)) + return new MemberResolveResult(null, method); + } + } + return new MemberResolveResult(null, methods.FirstOrDefault()); + } else { + // not a conversion operator + return FindByParameters(methods, parameters); + } + } else { + throw new NotSupportedException(); // unknown entity type + } + } + + IParameter ResolveXmlDocParameter(ParameterDeclaration p) + { + var lrr = Resolve(p) as LocalResolveResult; + if (lrr != null && lrr.IsParameter) + return (IParameter)lrr.Variable; + else + return new DefaultParameter(SpecialType.UnknownType, string.Empty); + } + + ResolveResult FindByParameters(IEnumerable methods, IList parameters) + { + foreach (var method in methods) { + if (ParameterListComparer.Instance.Equals(method.Parameters, parameters)) + return new MemberResolveResult(null, method); + } + return new MemberResolveResult(null, methods.FirstOrDefault()); } #endregion } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs index 5ca58078cb..d831eea509 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs @@ -17,8 +17,10 @@ // DEALINGS IN THE SOFTWARE. using System; +using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Documentation; using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -38,6 +40,23 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem // resolve ID string return base.ResolveCref(cref); } + var documentationReference = new CSharpParser().ParseDocumentationReference(cref); + var csharpContext = context as CSharpTypeResolveContext; + CSharpResolver resolver; + if (csharpContext != null) { + resolver = new CSharpResolver(csharpContext); + } else { + resolver = new CSharpResolver(context.Compilation); + } + var astResolver = new CSharpAstResolver(resolver, documentationReference); + var rr = astResolver.Resolve(documentationReference); + + MemberResolveResult mrr = rr as MemberResolveResult; + if (mrr != null) + return mrr.Member; + TypeResolveResult trr = rr as TypeResolveResult; + if (trr != null) + return trr.Type.GetDefinition(); return null; } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs index 8d077fdb13..19af6d7310 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Analysis/DefiniteAssignmentTests.cs @@ -17,9 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.IO; using System.Linq; using System.Threading; - using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -289,5 +289,41 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusBefore(case2.Statements.First())); Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(@switch)); } + + [Test] + public void ConditionalExpression1() + { + string code = "int a; int b = X ? (a = 1) : 0;"; + var block = new BlockStatement(); + block.Statements.AddRange(new CSharpParser().ParseStatements(new StringReader(code))); + + DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); + da.Analyze("a"); + Assert.AreEqual(DefiniteAssignmentStatus.PotentiallyAssigned, da.GetStatusAfter(block)); + } + + [Test] + public void ConditionalExpression2() + { + string code = "int a; int b = X ? (a = 1) : (a = 2);"; + var block = new BlockStatement(); + block.Statements.AddRange(new CSharpParser().ParseStatements(new StringReader(code))); + + DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); + da.Analyze("a"); + Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(block)); + } + + [Test] + public void ConditionalExpression3() + { + string code = "int a; int b = true ? (a = 1) : 0;"; + var block = new BlockStatement(); + block.Statements.AddRange(new CSharpParser().ParseStatements(new StringReader(code))); + + DefiniteAssignmentAnalysis da = CreateDefiniteAssignmentAnalysis(block); + da.Analyze("a"); + Assert.AreEqual(DefiniteAssignmentStatus.DefinitelyAssigned, da.GetStatusAfter(block)); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs index 41a5a68fa4..74579ddce9 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs @@ -18,6 +18,7 @@ using System; using System.Linq; +using System.Text; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression @@ -234,5 +235,19 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression Assert.AreEqual(new TextLocation(1, 2), pe.EndLocation); Assert.AreEqual("0", pe.LiteralValue); } + + [Test] + [Ignore("Mono parser crash")] + public void LargeVerbatimString() + { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < 10000; i++) { + b.Append(i.ToString()); + b.Append("\r\n"); + } + string literal = b.ToString(); + var pe = ParseUtilCSharp.ParseExpression("@\"" + literal + "\""); + Assert.AreEqual(literal, pe.Value); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs index cdf8e1cd09..5cced86459 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs @@ -205,5 +205,19 @@ public class Form1 { typeof(NamespaceDeclaration) }, cu.Children.Select(c => c.GetType()).ToArray()); } + + [Ignore("Fixme!")] + [Test] + public void AssemblyAttributeBeforeClass() + { + var cu = new CSharpParser().Parse(new StringReader("using System; [assembly: Attr] class X {}"), "code.cs"); + Assert.AreEqual( + new Type[] { + typeof(UsingDeclaration), + typeof(AttributeSection), + typeof(TypeDeclaration) + }, cu.Children.Select(c => c.GetType()).ToArray()); + Assert.That(((TypeDeclaration)cu.LastChild).Attributes, Is.Empty); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs index 21074279f7..28b522fc6c 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs @@ -132,5 +132,118 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual(PreProcessorDirectiveType.Pragma, ppd.Type); Assert.AreEqual("warning disable 809", ppd.Argument); } + + const string elifProgram = @" +#if AAA +class A { } +#elif BBB +class B { } +#endif"; + + [Test] + [Ignore("parser bug (missing comment node)")] + public void ElifBothFalse() + { + CSharpParser parser = new CSharpParser(); + var cu = parser.Parse(elifProgram, "elif.cs"); + Assert.IsFalse(parser.HasErrors); + + Assert.AreEqual(new Role[] { + Roles.PreProcessorDirective, + Roles.Comment, + Roles.PreProcessorDirective, + Roles.Comment, + Roles.PreProcessorDirective + }, cu.Children.Select(c => c.Role).ToArray()); + var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0); + Assert.IsFalse(aaa.Take); + Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type); + Assert.AreEqual("AAA", aaa.Argument); + + var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1); + Assert.IsFalse(bbb.Take); + Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type); + Assert.AreEqual("BBB", bbb.Argument); + } + + [Test] + [Ignore("parser bug (bbb.Take is true, should be false)")] + public void ElifBothTrue() + { + CSharpParser parser = new CSharpParser(); + parser.CompilerSettings.ConditionalSymbols.Add("AAA"); + var cu = parser.Parse(elifProgram, "elif.cs"); + Assert.IsFalse(parser.HasErrors); + + Assert.AreEqual(new Role[] { + Roles.PreProcessorDirective, + NamespaceDeclaration.MemberRole, + Roles.PreProcessorDirective, + Roles.Comment, + Roles.PreProcessorDirective + }, cu.Children.Select(c => c.Role).ToArray()); + var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0); + Assert.IsTrue(aaa.Take); + Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type); + Assert.AreEqual("AAA", aaa.Argument); + + var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1); + Assert.IsFalse(bbb.Take); + Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type); + Assert.AreEqual("BBB", bbb.Argument); + } + + [Test] + [Ignore("parser bug (bbb.Take is true, should be false)")] + public void ElifFirstTaken() + { + CSharpParser parser = new CSharpParser(); + parser.CompilerSettings.ConditionalSymbols.Add("AAA"); + var cu = parser.Parse(elifProgram, "elif.cs"); + Assert.IsFalse(parser.HasErrors); + + Assert.AreEqual(new Role[] { + Roles.PreProcessorDirective, + NamespaceDeclaration.MemberRole, + Roles.PreProcessorDirective, + Roles.Comment, + Roles.PreProcessorDirective + }, cu.Children.Select(c => c.Role).ToArray()); + var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0); + Assert.IsTrue(aaa.Take); + Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type); + Assert.AreEqual("AAA", aaa.Argument); + + var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1); + Assert.IsFalse(bbb.Take); + Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type); + Assert.AreEqual("BBB", bbb.Argument); + } + + [Test] + public void ElifSecondTaken() + { + CSharpParser parser = new CSharpParser(); + parser.CompilerSettings.ConditionalSymbols.Add("BBB"); + var cu = parser.Parse(elifProgram, "elif.cs"); + Assert.IsFalse(parser.HasErrors); + + Assert.AreEqual(new Role[] { + Roles.PreProcessorDirective, + Roles.Comment, + Roles.PreProcessorDirective, + NamespaceDeclaration.MemberRole, + Roles.PreProcessorDirective + }, cu.Children.Select(c => c.Role).ToArray()); + var aaa = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(0); + Assert.IsFalse(aaa.Take); + Assert.AreEqual(PreProcessorDirectiveType.If, aaa.Type); + Assert.AreEqual("AAA", aaa.Argument); + + var bbb = cu.GetChildrenByRole(Roles.PreProcessorDirective).ElementAt(1); + Assert.IsTrue(bbb.Take); + Assert.AreEqual(PreProcessorDirectiveType.Elif, bbb.Type); + Assert.AreEqual("BBB", bbb.Argument); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs index e422edd811..6bfc82c647 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs @@ -524,7 +524,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } [Test] - public void ExplicitUserDefinedConversion() { + public void ExplicitUserDefinedConversion() + { var rr = Resolve(@" class C1 {} class C2 { @@ -541,5 +542,29 @@ class C { Assert.IsTrue(rr.Conversion.IsUserDefined); Assert.AreEqual("op_Explicit", rr.Conversion.Method.Name); } + + [Test] + public void ImplicitTypeParameterConversion() + { + string program = @"using System; +class Test { + public void M(T t) where T : U { + U u = $t$; + } +}"; + Assert.AreEqual(C.BoxingConversion, GetConversion(program)); + } + + [Test] + public void InvalidImplicitTypeParameterConversion() + { + string program = @"using System; +class Test { + public void M(T t) where U : T { + U u = $t$; + } +}"; + Assert.AreEqual(C.None, GetConversion(program)); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs index 088064320c..1c02f6c114 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/DynamicTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Text; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; @@ -37,6 +38,7 @@ class TestClass { }"; var rr = Resolve(program); Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); Assert.That(rr.Target, Is.InstanceOf()); var dynamicMember = (DynamicMemberResolveResult)rr.Target; Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj"); @@ -61,6 +63,7 @@ class TestClass { }"; var rr = Resolve(program); Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); Assert.That(rr.Target, Is.InstanceOf()); var dynamicMember = (DynamicMemberResolveResult)rr.Target; Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj"); @@ -86,12 +89,14 @@ class TestClass { }"; var rr = Resolve(program); Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); Assert.That(rr.Target, Is.InstanceOf()); var innerInvocation = (DynamicInvocationResolveResult)rr.Target; Assert.That(innerInvocation.Target, Is.InstanceOf()); var dynamicMember = (DynamicMemberResolveResult)innerInvocation.Target; Assert.That(dynamicMember.Target is LocalResolveResult && ((LocalResolveResult)dynamicMember.Target).Variable.Name == "obj"); Assert.That(dynamicMember.Member, Is.EqualTo("SomeMethod")); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); Assert.That(innerInvocation.Arguments.Count, Is.EqualTo(1)); Assert.That(innerInvocation.Arguments[0].Name, Is.Null); Assert.That(innerInvocation.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)innerInvocation.Arguments[0].Value).Variable.Name == "a"); @@ -99,5 +104,612 @@ class TestClass { Assert.That(rr.Arguments[0].Name, Is.Null); Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "b"); } + + [Test] + public void InvocationWithDynamicArgumentWithOneApplicableMethod() { + string program = @"using System; +class TestClass { + public void SomeMethod(int a) {} + public void SomeMethod(int a, string b) {} + + void F() { + dynamic obj = null; + var x = $this.SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod")); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Conversion.IsImplicit, Is.True); + Assert.That(cr.Conversion.IsDynamicConversion, Is.True); + Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj"); + } + + [Test] + public void InvocationWithDynamicArgumentWhenBothAnOwnAndABaseMethodAreApplicable() { + string program = @"using System; +class TestBase { + public void SomeMethod(int a) {} +} + +class TestClass : TestBase { + public void SomeMethod(string a) {} + public void SomeMethod(string a, int b) {} + + void F() { + dynamic obj = null; + var x = $this.SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.InstanceOf()); + Assert.That(mg.MethodName, Is.EqualTo("SomeMethod")); + Assert.That(mg.Methods.Count(), Is.EqualTo(2)); + Assert.That(mg.Methods.Any(m => m.Parameters.Count == 1 && m.DeclaringType.Name == "TestBase" && m.Name == "SomeMethod" && m.Parameters[0].Type.Name == "Int32")); + Assert.That(mg.Methods.Any(m => m.Parameters.Count == 1 && m.DeclaringType.Name == "TestClass" && m.Name == "SomeMethod" && m.Parameters[0].Type.Name == "String")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + } + + [Test, Ignore("Fails")] + public void InvocationWithDynamicArgumentWhenABaseMethodIsShadowed() { + string program = @"using System; +class TestBase { + public void SomeMethod(int a) {} +} + +class TestClass : TestBase { + public void SomeMethod(int a) {} + public void SomeMethod(string a, int b) {} + + void F() { + dynamic obj = null; + var x = $this.SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Member.Name, Is.EqualTo("SomeMethod")); + Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestClass")); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Conversion.IsImplicit, Is.True); + Assert.That(cr.Conversion.IsDynamicConversion, Is.True); + Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj"); + } + + [Test] + public void InvocationWithDynamicArgumentWithTwoApplicableMethods() { + string program = @"using System; +class TestClass { + public void SomeMethod(int a) {} + public void SomeMethod(string a) {} + public void SomeMethod(int a, string b) {} + + void F() { + dynamic obj = null; + var x = $SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.InstanceOf()); + Assert.That(mg.MethodName, Is.EqualTo("SomeMethod")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 1)); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + } + + [Test] + public void InvocationWithDynamicArgumentWithTwoApplicableStaticMethods() { + string program = @"using System; +class TestClass { + public static void SomeMethod(int a) {} + public static void SomeMethod(string a) {} + public static void SomeMethod(int a, string b) {} + + void F() { + dynamic obj = null; + var x = $SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.InstanceOf()); + Assert.That(mg.MethodName, Is.EqualTo("SomeMethod")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 1)); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + } + + [Test] + public void InvocationWithDynamicArgumentWithApplicableStaticAndNonStaticMethodsFavorTheNonStaticOne() { + string program = @"using System; +class TestClass { + public static void SomeMethod(int a) {} + public void SomeMethod(string a) {} + public static void SomeMethod(int a, string b) {} + + void F() { + dynamic obj = null; + var x = $SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.InstanceOf()); + Assert.That(mg.MethodName, Is.EqualTo("SomeMethod")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 1)); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + } + + [Test] + public void InvocationWithDynamicArgumentWhenTheOnlyApplicableMethodIsAnExtensionMethod() { + string program = @"using System; +static class OtherClass { + public void SomeMethod(this TestClass x, int a) {} + public void SomeMethod(this TestClass x, string a) {} + public void SomeMethod(this TestClass x, int a, string b) {} +} +class TestClass { + void F() { + dynamic obj = null; + var x = $this.SomeMethod(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.IsError, Is.True); + } + + [Test] + public void InvocationWithDynamicArgumentWithTwoApplicableMethodsAndNamedArguments() { + string program = @"using System; +class TestClass { + public void SomeMethod(int a, int i) {} + public void SomeMethod(string a, int i) {} + public void SomeMethod(int a, string b, int i) {} + + void F() { + dynamic obj = null; + int idx = 0; + var x = $this.SomeMethod(a: obj, i: idx)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Invocation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.InstanceOf()); + Assert.That(mg.MethodName, Is.EqualTo("SomeMethod")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 2) && mg.Methods.All(m => m.Parameters[1].Type.Name == "Int32")); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == "SomeMethod" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Name, Is.EqualTo("a")); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + Assert.That(rr.Arguments[1].Name, Is.EqualTo("i")); + Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "idx"); + } + + [Test] + public void IndexingDynamicObjectWithUnnamedArguments() { + string program = @"using System; +class TestClass { + void F() { + dynamic obj = null; + int a = 0, b = 0; + object o = $obj[a]$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing)); + Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj"); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Name, Is.Null); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a"); + } + + [Test] + public void IndexingDynamicObjectWithNamedArguments() { + string program = @"using System; +class TestClass { + void F() { + dynamic obj = null; + int a = 0, b = 0; + $obj[arg1: a, arg2: b]$ = 1; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing)); + Assert.That(rr.Target is LocalResolveResult && ((LocalResolveResult)rr.Target).Variable.Name == "obj"); + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Name, Is.EqualTo("arg1")); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "a"); + Assert.That(rr.Arguments[1].Name, Is.EqualTo("arg2")); + Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "b"); + } + + [Test] + public void IndexingWithDynamicArgumentWithOneApplicableIndexer() { + string program = @"using System; +class TestClass { + public int this[int a] { get { return 0; } } + public int this[int a, string b] { get { return 0; } } + + void F() { + dynamic obj = null; + var x = $this[obj]$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Member.Name, Is.EqualTo("Item")); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Conversion.IsImplicit, Is.True); + Assert.That(cr.Conversion.IsDynamicConversion, Is.True); + Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj"); + } + + [Test] + public void IndexingWithDynamicArgumentWithTwoApplicableIndexersAndUnnamedArguments() { + string program = @"using System; +class TestClass { + public int this[int a] { get { return 0; } } + public int this[string a] { get { return 0; } } + void F() { + dynamic obj = null; + var x = $this[obj]$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing)); + Assert.That(rr.Target, Is.InstanceOf()); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Name, Is.Null); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + } + + [Test] + public void IndexingWithDynamicArgumentWithAnApplicableBaseIndexer() { + string program = @"using System; +class TestBase { + public int this[int a] { get { return 0; } } +} + +class TestClass : TestBase { + public int this[string a] { get { return 0; } } + public int this[string a, int b] { get { return 0; } } + void F() { + dynamic obj = null; + var x = $this[obj]$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing)); + Assert.That(rr.Target, Is.InstanceOf()); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments[0].Name, Is.Null); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + } + + [Test, Ignore("Fails")] + public void IndexingWithDynamicArgumentWithTheOnlyApplicableIndexerShadowingABaseIndexer() { + string program = @"using System; +class TestBase { + public int this[int a] { get { return 0; } } +} + +class TestClass : TestBase { + public new int this[int a] { get { return 0; } } + public int this[int a, string b] { get { return 0; } } + + void F() { + dynamic obj = null; + var x = $this[obj]$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Member.Name, Is.EqualTo("Item")); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Conversion.IsImplicit, Is.True); + Assert.That(cr.Conversion.IsDynamicConversion, Is.True); + Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj"); + } + + [Test] + public void IndexingWithDynamicArgumentWithTwoApplicableIndexersAndNamedArguments() { + string program = @"using System; +class TestClass { + public int this[int a, int i] { get { return 0; } } + public int this[string a, int i] { get { return 0; } } + void F() { + dynamic obj = null; + int idx = 0; + var x = $this[a: obj, i: idx]$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Type.Kind, Is.EqualTo(TypeKind.Dynamic)); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.Indexing)); + Assert.That(rr.Target, Is.InstanceOf()); + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Name, Is.EqualTo("a")); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + Assert.That(rr.Arguments[1].Name, Is.EqualTo("i")); + Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "idx"); + } + + [Test] + public void ConstructingObjectWithDynamicArgumentWithOneApplicableConstructor() { + string program = @"using System; +class TestClass { + public TestClass(int a) {} + public void TestClass(int a, string b) {} + + void F() { + dynamic obj = null; + var x = $new TestClass(obj)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.Member.Name, Is.EqualTo(".ctor")); + Assert.That(rr.TargetResult, Is.Null); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(1)); + Assert.That(rr.Arguments.Count, Is.EqualTo(1)); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Input is LocalResolveResult && ((LocalResolveResult)cr.Input).Variable.Name == "obj"); + } + + [Test] + public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructors() { + string program = @"using System; +class TestClass { + public TestClass(int a, int b) {} + public TestClass(string a, int b) {} + public void TestClass(int a, string b) {} + + void F() { + dynamic obj = null; + int i = 0; + var x = $new TestClass(obj, i)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.Null); + Assert.That(mg.MethodName, Is.EqualTo(".ctor")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32")); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "i"); + } + + [Test] + public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructorsAndNamedArguments() { + string program = @"using System; +class TestClass { + public TestClass(int arg1, int arg2) {} + public TestClass(string arg1, int arg2) {} + public void TestClass(int a) {} + + void F() { + dynamic obj = null; + int i = 0; + var x = $new TestClass(arg1: obj, arg2: i)$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.Null); + Assert.That(mg.MethodName, Is.EqualTo(".ctor")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32")); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Name, Is.EqualTo("arg1")); + Assert.That(rr.Arguments[0].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[0].Value).Variable.Name == "obj"); + Assert.That(rr.Arguments[1].Name, Is.EqualTo("arg2")); + Assert.That(rr.Arguments[1].Value is LocalResolveResult && ((LocalResolveResult)rr.Arguments[1].Value).Variable.Name == "i"); + } + + [Test] + public void ConstructingObjectWithDynamicArgumentWithTwoApplicableConstructorsAndInitializerStatements() { + string program = @"using System; +class TestClass { + public TestClass(int a, int b) {} + public TestClass(string a, int b) {} + + public int A { get; set; } + + void F() { + dynamic obj = null; + int i = 0; + int j = 0; + var x = $new TestClass(obj, i) { A = j }$; + } +}"; + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation)); + + Assert.That(rr.InitializerStatements.Count, Is.EqualTo(1)); + var or = rr.InitializerStatements[0] as OperatorResolveResult; + Assert.That(or, Is.Not.Null); + Assert.That(or.OperatorType, Is.EqualTo(ExpressionType.Assign)); + var mrr = or.Operands[0] as MemberResolveResult; + Assert.That(mrr, Is.Not.Null); + Assert.That(mrr.TargetResult, Is.InstanceOf()); + Assert.That(mrr.Member.Name, Is.EqualTo("A")); + Assert.That(or.Operands[1], Is.InstanceOf()); + Assert.That(((LocalResolveResult)or.Operands[1]).Variable.Name, Is.EqualTo("j")); + } + + [Test] + public void InitializingBaseWithDynamicArgumentAndOneApplicableConstructor() { + string program = @"using System; +class TestBase { + public TestBase(int a, int b) {} + public TestBase(string a) {} +} + +class TestClass : TestBase { + private static dynamic d; + private static int i; + + public TestClass() : $base(d, i)$ {} +}"; + + var rr = Resolve(program); + + Assert.That(rr.Member.Name, Is.EqualTo(".ctor")); + Assert.That(rr.TargetResult, Is.Null); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestBase")); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Input is MemberResolveResult && ((MemberResolveResult)cr.Input).Member.Name == "d"); + Assert.That(rr.Arguments[1] is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1]).Member.Name == "i"); + } + + [Test] + public void InitializingBaseWithDynamicArgumentAndTwoApplicableConstructors() { + string program = @"using System; +class TestBase { + public TestBase(int a, int b) {} + public TestBase(string a, int b) {} + public TestBase(string a) {} +} + +class TestClass : TestBase { + private static dynamic d; + private static int i; + + public TestClass() : $base(d, i)$ {} +}"; + + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.Null); + Assert.That(mg.MethodName, Is.EqualTo(".ctor")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32")); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestBase")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[0].Value).Member.Name == "d"); + Assert.That(rr.Arguments[1].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1].Value).Member.Name == "i"); + } + + [Test] + public void ConstructorChainingWithDynamicArgumentAndOneApplicableConstructor() { + string program = @"using System; +class TestClass { + private static dynamic d; + private static int i; + + public TestClass(int a, int b) {} + public TestClass(string a) {} + + public TestClass() : $this(d, i)$ {} +}"; + + var rr = Resolve(program); + + Assert.That(rr.Member.Name, Is.EqualTo(".ctor")); + Assert.That(rr.TargetResult, Is.Null); + Assert.That(((IParameterizedMember)rr.Member).Parameters.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Member.DeclaringType.Name, Is.EqualTo("TestClass")); + var cr = rr.Arguments[0] as ConversionResolveResult; + Assert.That(cr, Is.Not.Null); + Assert.That(cr.Input is MemberResolveResult && ((MemberResolveResult)cr.Input).Member.Name == "d"); + Assert.That(rr.Arguments[1] is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1]).Member.Name == "i"); + } + + [Test] + public void ConstructorChainingWithDynamicArgumentAndTwoApplicableConstructors() { + string program = @"using System; +class TestBase { +} + +class TestClass { + private static dynamic d; + private static int i; + + public TestClass(int a, int b) {} + public TestClass(string a, int b) {} + public TestClass(string a) {} + + public TestClass() : $this(d, i)$ {} +}"; + + var rr = Resolve(program); + Assert.That(rr.InvocationType, Is.EqualTo(DynamicInvocationType.ObjectCreation)); + + var mg = rr.Target as MethodGroupResolveResult; + Assert.That(mg, Is.Not.Null, "Expected a MethodGroup"); + Assert.That(mg.TargetResult, Is.Null); + Assert.That(mg.MethodName, Is.EqualTo(".ctor")); + Assert.That(mg.Methods.All(m => m.Parameters.Count == 2 && m.Parameters[1].Type.Name == "Int32")); + Assert.That(mg.Methods.Select(m => m.Parameters[0].Type.Name), Is.EquivalentTo(new[] { "Int32", "String" })); + Assert.That(mg.Methods.All(m => m.Name == ".ctor" && m.DeclaringType.Name == "TestClass")); + + Assert.That(rr.Arguments.Count, Is.EqualTo(2)); + Assert.That(rr.Arguments[0].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[0].Value).Member.Name == "d"); + Assert.That(rr.Arguments[1].Value is MemberResolveResult && ((MemberResolveResult)rr.Arguments[1].Value).Member.Name == "i"); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs index 721a510115..609c66ec33 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs @@ -275,5 +275,46 @@ class Test where T : new() { Assert.AreEqual(TypeKind.TypeParameter, rr.Type.Kind); Assert.AreEqual(TypeKind.TypeParameter, rr.Member.DeclaringType.Kind); } + + [Test] + public void CreateDelegateFromMethodGroup() + { + string program = @"using System; +delegate void D(int i); +class C { + void M(int y) { + D d = $new D(M)$; + } +}"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + Assert.IsTrue(rr.Conversion.IsIdentityConversion); + var rr2 = (ConversionResolveResult)rr.Input; + Assert.IsFalse(rr2.IsError); + Assert.IsTrue(rr2.Conversion.IsMethodGroupConversion); + + Assert.AreEqual("C.M", rr2.Conversion.Method.FullName); + var mgrr = (MethodGroupResolveResult)rr2.Input; + Assert.IsInstanceOf(mgrr.TargetResult); + } + + [Test] + public void CreateDelegateFromDelegate() + { + string program = @"using System; +delegate void D1(int i); +delegate void D2(int i); +class C { + void M(D1 d1) { + D2 d2 = $new D2(d1)$; + } +}"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + Assert.IsTrue(rr.Conversion.IsMethodGroupConversion); + Assert.AreEqual("D1.Invoke", rr.Conversion.Method.FullName); + var mgrr = (MethodGroupResolveResult)rr.Input; + Assert.IsInstanceOf(mgrr.TargetResult); + } } } diff --git a/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs b/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs index 97f855453c..26de3ca22d 100644 --- a/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs @@ -26,7 +26,6 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.Documentation { [TestFixture] - [Ignore("Cref parsing not yet implemented")] public class CSharpCrefLookupTests { IEntity Lookup(string cref) @@ -58,7 +57,7 @@ class Impl : IGeneric[,], T> { var pc = new CSharpProjectContent().AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib }); var cu = new CSharpParser().Parse(new StringReader(program), "program.cs"); var compilation = pc.UpdateProjectContent(null, cu.ToTypeSystem()).CreateCompilation(); - var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.Single(); + var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.First(); IEntity entity = typeDefinition.Documentation.ResolveCref(cref); Assert.IsNotNull(entity, "ResolveCref() returned null."); return entity; @@ -109,7 +108,7 @@ class Impl : IGeneric[,], T> { [Test] public void M() { - Assert.AreEqual("M:Test.M(System.String[0:,0:])", + Assert.AreEqual("M:Test.M(System.Int32)", IdStringProvider.GetIdString(Lookup("M"))); } @@ -141,19 +140,25 @@ class Impl : IGeneric[,], T> { [Test] public void MethodInGenericInterface() { - Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)", + Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)", IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test"))); - Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)", + Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)", IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}"))); - Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)", + Assert.AreEqual("M:IGeneric`2.Test``1(``0[0:,0:]@)", IdStringProvider.GetIdString(Lookup("IGeneric{X, Y}.Test{Z}(ref Z[,])"))); } [Test] - public void Indexer() + [Ignore("Fails due to mcs parser bug (see CSharpCrefParserTests.This)")] + public void IndexerWithoutDeclaringType() { Assert.AreEqual("P:Test.Item(System.Int32)", IdStringProvider.GetIdString(Lookup("this"))); + } + + [Test] + public void IndexerWithDeclaringType() + { Assert.AreEqual("P:Test.Item(System.Int32)", IdStringProvider.GetIdString(Lookup("Test.this"))); Assert.AreEqual("P:Test.Item(System.Int32)", @@ -161,6 +166,7 @@ class Impl : IGeneric[,], T> { } [Test] + [Ignore("mcs bug, see CSharpCrefParserTests.OperatorPlusWithDeclaringType")] public void OperatorPlus() { Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)", @@ -172,6 +178,7 @@ class Impl : IGeneric[,], T> { } [Test] + [Ignore("mcs bug, see CSharpCrefParserTests.OperatorPlusWithDeclaringType")] public void ImplicitOperator() { Assert.AreEqual("M:Test.op_Implicit(Test)~System.Int32", diff --git a/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs b/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs index 505c7b83c9..d0dc33c5b6 100644 --- a/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs +++ b/ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs @@ -25,7 +25,6 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.Documentation { [TestFixture] - [Ignore("Cref parsing not yet implemented")] public class CSharpCrefParserTests { [Test] @@ -39,6 +38,7 @@ namespace ICSharpCode.NRefactory.Documentation } [Test] + [Ignore("mcs bug")] public void This() { ParseUtilCSharp.AssertDocumentationReference( @@ -49,6 +49,7 @@ namespace ICSharpCode.NRefactory.Documentation } [Test] + [Ignore("mcs bug (Unexpected symbol `this', expecting `explicit', `implicit', `operator', or `type')")] public void ThisWithParameter() { ParseUtilCSharp.AssertDocumentationReference( @@ -115,6 +116,21 @@ namespace ICSharpCode.NRefactory.Documentation }); } + [Test] + public void IntParse() + { + ParseUtilCSharp.AssertDocumentationReference( + "int.Parse(string)", + new DocumentationReference { + DeclaringType = new PrimitiveType("int"), + MemberName = "Parse", + HasParameterList = true, + Parameters = { + new ParameterDeclaration { Type = new PrimitiveType("string") } + } + }); + } + [Test] public void Generic() { @@ -201,6 +217,7 @@ namespace ICSharpCode.NRefactory.Documentation } [Test] + [Ignore("mcs bug (Unexpected symbol `operator', expecting `identifier' or `this')")] public void OperatorPlusWithDeclaringType() { ParseUtilCSharp.AssertDocumentationReference( @@ -256,6 +273,7 @@ namespace ICSharpCode.NRefactory.Documentation } [Test] + [Ignore("mcs bug (Unexpected symbol `explicit', expecting `identifier' or `this')")] public void ExplicitOperatorWithParameterListAndDeclaringType() { ParseUtilCSharp.AssertDocumentationReference( diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs index 2318208a55..1600e5372a 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs @@ -21,6 +21,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.TypeSystem.Implementation; using NUnit.Framework; @@ -31,12 +32,43 @@ namespace ICSharpCode.NRefactory.TypeSystem [TestFixture] public class GetAllBaseTypesTest { + const string corlib = @" +namespace System { + class Object {} + class ValueType {} + class String : System.Collections.Generic.IEnumerable, IComparable {} + class Array : System.Collections.IList, ICloneable {} + + interface ICloneable {} + interface IComparable {} + struct Int32 {} + struct Char {} +} +namespace System.Collections { + interface IEnumerable {} + interface ICollection : IEnumerable {} + interface IList : ICollection {} + interface IDictionary : ICollection {} +} +namespace System.Collections.Generic { + interface IEnumerable : IEnumerable {} + interface ICollection : IEnumerable {} + interface IList : ICollection {} + interface IDictionary : ICollection> {} + + class List : IList, IList {} + class Dictionary : IDictionary, IDictionary {} + struct KeyValuePair {} +} +"; + ICompilation compilation; [SetUp] public void SetUp() { - compilation = new SimpleCompilation(CecilLoaderTests.Mscorlib); + var parsedFile = new CSharpParser().Parse(corlib, "corlib.cs").ToTypeSystem(); + compilation = new CSharpProjectContent().SetAssemblyName("mscorlib").UpdateProjectContent(null, parsedFile).CreateCompilation(); } IType[] GetAllBaseTypes(Type type) @@ -46,7 +78,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IType[] GetTypes(params Type[] types) { - return types.Select(t => compilation.FindType(t)).OrderBy(t => t.ReflectionName).ToArray();; + return types.Select(t => compilation.FindType(t)).OrderBy(t => t.ReflectionName).ToArray(); } ITypeDefinition Resolve(IUnresolvedTypeDefinition typeDef) @@ -58,24 +90,26 @@ namespace ICSharpCode.NRefactory.TypeSystem public void ObjectBaseTypes() { Assert.AreEqual(GetTypes(typeof(object)), GetAllBaseTypes(typeof(object))); + + Assert.That(compilation.FindType(KnownTypeCode.Object).DirectBaseTypes, Is.Empty); } [Test] public void StringBaseTypes() { - Assert.AreEqual(GetTypes(typeof(string), typeof(object), typeof(IComparable), typeof(ICloneable), typeof(IConvertible), - typeof(IComparable), typeof(IEquatable), typeof(IEnumerable), typeof(IEnumerable)), + Assert.AreEqual(GetTypes(typeof(string), typeof(object), + typeof(IComparable), typeof(IEnumerable), typeof(IEnumerable)), GetAllBaseTypes(typeof(string))); } [Test] - [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")] public void ArrayOfString() { - Assert.AreEqual(GetTypes(typeof(string[]), typeof(Array), typeof(object), - typeof(IList), typeof(ICollection), typeof(IEnumerable), - typeof(IList), typeof(ICollection), typeof(IEnumerable), - typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)), + var expectedTypes = GetTypes( + typeof(string[]), typeof(Array), typeof(object), + typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable), + typeof(IList), typeof(ICollection), typeof(IEnumerable)); + Assert.AreEqual(expectedTypes, GetAllBaseTypes(typeof(string[]))); } @@ -83,8 +117,7 @@ namespace ICSharpCode.NRefactory.TypeSystem public unsafe void ArrayOfPointers() { Assert.AreEqual(GetTypes(typeof(int*[]), typeof(Array), typeof(object), - typeof(IList), typeof(ICollection), typeof(IEnumerable), - typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)), + typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable)), GetAllBaseTypes(typeof(int*[]))); } @@ -92,8 +125,7 @@ namespace ICSharpCode.NRefactory.TypeSystem public void MultidimensionalArrayOfString() { Assert.AreEqual(GetTypes(typeof(string[,]), typeof(Array), typeof(object), - typeof(IList), typeof(ICollection), typeof(IEnumerable), - typeof(IStructuralEquatable), typeof(IStructuralComparable), typeof(ICloneable)), + typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(ICloneable)), GetAllBaseTypes(typeof(string[,]))); } @@ -175,7 +207,6 @@ namespace ICSharpCode.NRefactory.TypeSystem } [Test] - [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")] public void BaseTypesOfListOfString() { Assert.AreEqual( @@ -186,7 +217,6 @@ namespace ICSharpCode.NRefactory.TypeSystem } [Test] - [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")] public void BaseTypesOfUnboundDictionary() { Assert.AreEqual( @@ -198,15 +228,12 @@ namespace ICSharpCode.NRefactory.TypeSystem typeof(ICollection).FullName, typeof(IDictionary).FullName, typeof(IEnumerable).FullName, - typeof(object).FullName, - typeof(IDeserializationCallback).FullName, - typeof(ISerializable).FullName, + typeof(object).FullName }, - GetAllBaseTypes(typeof(Dictionary<,>)).Select(t => t.ReflectionName).ToArray()); + GetAllBaseTypes(typeof(Dictionary<,>)).Select(t => t.ReflectionName).OrderBy(n => n).ToArray()); } [Test] - [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")] public void BaseTypeDefinitionsOfListOfString() { Assert.AreEqual( @@ -217,12 +244,10 @@ namespace ICSharpCode.NRefactory.TypeSystem } [Test] - [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")] public void BaseTypeDefinitionsOfStringArray() { Assert.AreEqual( - GetTypes(typeof(Array), typeof(object), - typeof(ICloneable), typeof(IStructuralComparable), typeof(IStructuralEquatable), + GetTypes(typeof(Array), typeof(object), typeof(ICloneable), typeof(IList), typeof(ICollection), typeof(IEnumerable), typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)), compilation.FindType(typeof(string[])).GetAllBaseTypeDefinitions().OrderBy(t => t.ReflectionName).ToArray()); diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs index 2efddd385a..f95b5a5d3f 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs @@ -44,6 +44,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase public class ParamsAttribute : Attribute { public ParamsAttribute(params object[] x) {} + + [Params(Property = new string[] { "a", "b" })] + public string[] Property { get; set; } } [Double(1)] @@ -291,4 +294,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase public class ClassThatImplementsEventExplicitly : IHasEvent { event EventHandler IHasEvent.Event { add {} remove {} } } + + public interface IShadowTestBase { + void Method(); + int this[int i] { get; set; } + int Prop { get; set; } + event EventHandler Evt; + } + + public interface IShadowTestDerived : IShadowTestBase { + new void Method(); + new int this[int i] { get; set; } + new int Prop { get; set; } + new event EventHandler Evt; + } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index 08ce99a935..f8e41711f0 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -821,6 +821,23 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual("Test", rr.Input.ConstantValue); } + [Test] + public void ParamsAttribute_Property() + { + ITypeDefinition type = GetTypeDefinition(typeof(ParamsAttribute)); + IProperty prop = type.Properties.Single(p => p.Name == "Property"); + var attr = prop.Attributes.Single(); + Assert.AreEqual(type, attr.AttributeType); + + var normalArguments = ((ArrayCreateResolveResult)attr.PositionalArguments.Single()).InitializerElements; + Assert.AreEqual(0, normalArguments.Count); + + var namedArg = attr.NamedArguments.Single(); + Assert.AreEqual(prop, namedArg.Key); + var arrayElements = ((ArrayCreateResolveResult)namedArg.Value).InitializerElements; + Assert.AreEqual(2, arrayElements.Count); + } + [Test] public void DoubleAttribute_ImplicitNumericConversion() { @@ -978,6 +995,7 @@ namespace ICSharpCode.NRefactory.TypeSystem public void ExplicitIndexerImplementationReturnsTheCorrectMembers() { ITypeDefinition type = GetTypeDefinition(typeof(ClassThatImplementsIndexersExplicitly)); + Assert.That(type.Properties.All(p => p.EntityType == EntityType.Indexer)); Assert.That(type.Properties.All(p => p.ImplementedInterfaceMembers.Count == 1)); Assert.That(type.Properties.All(p => p.Getter.ImplementedInterfaceMembers.Count == 1)); Assert.That(type.Properties.All(p => p.Setter.ImplementedInterfaceMembers.Count == 1)); @@ -1094,5 +1112,25 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.That(evt.AddAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.NRefactory.TypeSystem.TestCase.IHasEvent.add_Event" })); Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers.Select(p => p.ReflectionName).ToList(), Is.EqualTo(new[] { "ICSharpCode.NRefactory.TypeSystem.TestCase.IHasEvent.remove_Event" })); } + + [Test] + public void MembersDeclaredInDerivedInterfacesDoNotImplementBaseMembers() { + ITypeDefinition type = GetTypeDefinition(typeof(IShadowTestDerived)); + var method = type.Methods.Single(m => m.Name == "Method"); + var indexer = type.Properties.Single(p => p.IsIndexer); + var prop = type.Properties.Single(p => p.Name == "Prop"); + var evt = type.Events.Single(e => e.Name == "Evt"); + + Assert.That(method.ImplementedInterfaceMembers, Is.Empty); + Assert.That(indexer.ImplementedInterfaceMembers, Is.Empty); + Assert.That(indexer.Getter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(indexer.Setter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(prop.ImplementedInterfaceMembers, Is.Empty); + Assert.That(prop.Getter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(prop.Setter.ImplementedInterfaceMembers, Is.Empty); + Assert.That(evt.ImplementedInterfaceMembers, Is.Empty); + Assert.That(evt.AddAccessor.ImplementedInterfaceMembers, Is.Empty); + Assert.That(evt.RemoveAccessor.ImplementedInterfaceMembers, Is.Empty); + } } } diff --git a/ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs b/ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs index f2381b878e..3c6b82ac4b 100644 --- a/ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs +++ b/ICSharpCode.NRefactory/Properties/GlobalAssemblyInfo.cs @@ -23,4 +23,4 @@ using System.Runtime.InteropServices; // [AssemblyFileVersion] is the version of the NuGet package, // should follow http://semver.org/ rules -[assembly: AssemblyFileVersion("5.0.1")] +[assembly: AssemblyFileVersion("5.1.0")] diff --git a/ICSharpCode.NRefactory/Semantics/Conversion.cs b/ICSharpCode.NRefactory/Semantics/Conversion.cs index a68a7f407f..fc5889d55f 100644 --- a/ICSharpCode.NRefactory/Semantics/Conversion.cs +++ b/ICSharpCode.NRefactory/Semantics/Conversion.cs @@ -185,6 +185,14 @@ namespace ICSharpCode.NRefactory.Semantics get { return type == 0; } } + public override bool IsNullLiteralConversion { + get { return type == 1; } + } + + public override bool IsConstantExpressionConversion { + get { return type == 2; } + } + public override bool IsReferenceConversion { get { return type == 3; } } @@ -365,6 +373,14 @@ namespace ICSharpCode.NRefactory.Semantics get { return false; } } + public virtual bool IsNullLiteralConversion { + get { return false; } + } + + public virtual bool IsConstantExpressionConversion { + get { return false; } + } + public virtual bool IsNumericConversion { get { return false; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index 4d4fd9c5f2..e4322822f9 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -1676,7 +1676,18 @@ namespace ICSharpCode.NRefactory.TypeSystem bool getterVisible = property.GetMethod != null && IsVisible(property.GetMethod.Attributes); bool setterVisible = property.SetMethod != null && IsVisible(property.SetMethod.Attributes); if (getterVisible || setterVisible) { - EntityType type = property.Name == defaultMemberName ? EntityType.Indexer : EntityType.Property; + EntityType type = EntityType.Property; + if (property.HasParameters) { + // Try to detect indexer: + if (property.Name == defaultMemberName) { + type = EntityType.Indexer; // normal indexer + } else if (property.Name.EndsWith(".Item", StringComparison.Ordinal) && (property.GetMethod ?? property.SetMethod).HasOverrides) { + // explicit interface implementation of indexer + type = EntityType.Indexer; + // We can't really tell parameterized properties and indexers apart in this case without + // resolving the interface, so we rely on the "Item" naming convention instead. + } + } members.Add(ReadProperty(property, td, type)); } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs index d027f0b21d..0ff0b25a58 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs @@ -76,7 +76,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation result.Add(member); } return result.ToArray(); - } else if (unresolved.IsStatic) { + } else if (unresolved.IsStatic || DeclaringTypeDefinition == null || DeclaringTypeDefinition.Kind == TypeKind.Interface) { return EmptyList.Instance; } else { // TODO: implement interface member mappings correctly diff --git a/Packages/ICSharpCode.NRefactory.nuspec b/Packages/ICSharpCode.NRefactory.nuspec index 770e9c0094..230579c4ec 100644 --- a/Packages/ICSharpCode.NRefactory.nuspec +++ b/Packages/ICSharpCode.NRefactory.nuspec @@ -2,9 +2,9 @@ ICSharpCode.NRefactory - 5.0.1 + 5.1.0 NRefactory - Daniel Grunwald, Mike Krüger + Daniel Grunwald, Mike Krüger, Erik Källén Daniel Grunwald http://www.opensource.org/licenses/mit-license.php https://github.com/icsharpcode/NRefactory/