Exemplo n.º 1
0
		public void InferFromMethodReturnType()
		{
			// static void M<T>(Func<T> f) {}
			// M(Console.ReadKey); // type inference produces ConsoleKeyInfo
			
			var T = new DefaultTypeParameter(compilation, SymbolKind.Method, 0, "T");
			
			IType declType = compilation.FindType(typeof(Console));
			var methods = new MethodListWithDeclaringType(declType, declType.GetMethods(m => m.Name == "ReadKey"));
			var argument = new MethodGroupResolveResult(new TypeResolveResult(declType), "ReadKey", new[] { methods }, new IType[0]);
			
			bool success;
			Assert.AreEqual(
				new [] { compilation.FindType(typeof(ConsoleKeyInfo)) },
				ti.InferTypeArguments(new [] { T }, new [] { argument },
				                      new [] { new ParameterizedType(compilation.FindType(typeof(Func<>)).GetDefinition(), new[] { T }) },
				                      out success));
			Assert.IsTrue(success);
		}
Exemplo n.º 2
0
		IEnumerable<ICompletionData> CreateParameterCompletion(MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, SyntaxTree unit, int parameter, bool controlSpace)
		{
			var result = new CompletionDataWrapper(this);
			var addedEnums = new HashSet<string>();
			var addedDelegates = new HashSet<string>();

			foreach (var method in resolveResult.Methods) {
				CreateParameterForInvocation(result, method, state, parameter, addedEnums, addedDelegates);
			}
			foreach (var methods in resolveResult.GetEligibleExtensionMethods (true)) {
				foreach (var method in methods) {
					if (resolveResult.Methods.Contains(method))
						continue;
					CreateParameterForInvocation(result, new ReducedExtensionMethod(method), state, parameter, addedEnums, addedDelegates);
				}
			}

			foreach (var method in resolveResult.Methods) {
				if (parameter < method.Parameters.Count && method.Parameters [parameter].Type.Kind == TypeKind.Delegate) {
					AutoSelect = false;
					AutoCompleteEmptyMatch = false;
				}
				foreach (var p in method.Parameters) {
					result.AddNamedParameterVariable(p);
				}
			}

			if (!controlSpace) {
				if (addedEnums.Count + addedDelegates.Count == 0) {
					return Enumerable.Empty<ICompletionData>();
				}
				AutoCompleteEmptyMatch = false;
				AutoSelect = false;
			}
			AddContextCompletion(result, state, invocation);

			//			resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc);
			//			if (addedDelegates.Count > 0) {
			//				foreach (var data in result.Result) {
			//					if (data is MemberCompletionData) 
			//						((MemberCompletionData)data).IsDelegateExpected = true;
			//				}
			//			}
			return result.Result;
		}
Exemplo n.º 3
0
		public void CannotInferFromMethodParameterTypes()
		{
			// static void M<A, B>(Func<A, B> f) {}
			// M(int.Parse); // type inference fails
			var A = new DefaultTypeParameter(compilation, SymbolKind.Method, 0, "A");
			var B = new DefaultTypeParameter(compilation, SymbolKind.Method, 1, "B");
			
			IType declType = compilation.FindType(typeof(int));
			var methods = new MethodListWithDeclaringType(declType, declType.GetMethods(m => m.Name == "Parse"));
			var argument = new MethodGroupResolveResult(new TypeResolveResult(declType), "Parse", new[] { methods }, new IType[0]);
			
			bool success;
			ti.InferTypeArguments(new [] { A, B }, new [] { argument },
			                      new [] { new ParameterizedType(compilation.FindType(typeof(Func<,>)).GetDefinition(), new[] { A, B }) },
			                      out success);
			Assert.IsFalse(success);
		}
