|
// 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;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Shared.Extensions;
internal static partial class INamespaceOrTypeSymbolExtensions
{
private static readonly ConditionalWeakTable<INamespaceOrTypeSymbol, List<string>> s_namespaceOrTypeToNameMap = new();
private static readonly SymbolDisplayFormat s_shortNameFormat = new(
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes | SymbolDisplayMiscellaneousOptions.ExpandNullable);
public static string GetShortName(this INamespaceOrTypeSymbol symbol)
=> symbol.ToDisplayString(s_shortNameFormat);
public static IEnumerable<IPropertySymbol> GetIndexers(this INamespaceOrTypeSymbol? symbol)
{
return symbol == null
? []
: symbol.GetMembers(WellKnownMemberNames.Indexer).OfType<IPropertySymbol>().Where(p => p.IsIndexer);
}
public static IReadOnlyList<string> GetNameParts(this INamespaceOrTypeSymbol symbol)
=> s_namespaceOrTypeToNameMap.GetValue(symbol, static symbol =>
{
var result = new List<string>();
GetNameParts(symbol, result);
return result;
});
public static int CompareNameParts(
IReadOnlyList<string> names1, IReadOnlyList<string> names2,
bool placeSystemNamespaceFirst)
{
for (var i = 0; i < Math.Min(names1.Count, names2.Count); i++)
{
var name1 = names1[i];
var name2 = names2[i];
if (i == 0 && placeSystemNamespaceFirst)
{
var name1IsSystem = name1 == nameof(System);
var name2IsSystem = name2 == nameof(System);
if (name1IsSystem && !name2IsSystem)
{
return -1;
}
else if (!name1IsSystem && name2IsSystem)
{
return 1;
}
}
var comp = name1.CompareTo(name2);
if (comp != 0)
{
return comp;
}
}
return names1.Count - names2.Count;
}
private static void GetNameParts(INamespaceOrTypeSymbol? namespaceOrTypeSymbol, List<string> result)
{
if (namespaceOrTypeSymbol == null || (namespaceOrTypeSymbol.IsNamespace && ((INamespaceSymbol)namespaceOrTypeSymbol).IsGlobalNamespace))
{
return;
}
GetNameParts(namespaceOrTypeSymbol.ContainingNamespace, result);
result.Add(namespaceOrTypeSymbol.Name);
}
/// <summary>
/// Lazily returns all nested types contained (recursively) within this namespace or type.
/// In case of a type, it is included itself as the first result.
/// </summary>
public static IEnumerable<INamedTypeSymbol> GetAllTypes(
this INamespaceOrTypeSymbol namespaceOrTypeSymbol,
CancellationToken cancellationToken)
{
using var _ = ArrayBuilder<INamespaceOrTypeSymbol>.GetInstance(out var stack);
stack.Push(namespaceOrTypeSymbol);
while (stack.TryPop(out var current))
{
cancellationToken.ThrowIfCancellationRequested();
if (current is INamespaceSymbol currentNs)
{
stack.AddRange(currentNs.GetMembers());
}
else
{
var namedType = (INamedTypeSymbol)current;
stack.AddRange(namedType.GetTypeMembers());
yield return namedType;
}
}
}
}
|