File: Snippets\SnippetProviders\AbstractForLoopSnippetProvider.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Microsoft.CodeAnalysis.Snippets.SnippetProviders;
 
internal abstract class AbstractForLoopSnippetProvider<TStatementSyntax> : AbstractInlineStatementSnippetProvider<TStatementSyntax>
    where TStatementSyntax : SyntaxNode
{
    protected sealed override bool IsValidAccessingType(ITypeSymbol type, Compilation compilation)
    {
        if (IsSuitableIntegerType(type))
        {
            return true;
        }
 
        var hasLengthProperty = FindLengthProperty(type, compilation) is not null;
        var hasCountProperty = FindCountProperty(type, compilation) is not null;
 
        // We want to allow types, which have either `Length` or `Count` property, but not both to avoid ambiguity
        return hasLengthProperty ^ hasCountProperty;
    }
 
    protected static bool IsSuitableIntegerType(ITypeSymbol type)
        => type.IsIntegralType() || type.IsNativeIntegerType;
 
    protected static IPropertySymbol? FindLengthProperty(ITypeSymbol type, Compilation compilation)
        => FindAccessibleIntegerProperty(type, compilation, "Length");
 
    protected static IPropertySymbol? FindCountProperty(ITypeSymbol type, Compilation compilation)
        => FindAccessibleIntegerProperty(type, compilation, "Count");
 
    private static IPropertySymbol? FindAccessibleIntegerProperty(ITypeSymbol type, Compilation compilation, string propertyName)
    {
        return type
            .GetAccessibleMembersInThisAndBaseTypes<IPropertySymbol>(propertyName, compilation.Assembly)
            .FirstOrDefault(p => p is { GetMethod: { } getMethod } && getMethod.IsAccessibleWithin(compilation.Assembly) && IsSuitableIntegerType(p.Type));
    }
}