Exemplo n.º 4
0
        /// <summary>
        /// Resolves an object creation.
        /// </summary>
        /// <param name="type">Type of the object to create.</param>
        /// <param name="arguments">
        /// Arguments passed to the constructor.
        /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
        /// </param>
        /// <param name="argumentNames">
        /// The argument names. Pass the null string for positional arguments.
        /// </param>
        /// <param name="allowProtectedAccess">
        /// Whether to allow calling protected constructors.
        /// This should be false except when resolving constructor initializers.
        /// </param>
        /// <param name="initializerStatements">
        /// Statements for Objects/Collections initializer.
        /// <see cref="InvocationResolveResult.InitializerStatements"/>
        /// </param>
        /// <returns>InvocationResolveResult or ErrorResolveResult</returns>
        public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList<ResolveResult> initializerStatements = null)
        {
            if (type.Kind == TypeKind.Delegate && arguments.Length == 1) {
                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<IType>.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<IMethod>() : null);
            foreach (IMethod ctor in type.GetConstructors()) {
                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, AddArgumentNamesIfNecessary(arguments, argumentNames), initializerStatements);
            }

            if (or.BestCandidate != null) {
                return or.CreateResolveResult(null, initializerStatements);
            } else {
                return new ErrorResolveResult(type);
            }
        }
Exemplo n.º 5
0
		IEnumerable<ICompletionData> CreateParameterCompletion(MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, CompilationUnit unit, int parameter, bool controlSpace)
		{
			var result = new CompletionDataWrapper(this);
			var addedEnums = new HashSet<string>();
			var addedDelegates = new HashSet<string>();
			
			foreach (var method in resolveResult.Methods) {
				if (method.Parameters.Count <= parameter) {
					continue;
				}
				var resolvedType = method.Parameters [parameter].Type;
				if (resolvedType.Kind == TypeKind.Enum) {
					if (addedEnums.Contains(resolvedType.ReflectionName)) {
						continue;
					}
					addedEnums.Add(resolvedType.ReflectionName);
					AddEnumMembers(result, resolvedType, state);
				} else if (resolvedType.Kind == TypeKind.Delegate) {
					if (addedDelegates.Contains(resolvedType.ReflectionName))
						continue;
					string parameterDefinition = AddDelegateHandlers(result, resolvedType);
					string varName = "Handle" + method.Parameters [parameter].Type.Name + method.Parameters [parameter].Name;
					result.Result.Add(
						factory.CreateEventCreationCompletionData(
						varName,
						resolvedType,
						null,
						parameterDefinition,
						currentMember,
						currentType)
					);
				}
			}
			if (!controlSpace) {
				if (addedEnums.Count + addedDelegates.Count == 0) {
					return Enumerable.Empty<ICompletionData>();
				}
				AutoCompleteEmptyMatch = false;
				AutoSelect = false;
			}
			AddContextCompletion(result, state, invocation, unit);
			
			//			resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc);
			//			if (addedDelegates.Count > 0) {
			//				foreach (var data in result.Result) {
			//					if (data is MemberCompletionData) 
			//						((MemberCompletionData)data).IsDelegateExpected = true;
			//				}
			//			}
			return result.Result;
		}
		IEnumerable<IMethod> CollectMethods(AstNode resolvedNode, MethodGroupResolveResult resolveResult)
		{
			var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);
			bool onlyStatic = false;
			if (resolvedNode is IdentifierExpression && currentMember != null && currentMember.IsStatic || resolveResult.TargetResult is TypeResolveResult) {
				onlyStatic = true;
			}
			var methods = new List<IMethod>();
			foreach (var method in resolveResult.Methods) {
				if (method.IsConstructor) {
					continue;
				}
				if (!lookup.IsAccessible (method, true))
					continue;
				if (onlyStatic && !method.IsStatic) {
					continue;
				}
				if (method.IsShadowing) {
					for (int j = 0; j < methods.Count; j++) {
						if (ParameterListComparer.Instance.Equals(methods[j].Parameters, method.Parameters)) {
							methods.RemoveAt (j);
							j--;
						}
					}
				}
				methods.Add (method);
			}
			foreach (var m in methods) {
				yield return m;
			}
			foreach (var extMethods in resolveResult.GetEligibleExtensionMethods (true)) {
				foreach (var method in extMethods) {
					if (methods.Contains (method))
						continue;
					yield return new ReducedExtensionMethod (method);
				}
			}
		}
