public static bool IsPotentialTypeName(this TypeSyntax typeSyntax, SemanticModel semanticModelOpt, CancellationToken cancellationToken) { if (typeSyntax == null) { return false; } if (typeSyntax is PredefinedTypeSyntax || typeSyntax is ArrayTypeSyntax || typeSyntax is GenericNameSyntax || typeSyntax is PointerTypeSyntax || typeSyntax is NullableTypeSyntax) { return true; } if (semanticModelOpt == null) { return false; } var nameSyntax = typeSyntax as NameSyntax; if (nameSyntax == null) { return false; } var nameToken = nameSyntax.GetNameToken(); var symbols = semanticModelOpt.LookupName(nameToken, namespacesAndTypesOnly: true, cancellationToken: cancellationToken); var firstSymbol = symbols.FirstOrDefault(); var typeSymbol = firstSymbol != null && firstSymbol.Kind == SymbolKind.Alias ? (firstSymbol as IAliasSymbol).Target : firstSymbol as ITypeSymbol; return typeSymbol != null && !typeSymbol.IsErrorType(); }
public static bool IsGenericTypeArgumentContext( this SyntaxTree syntaxTree, int position, SyntaxToken tokenOnLeftOfPosition, CancellationToken cancellationToken, SemanticModel semanticModelOpt = null) { // cases: // Foo<| // Foo<Bar,| // Foo<Bar<Baz<int[],| var token = tokenOnLeftOfPosition; token = token.GetPreviousTokenIfTouchingWord(position); if (token.Kind() != SyntaxKind.LessThanToken && token.Kind() != SyntaxKind.CommaToken) { return false; } if (token.Parent is TypeArgumentListSyntax) { // Easy case, it was known to be a generic name, so this is a type argument context. return true; } SyntaxToken nameToken; if (!syntaxTree.IsInPartiallyWrittenGeneric(position, cancellationToken, out nameToken)) { return false; } var name = nameToken.Parent as NameSyntax; if (name == null) { return false; } // Looks viable! If they provided a binding, then check if it binds properly to // an actual generic entity. if (semanticModelOpt == null) { // No binding. Just make the decision based on the syntax tree. return true; } // '?' is syntactically ambiguous in incomplete top-level statements: // // T ? foo<| // // Might be an incomplete conditional expression or an incomplete declaration of a method returning a nullable type. // Bind T to see if it is a type. If it is we don't show signature help. if (name.IsParentKind(SyntaxKind.LessThanExpression) && name.Parent.IsParentKind(SyntaxKind.ConditionalExpression) && name.Parent.Parent.IsParentKind(SyntaxKind.ExpressionStatement) && name.Parent.Parent.Parent.IsParentKind(SyntaxKind.GlobalStatement)) { var conditionOrType = semanticModelOpt.GetSymbolInfo( ((ConditionalExpressionSyntax)name.Parent.Parent).Condition, cancellationToken); if (conditionOrType.GetBestOrAllSymbols().FirstOrDefault() != null && conditionOrType.GetBestOrAllSymbols().FirstOrDefault().Kind == SymbolKind.NamedType) { return false; } } var symbols = semanticModelOpt.LookupName(nameToken, namespacesAndTypesOnly: SyntaxFacts.IsInNamespaceOrTypeContext(name), cancellationToken: cancellationToken); return symbols.Any(s => s.TypeSwitch( (INamedTypeSymbol nt) => nt.Arity > 0, (IMethodSymbol m) => m.Arity > 0)); }