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));
        }