Exemplo n.º 7
0
        IEnumerable<ICompletionData> CreateParameterCompletion(MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, int parameter, bool controlSpace)
        {
            var result = new CompletionDataWrapper (this);
            var addedEnums = new HashSet<string> ();
            var addedDelegates = new HashSet<string> ();

            foreach (var method in resolveResult.Methods) {
                if (method.Parameters.Count <= parameter)
                    continue;
                var resolvedType = method.Parameters [parameter].Type;
                if (resolvedType.Kind == TypeKind.Enum) {
                    if (addedEnums.Contains (resolvedType.ReflectionName))
                        continue;
                    addedEnums.Add (resolvedType.ReflectionName);
                    AddEnumMembers (result, resolvedType, state);
                } else if (resolvedType.Kind == TypeKind.Delegate) {
            //					if (addedDelegates.Contains (resolvedType.DecoratedFullName))
            //						continue;
            //					addedDelegates.Add (resolvedType.DecoratedFullName);
            //					string parameterDefinition = AddDelegateHandlers (completionList, resolvedType, false, addedDelegates.Count == 1);
            //					string varName = "Handle" + method.Parameters [parameter].ReturnType.Name + method.Parameters [parameter].Name;
            //					result.Add (new EventCreationCompletionData (document, varName, resolvedType, null, parameterDefinition, resolver.Unit.GetMemberAt (location), resolvedType) { AddSemicolon = false });

                }
            }
            if (!controlSpace) {
                if (addedEnums.Count + addedDelegates.Count == 0)
                    return Enumerable.Empty<ICompletionData> ();
                AutoCompleteEmptyMatch = false;
                AutoSelect = false;
            }
            AddContextCompletion (result, state, invocation);

            //			resolver.AddAccessibleCodeCompletionData (ExpressionContext.MethodBody, cdc);
            //			if (addedDelegates.Count > 0) {
            //				foreach (var data in result.Result) {
            //					if (data is MemberCompletionData)
            //						((MemberCompletionData)data).IsDelegateExpected = true;
            //				}
            //			}
            return result.Result;
        }
		IEnumerable<IMethod> CollectMethods(AstNode resolvedNode, MethodGroupResolveResult resolveResult)
		{
			var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);
			bool onlyStatic = false;
			if (resolvedNode is IdentifierExpression && currentMember != null && currentMember.IsStatic || resolveResult.TargetResult is TypeResolveResult) {
				onlyStatic = true;
			}
			foreach (var method in resolveResult.Methods) {
				if (method.IsConstructor) {
					continue;
				}
				if (!lookup.IsAccessible (method, true))
					continue;
				if (onlyStatic && !method.IsStatic) {
					continue;
				}
				yield return method;	
			}
				
			foreach (var extMethods in resolveResult.GetEligibleExtensionMethods (true)) {
				foreach (var method in extMethods) {
					yield return method;
				}
			}
		}
Exemplo n.º 9
0
        void MakeOutputTypeInference(ResolveResult e, IType t)
        {
            Log.WriteLine(" MakeOutputTypeInference from " + e + " to " + t);
            // If E is an anonymous function with inferred return type  U (§7.5.2.12) and T is a delegate type or expression
            // tree type with return type Tb, then a lower-bound inference (§7.5.2.9) is made from U to Tb.
            LambdaResolveResult lrr = e as LambdaResolveResult;

            if (lrr != null)
            {
                IMethod m = GetDelegateOrExpressionTreeSignature(t);
                if (m != null)
                {
                    IType inferredReturnType;
                    if (lrr.IsImplicitlyTyped)
                    {
                        if (m.Parameters.Count != lrr.Parameters.Count)
                        {
                            return;                             // cannot infer due to mismatched parameter lists
                        }
                        TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs();
                        IType[] inferredParameterTypes         = new IType[m.Parameters.Count];
                        for (int i = 0; i < inferredParameterTypes.Length; i++)
                        {
                            IType parameterType = m.Parameters[i].Type;
                            inferredParameterTypes[i] = parameterType.AcceptVisitor(substitution);
                        }
                        inferredReturnType = lrr.GetInferredReturnType(inferredParameterTypes);
                    }
                    else
                    {
                        inferredReturnType = lrr.GetInferredReturnType(null);
                    }
                    MakeLowerBoundInference(inferredReturnType, m.ReturnType);
                    return;
                }
            }
            // Otherwise, if E is a method group and T is a delegate type or expression tree type
            // with parameter types T1…Tk and return type Tb, and overload resolution
            // of E with the types T1…Tk yields a single method with return type U, then a lower­-bound
            // inference is made from U to Tb.
            MethodGroupResolveResult mgrr = e as MethodGroupResolveResult;

            if (mgrr != null)
            {
                IMethod m = GetDelegateOrExpressionTreeSignature(t);
                if (m != null)
                {
                    ResolveResult[]           args         = new ResolveResult[m.Parameters.Count];
                    TypeParameterSubstitution substitution = GetSubstitutionForFixedTPs();
                    for (int i = 0; i < args.Length; i++)
                    {
                        IParameter param         = m.Parameters[i];
                        IType      parameterType = param.Type.AcceptVisitor(substitution);
                        if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference)
                        {
                            parameterType = ((ByReferenceType)parameterType).ElementType;
                            args[i]       = new ByReferenceResolveResult(parameterType, param.IsOut);
                        }
                        else
                        {
                            args[i] = new ResolveResult(parameterType);
                        }
                    }
                    var or = mgrr.PerformOverloadResolution(compilation,
                                                            args,
                                                            allowExpandingParams: false);
                    if (or.FoundApplicableCandidate && or.BestCandidateAmbiguousWith == null)
                    {
                        IType returnType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;
                        MakeLowerBoundInference(returnType, m.ReturnType);
                    }
                }
                return;
            }
            // Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T.
            if (IsValidType(e.Type))
            {
                MakeLowerBoundInference(e.Type, t);
            }
        }
