> GetElementAccessExpressionParameterLists( SemanticModel semanticModel, int position, ElementAccessExpressionSyntax elementAccessExpression, CancellationToken cancellationToken ) { var expressionSymbol = semanticModel .GetSymbolInfo(elementAccessExpression.Expression, cancellationToken) .GetAnySymbol(); var expressionType = semanticModel.GetTypeInfo( elementAccessExpression.Expression, cancellationToken ).Type; if (expressionSymbol != null && expressionType != null) { var indexers = semanticModel .LookupSymbols(position, expressionType, WellKnownMemberNames.Indexer) .OfType<IPropertySymbol>(); var within = semanticModel.GetEnclosingNamedTypeOrAssembly( position, cancellationToken ); if (within != null) { return indexers .Where(i => i.IsAccessibleWithin(within, throughType: expressionType)) .Select(i => i.Parameters); } } return null; }
private IEnumerable <ImmutableArray <IParameterSymbol> > GetInvocationExpressionParameterLists( SemanticModel semanticModel, int position, InvocationExpressionSyntax invocationExpression, CancellationToken cancellationToken) { var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within != null) { var methodGroup = semanticModel.GetMemberGroup(invocationExpression.Expression, cancellationToken).OfType <IMethodSymbol>(); var expressionType = semanticModel.GetTypeInfo(invocationExpression.Expression, cancellationToken).Type as INamedTypeSymbol; if (methodGroup.Any()) { return(methodGroup.Where(m => m.IsAccessibleWithin(within)) .Select(m => m.Parameters)); } else if (expressionType.IsDelegateType()) { var delegateType = expressionType; return(SpecializedCollections.SingletonEnumerable(delegateType.DelegateInvokeMethod.Parameters)); } } return(null); }
private IEnumerable <ISymbol> GetAttributeNamedParameters( SemanticModel semanticModel, int position, AttributeSyntax attribute, CancellationToken cancellationToken) { var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); var attributeType = semanticModel.GetTypeInfo(attribute, cancellationToken).Type as INamedTypeSymbol; return(attributeType.GetAttributeNamedParameters(semanticModel.Compilation, within)); }
private IEnumerable <ImmutableArray <IParameterSymbol> > GetParameterLists( SemanticModel semanticModel, int position, AttributeSyntax attribute, CancellationToken cancellationToken) { var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within != null && semanticModel.GetTypeInfo(attribute, cancellationToken).Type is INamedTypeSymbol attributeType) { return(attributeType.InstanceConstructors.Where(c => c.IsAccessibleWithin(within)) .Select(c => c.Parameters)); } return(SpecializedCollections.EmptyEnumerable <ImmutableArray <IParameterSymbol> >()); }
ParameterHintingResult HandleObjectCreationExpression(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) { // var info = semanticModel.GetSymbolInfo(node, cancellationToken); var result = new ParameterHintingResult(node.SpanStart); var within = semanticModel.GetEnclosingNamedTypeOrAssembly(node.SpanStart, cancellationToken); var targetTypeInfo = semanticModel.GetTypeInfo(node); if (targetTypeInfo.Type != null) { foreach (IMethodSymbol c in targetTypeInfo.Type.GetMembers().OfType <IMethodSymbol>().Where(m => m.MethodKind == MethodKind.Constructor)) { if (c.IsAccessibleWithin(within)) { result.AddData(factory.CreateConstructorProvider(c)); } } } return(result); }
> GetRecordBaseTypeParameterLists( SemanticModel semanticModel, int position, PrimaryConstructorBaseTypeSyntax recordBaseType, CancellationToken cancellationToken ) { var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (within != null) { var type = semanticModel.GetTypeInfo(recordBaseType.Type, cancellationToken).Type as INamedTypeSymbol; return type?.InstanceConstructors.Where(m => m.IsAccessibleWithin(within)) .Select(m => m.Parameters); } return null; }
ParameterHintingResult HandleElementAccessExpression(SemanticModel semanticModel, ElementAccessExpressionSyntax node, CancellationToken cancellationToken) { var within = semanticModel.GetEnclosingNamedTypeOrAssembly(node.SpanStart, cancellationToken); var targetTypeInfo = semanticModel.GetTypeInfo(node.Expression); ITypeSymbol type = targetTypeInfo.Type; if (type == null) { return(ParameterHintingResult.Empty); } var result = new ParameterHintingResult(node.SpanStart); if (type.TypeKind == TypeKind.Array) { result.AddData(factory.CreateArrayDataProvider((IArrayTypeSymbol)type)); return(result); } var addedProperties = new List <IPropertySymbol> (); for (; type != null; type = type.BaseType) { foreach (var indexer in type.GetMembers().OfType <IPropertySymbol> ().Where(p => p.IsIndexer)) { if (addedProperties.Any(added => SignatureComparer.HaveSameSignature(indexer, added, true))) { continue; } if (indexer.IsAccessibleWithin(within)) { addedProperties.Add(indexer); result.AddData(factory.CreateIndexerParameterDataProvider(indexer, node)); } } } return(result); }
ParameterHintingResult HandleConstructorInitializer(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken) { var info = semanticModel.GetSymbolInfo(node, cancellationToken); var result = new ParameterHintingResult(node.SpanStart); var resolvedMethod = info.Symbol as IMethodSymbol; if (resolvedMethod != null) { var type = resolvedMethod.ContainingType; var within = semanticModel.GetEnclosingNamedTypeOrAssembly(node.SpanStart, cancellationToken); result.AddRange(type.GetMembers() .OfType <IMethodSymbol> () .Where(m => m.MethodKind == MethodKind.Constructor && m.IsAccessibleWithin(within)) .Select(factory.CreateConstructorProvider)); } else { result.AddRange(info.CandidateSymbols.OfType <IMethodSymbol> ().Select(factory.CreateConstructorProvider)); } return(result); }
ParameterHintingResult HandleInvocationExpression(SemanticModel semanticModel, InvocationExpressionSyntax node, CancellationToken cancellationToken) { var info = semanticModel.GetSymbolInfo(node, cancellationToken); var result = new ParameterHintingResult(node.SpanStart); var targetTypeInfo = semanticModel.GetTypeInfo(node.Expression); if (targetTypeInfo.Type != null && targetTypeInfo.Type.TypeKind == TypeKind.Delegate) { result.AddData(factory.CreateMethodDataProvider(targetTypeInfo.Type.GetDelegateInvokeMethod())); return(result); } var within = semanticModel.GetEnclosingNamedTypeOrAssembly(node.SpanStart, cancellationToken); ITypeSymbol type; var ma = node.Expression as MemberAccessExpressionSyntax; string name = null; bool staticLookup = false; if (ma != null) { staticLookup = semanticModel.GetSymbolInfo(ma.Expression).Symbol is ITypeSymbol; type = semanticModel.GetTypeInfo(ma.Expression).Type; name = info.Symbol?.Name ?? ma.Name.Identifier.ValueText; } else { type = within as ITypeSymbol; name = info.Symbol?.Name ?? node.Expression.ToString(); var sym = semanticModel.GetEnclosingSymbol(node.SpanStart, cancellationToken); staticLookup = sym.IsStatic; } var addedMethods = new List <IMethodSymbol> (); var filterMethod = new HashSet <IMethodSymbol> (); for (; type != null; type = type.BaseType) { foreach (var method in type.GetMembers().OfType <IMethodSymbol> ().Concat(GetExtensionMethods(semanticModel, type, node, cancellationToken)).Where(m => m.Name == name)) { if (staticLookup && !method.IsStatic) { continue; } if (method.OverriddenMethod != null) { filterMethod.Add(method.OverriddenMethod); } if (filterMethod.Contains(method)) { continue; } if (addedMethods.Any(added => SignatureComparer.HaveSameSignature(method, added, true))) { continue; } if (method.IsAccessibleWithin(within)) { if (info.Symbol != null) { var smethod = (IMethodSymbol)info.Symbol; if (smethod != null && smethod.OriginalDefinition == method) { continue; } } addedMethods.Add(method); result.AddData(factory.CreateMethodDataProvider(method)); } } } if (info.Symbol != null && !addedMethods.Contains(info.Symbol)) { if (!staticLookup || info.Symbol.IsStatic) { result.AddData(factory.CreateMethodDataProvider((IMethodSymbol)info.Symbol)); } } return(result); }
public static bool IsExpressionContext( this SyntaxTree syntaxTree, int position, SyntaxToken tokenOnLeftOfPosition, bool attributes, CancellationToken cancellationToken, SemanticModel semanticModelOpt = null) { // cases: // var q = | // var q = a| // this list is *not* exhaustive. var token = tokenOnLeftOfPosition.GetPreviousTokenIfTouchingWord(position); if (token.GetAncestor<ConditionalDirectiveTriviaSyntax>() != null) { return false; } if (!attributes) { if (token.GetAncestor<AttributeListSyntax>() != null) { return false; } } if (syntaxTree.IsConstantExpressionContext(position, tokenOnLeftOfPosition, cancellationToken)) { return true; } // no expressions after . :: -> if (token.IsKind(SyntaxKind.DotToken) || token.IsKind(SyntaxKind.ColonColonToken) || token.IsKind(SyntaxKind.MinusGreaterThanToken)) { return false; } // Normally you can have any sort of expression after an equals. However, this does not // apply to a "using Foo = ..." situation. if (token.IsKind(SyntaxKind.EqualsToken)) { if (token.Parent.IsKind(SyntaxKind.NameEquals) && token.Parent.IsParentKind(SyntaxKind.UsingDirective)) { return false; } } // q = | // q -= | // q *= | // q += | // q /= | // q ^= | // q %= | // q &= | // q |= | // q <<= | // q >>= | if (token.IsKind(SyntaxKind.EqualsToken) || token.IsKind(SyntaxKind.MinusEqualsToken) || token.IsKind(SyntaxKind.AsteriskEqualsToken) || token.IsKind(SyntaxKind.PlusEqualsToken) || token.IsKind(SyntaxKind.SlashEqualsToken) || token.IsKind(SyntaxKind.ExclamationEqualsToken) || token.IsKind(SyntaxKind.CaretEqualsToken) || token.IsKind(SyntaxKind.AmpersandEqualsToken) || token.IsKind(SyntaxKind.BarEqualsToken) || token.IsKind(SyntaxKind.PercentEqualsToken) || token.IsKind(SyntaxKind.LessThanLessThanEqualsToken) || token.IsKind(SyntaxKind.GreaterThanGreaterThanEqualsToken)) { return true; } // ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.Parent.IsKind(SyntaxKind.ParenthesizedExpression)) { return true; } // - | // + | // ~ | // ! | if (token.Parent is PrefixUnaryExpressionSyntax) { var prefix = token.Parent as PrefixUnaryExpressionSyntax; return prefix.OperatorToken == token; } // not sure about these: // ++ | // -- | #if false token.Kind == SyntaxKind.PlusPlusToken || token.Kind == SyntaxKind.DashDashToken) #endif // await | if (token.Parent is AwaitExpressionSyntax) { var awaitExpression = token.Parent as AwaitExpressionSyntax; return awaitExpression.AwaitKeyword == token; } // Check for binary operators. // Note: // - We handle < specially as it can be ambiguous with generics. // - We handle * specially because it can be ambiguous with pointer types. // a * // a / // a % // a + // a - // a << // a >> // a < // a > // a && // a || // a & // a | // a ^ if (token.Parent is BinaryExpressionSyntax) { // If the client provided a binding, then check if this is actually generic. If so, // then this is not an expression context. i.e. if we have "Foo < |" then it could // be an expression context, or it could be a type context if Foo binds to a type or // method. if (semanticModelOpt != null && syntaxTree.IsGenericTypeArgumentContext(position, tokenOnLeftOfPosition, cancellationToken, semanticModelOpt)) { return false; } var binary = token.Parent as BinaryExpressionSyntax; if (binary.OperatorToken == token) { // If this is a multiplication expression and a semantic model was passed in, // check to see if the expression to the left is a type name. If it is, treat // this as a pointer type. if (token.IsKind(SyntaxKind.AsteriskToken) && semanticModelOpt != null) { var type = binary.Left as TypeSyntax; if (type != null && type.IsPotentialTypeName(semanticModelOpt, cancellationToken)) { return false; } } return true; } } // Special case: // Foo * bar // Foo ? bar // This parses as a local decl called bar of type Foo* or Foo? if (tokenOnLeftOfPosition.IntersectsWith(position) && tokenOnLeftOfPosition.IsKind(SyntaxKind.IdentifierToken)) { var previousToken = tokenOnLeftOfPosition.GetPreviousToken(includeSkipped: true); if (previousToken.IsKind(SyntaxKind.AsteriskToken) || previousToken.IsKind(SyntaxKind.QuestionToken)) { if (previousToken.Parent.IsKind(SyntaxKind.PointerType) || previousToken.Parent.IsKind(SyntaxKind.NullableType)) { var type = previousToken.Parent as TypeSyntax; if (type.IsParentKind(SyntaxKind.VariableDeclaration) && type.Parent.IsParentKind(SyntaxKind.LocalDeclarationStatement)) { var declStatement = type.Parent.Parent as LocalDeclarationStatementSyntax; // note, this doesn't apply for cases where we know it // absolutely is not multiplication or a conditional expression. var underlyingType = type is PointerTypeSyntax ? ((PointerTypeSyntax)type).ElementType : ((NullableTypeSyntax)type).ElementType; if (!underlyingType.IsPotentialTypeName(semanticModelOpt, cancellationToken)) { return true; } } } } } // new int[| // new int[expr, | if (token.IsKind(SyntaxKind.OpenBracketToken) || token.IsKind(SyntaxKind.CommaToken)) { if (token.Parent.IsKind(SyntaxKind.ArrayRankSpecifier)) { return true; } } // foo ? | if (token.IsKind(SyntaxKind.QuestionToken) && token.Parent.IsKind(SyntaxKind.ConditionalExpression)) { // If the condition is simply a TypeSyntax that binds to a type, treat this as a nullable type. var conditionalExpression = (ConditionalExpressionSyntax)token.Parent; var type = conditionalExpression.Condition as TypeSyntax; return type == null || !type.IsPotentialTypeName(semanticModelOpt, cancellationToken); } // foo ? bar : | if (token.IsKind(SyntaxKind.ColonToken) && token.Parent.IsKind(SyntaxKind.ConditionalExpression)) { return true; } // typeof(| // default(| // sizeof(| if (token.IsKind(SyntaxKind.OpenParenToken)) { if (token.Parent.IsKind(SyntaxKind.TypeOfExpression, SyntaxKind.DefaultExpression, SyntaxKind.SizeOfExpression)) { return false; } } // var(| // var(id, | // Those are more likely to be deconstruction-declarations being typed than invocations a method "var" if (token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken) && token.IsInvocationOfVarExpression()) { return false; } // Foo(| // Foo(expr, | // this[| // var t = (1, | // var t = (| , 2) if (token.IsKind(SyntaxKind.OpenParenToken) || token.IsKind(SyntaxKind.OpenBracketToken) || token.IsKind(SyntaxKind.CommaToken)) { if (token.Parent.IsKind(SyntaxKind.ArgumentList, SyntaxKind.BracketedArgumentList, SyntaxKind.TupleExpression)) { return true; } } // [Foo(| // [Foo(expr, | if (attributes) { if (token.IsKind(SyntaxKind.OpenParenToken) || token.IsKind(SyntaxKind.CommaToken)) { if (token.Parent.IsKind(SyntaxKind.AttributeArgumentList)) { return true; } } } // Foo(ref | // Foo(bar | if (token.IsKind(SyntaxKind.RefKeyword) || token.IsKind(SyntaxKind.OutKeyword)) { if (token.Parent.IsKind(SyntaxKind.Argument)) { return true; } } // Foo(bar: | if (token.IsKind(SyntaxKind.ColonToken) && token.Parent.IsKind(SyntaxKind.NameColon) && token.Parent.IsParentKind(SyntaxKind.Argument)) { return true; } // a => | if (token.IsKind(SyntaxKind.EqualsGreaterThanToken)) { return true; } // new List<int> { | // new List<int> { expr, | if (token.IsKind(SyntaxKind.OpenBraceToken) || token.IsKind(SyntaxKind.CommaToken)) { if (token.Parent is InitializerExpressionSyntax) { // The compiler treats the ambiguous case as an object initializer, so we'll say // expressions are legal here if (token.Parent.IsKind(SyntaxKind.ObjectInitializerExpression) && token.IsKind(SyntaxKind.OpenBraceToken)) { // In this position { a$$ =, the user is trying to type an object initializer. if (!token.IntersectsWith(position) && token.GetNextToken().GetNextToken().IsKind(SyntaxKind.EqualsToken)) { return false; } return true; } // Perform a semantic check to determine whether or not the type being created // can support a collection initializer. If not, this must be an object initializer // and can't be an expression context. if (semanticModelOpt != null && token.Parent.IsParentKind(SyntaxKind.ObjectCreationExpression)) { var objectCreation = (ObjectCreationExpressionSyntax)token.Parent.Parent; var type = semanticModelOpt.GetSymbolInfo(objectCreation.Type, cancellationToken).Symbol as ITypeSymbol; var containingSymbol = semanticModelOpt.GetEnclosingNamedTypeOrAssembly(position, cancellationToken); if (type != null && !type.CanSupportCollectionInitializer(containingSymbol)) { return false; } } return true; } } // for (; | // for (; ; | if (token.IsKind(SyntaxKind.SemicolonToken) && token.Parent.IsKind(SyntaxKind.ForStatement)) { var forStatement = (ForStatementSyntax)token.Parent; if (token == forStatement.FirstSemicolonToken || token == forStatement.SecondSemicolonToken) { return true; } } // for ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.Parent.IsKind(SyntaxKind.ForStatement)) { var forStatement = (ForStatementSyntax)token.Parent; if (token == forStatement.OpenParenToken) { return true; } } // for (; ; Foo(), | // for ( Foo(), | if (token.IsKind(SyntaxKind.CommaToken) && token.Parent.IsKind(SyntaxKind.ForStatement)) { return true; } // foreach (var v in | // from a in | // join b in | if (token.IsKind(SyntaxKind.InKeyword)) { if (token.Parent.IsKind(SyntaxKind.ForEachStatement, SyntaxKind.ForEachComponentStatement, SyntaxKind.FromClause, SyntaxKind.JoinClause)) { return true; } } // join x in y on | // join x in y on a equals | if (token.IsKind(SyntaxKind.OnKeyword) || token.IsKind(SyntaxKind.EqualsKeyword)) { if (token.Parent.IsKind(SyntaxKind.JoinClause)) { return true; } } // where | if (token.IsKind(SyntaxKind.WhereKeyword) && token.Parent.IsKind(SyntaxKind.WhereClause)) { return true; } // orderby | // orderby a, | if (token.IsKind(SyntaxKind.OrderByKeyword) || token.IsKind(SyntaxKind.CommaToken)) { if (token.Parent.IsKind(SyntaxKind.OrderByClause)) { return true; } } // select | if (token.IsKind(SyntaxKind.SelectKeyword) && token.Parent.IsKind(SyntaxKind.SelectClause)) { return true; } // group | // group expr by | if (token.IsKind(SyntaxKind.GroupKeyword) || token.IsKind(SyntaxKind.ByKeyword)) { if (token.Parent.IsKind(SyntaxKind.GroupClause)) { return true; } } // return | // yield return | // but not: [return | if (token.IsKind(SyntaxKind.ReturnKeyword)) { if (token.GetPreviousToken(includeSkipped: true).Kind() != SyntaxKind.OpenBracketToken) { return true; } } // throw | if (token.IsKind(SyntaxKind.ThrowKeyword)) { return true; } // while ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.WhileKeyword)) { return true; } // todo: handle 'for' cases. // using ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.UsingKeyword)) { return true; } // lock ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.LockKeyword)) { return true; } // lock ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.IfKeyword)) { return true; } // switch ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.SwitchKeyword)) { return true; } // checked ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.CheckedKeyword)) { return true; } // unchecked ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.UncheckedKeyword)) { return true; } // when ( | if (token.IsKind(SyntaxKind.OpenParenToken) && token.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.WhenKeyword)) { return true; } // (SomeType) | if (token.IsAfterPossibleCast()) { return true; } // In anonymous type initializer. // // new { | We allow new inside of anonymous object member declarators, so that the user // can dot into a member afterward. For example: // // var a = new { new C().Foo }; if (token.IsKind(SyntaxKind.OpenBraceToken) || token.IsKind(SyntaxKind.CommaToken)) { if (token.Parent.IsKind(SyntaxKind.AnonymousObjectCreationExpression)) { return true; } } // $"{ | // $@"{ | // $"{x} { | // $@"{x} { | if (token.IsKind(SyntaxKind.OpenBraceToken)) { return token.Parent.IsKind(SyntaxKind.Interpolation) && ((InterpolationSyntax)token.Parent).OpenBraceToken == token; } return false; }
ParameterHintingResult HandleInvocationExpression(SemanticModel semanticModel, InvocationExpressionSyntax node, CancellationToken cancellationToken) { var result = new ParameterHintingResult(node.SpanStart); var targetTypeInfo = semanticModel.GetTypeInfo(node.Expression); if (targetTypeInfo.Type != null && targetTypeInfo.Type.TypeKind == TypeKind.Delegate) { result.AddData(factory.CreateMethodDataProvider(targetTypeInfo.Type.GetDelegateInvokeMethod())); return(result); } var within = semanticModel.GetEnclosingNamedTypeOrAssembly(node.SpanStart, cancellationToken); if (within == null) { return(result); } var memberGroup = semanticModel.GetMemberGroup(node.Expression, cancellationToken).OfType <IMethodSymbol> (); var matchedMethodSymbol = semanticModel.GetSymbolInfo(node, cancellationToken).Symbol as IMethodSymbol; // if the symbol could be bound, replace that item in the symbol list if (matchedMethodSymbol != null && matchedMethodSymbol.IsGenericMethod) { memberGroup = memberGroup.Select(m => matchedMethodSymbol.OriginalDefinition == m ? matchedMethodSymbol : m); } ITypeSymbol throughType = null; if (node.Expression is MemberAccessExpressionSyntax) { var throughExpression = ((MemberAccessExpressionSyntax)node.Expression).Expression; var throughSymbol = semanticModel.GetSymbolInfo(throughExpression, cancellationToken).GetAnySymbol(); // if it is via a base expression "base.", we know the "throughType" is the base class but // we need to be able to tell between "base.M()" and "new Base().M()". // currently, Access check methods do not differentiate between them. // so handle "base." primary-expression here by nulling out "throughType" if (!(throughExpression is BaseExpressionSyntax)) { throughType = semanticModel.GetTypeInfo(throughExpression, cancellationToken).Type; } var includeInstance = !throughExpression.IsKind(SyntaxKind.IdentifierName) || semanticModel.LookupSymbols(throughExpression.SpanStart, name: throughSymbol.Name).Any(s => !(s is INamedTypeSymbol)) || (!(throughSymbol is INamespaceOrTypeSymbol) && semanticModel.LookupSymbols(throughExpression.SpanStart, container: throughSymbol.ContainingType).Any(s => !(s is INamedTypeSymbol))); var includeStatic = throughSymbol is INamedTypeSymbol || (throughExpression.IsKind(SyntaxKind.IdentifierName) && semanticModel.LookupNamespacesAndTypes(throughExpression.SpanStart, name: throughSymbol.Name).Any(t => t.GetSymbolType() == throughType)); memberGroup = memberGroup.Where(m => (m.IsStatic && includeStatic) || (!m.IsStatic && includeInstance)); } else if (node.Expression is SimpleNameSyntax && node.IsInStaticContext()) { memberGroup = memberGroup.Where(m => m.IsStatic); } var methodList = memberGroup.Where(member => member.IsAccessibleWithin(within, throughType)).ToList(); memberGroup = methodList.Where(m => !IsHiddenByOtherMethod(m, methodList)); foreach (var member in memberGroup) { result.AddData(factory.CreateMethodDataProvider(member)); } return(result); }
static SignatureHelp CreateMethodGroupSignatureHelp( ExpressionSyntax expression, ArgumentListSyntax argumentList, int position, SemanticModel semanticModel) { var signatureHelp = new SignatureHelp(); // Happens for object initializers with no preceding parens, as soon as user types comma if (argumentList == null) { return(signatureHelp); } int currentArg; if (TryGetCurrentArgumentIndex(argumentList, position, out currentArg)) { signatureHelp.ActiveParameter = currentArg; } var symbolInfo = semanticModel.GetSymbolInfo(expression); var bestGuessMethod = symbolInfo.Symbol as IMethodSymbol; // Include everything by default (global eval context) var includeInstance = true; var includeStatic = true; ITypeSymbol throughType = null; // When accessing method via some member, only show static methods in static context and vice versa for instance methods. // This block based on https://github.com/dotnet/roslyn/blob/3b6536f4a616e5f3b8ede940c63663a828e68b5d/src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider_MethodGroup.cs#L44-L50 if (expression is MemberAccessExpressionSyntax memberAccessExpression) { var throughExpression = (memberAccessExpression).Expression; if (!(throughExpression is BaseExpressionSyntax)) { throughType = semanticModel.GetTypeInfo(throughExpression).Type; } var throughSymbolInfo = semanticModel.GetSymbolInfo(throughExpression); var throughSymbol = throughSymbolInfo.Symbol ?? throughSymbolInfo.CandidateSymbols.FirstOrDefault(); includeInstance = !throughExpression.IsKind(SyntaxKind.IdentifierName) || semanticModel.LookupSymbols(throughExpression.SpanStart, name: throughSymbol.Name).Any(s => !(s is INamedTypeSymbol)) || (!(throughSymbol is INamespaceOrTypeSymbol) && semanticModel.LookupSymbols(throughExpression.SpanStart, throughSymbol.ContainingType).Any(s => !(s is INamedTypeSymbol))); includeStatic = throughSymbol is INamedTypeSymbol || (throughExpression.IsKind(SyntaxKind.IdentifierName) && semanticModel.LookupNamespacesAndTypes(throughExpression.SpanStart, name: throughSymbol.Name).Any(t => t.GetSymbolType() == throughType)); } // TODO: Start taking CT in here? Most calls in this method have optional CT arg. Could make this async. var within = semanticModel.GetEnclosingNamedTypeOrAssembly(position, CancellationToken.None); var methods = semanticModel .GetMemberGroup(expression) .OfType <IMethodSymbol> () .Where(m => (m.IsStatic && includeStatic) || (!m.IsStatic && includeInstance)) .Where(m => m.IsAccessibleWithin(within, throughTypeOpt: throughType)) .ToArray(); var signatures = new List <SignatureInformation> (); for (var i = 0; i < methods.Length; i++) { if (methods [i] == bestGuessMethod) { signatureHelp.ActiveSignature = i; } var signatureInfo = new SignatureInformation(methods [i]); signatures.Add(signatureInfo); } signatureHelp.Signatures = signatures.ToArray(); return(signatureHelp); }