Exemplo n.º 10
0
        public static ResolveResult Resolve(Lazy <ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node,
                                            CancellationToken cancellationToken = default(CancellationToken))
        {
            node = syntaxTree.GetNodeAt(location);
            if (node == null || node is ArrayInitializerExpression)
            {
                return(null);
            }
            if (node.Parent is UsingAliasDeclaration && node.Role == UsingAliasDeclaration.AliasRole)
            {
                var r = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile);
                return(r.Resolve(((UsingAliasDeclaration)node.Parent).Import, cancellationToken));
            }
            if (CSharpAstResolver.IsUnresolvableNode(node))
            {
                if (node is Identifier)
                {
                    node = node.Parent;
                }
                else if (node.NodeType == NodeType.Token)
                {
                    if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer || node.Role == IndexerDeclaration.ThisKeywordRole)
                    {
                        // There's no other place where one could hover to see the indexer's tooltip,
                        // so we need to resolve it when hovering over the '[' or ']'.
                        // For constructor initializer, the same applies to the 'base'/'this' token.
                        node = node.Parent;
                    }
                    else
                    {
                        return(null);
                    }
                }
                else
                {
                    // don't resolve arbitrary nodes - we don't want to show tooltips for everything
                    return(null);
                }
            }
            else
            {
                // It's a resolvable node.
                // However, we usually don't want to show the tooltip everywhere
                // For example, hovering with the mouse over an empty line between two methods causes
                // node==TypeDeclaration, but we don't want to show any tooltip.

                if (!node.GetChildByRole(Roles.Identifier).IsNull)
                {
                    // We'll suppress the tooltip for resolvable nodes if there is an identifier that
                    // could be hovered over instead:
                    return(null);
                }
            }

            if (node == null)
            {
                return(null);
            }

            if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type)
            {
                node = node.Parent;
            }

            InvocationExpression parentInvocation = null;

            if ((node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) && node.Role != Roles.Argument)
            {
                // we also need to resolve the invocation
                parentInvocation = node.Parent as InvocationExpression;
            }

            // TODO: I think we should provide an overload so that an existing CSharpAstResolver can be reused
            CSharpAstResolver        resolver = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile);
            ResolveResult            rr       = resolver.Resolve(node, cancellationToken);
            MethodGroupResolveResult mgrr     = rr as MethodGroupResolveResult;

            if (mgrr != null)
            {
                // For method groups, resolve the parent invocation instead.
                if (parentInvocation != null)
                {
                    return(resolver.Resolve(parentInvocation));
                }
                if (node is Expression)
                {
                    // If it's not an invocation, try if it's a conversion to a delegate type:
                    Conversion c = resolver.GetConversion((Expression)node, cancellationToken);
                    if (c.IsMethodGroupConversion)
                    {
                        return(new MemberResolveResult(mgrr.TargetResult, c.Method));
                    }
                }
            }
            return(rr);
        }