367 lines
12 KiB
C#
367 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using Microsoft.CodeAnalysis.Collections;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal sealed class DeclarationTable
|
|
{
|
|
private class Cache
|
|
{
|
|
private readonly DeclarationTable _table;
|
|
|
|
private MergedNamespaceDeclaration? _mergedRoot;
|
|
|
|
private ISet<string>? _typeNames;
|
|
|
|
private ISet<string>? _namespaceNames;
|
|
|
|
private ImmutableArray<ReferenceDirective> _referenceDirectives;
|
|
|
|
public MergedNamespaceDeclaration MergedRoot
|
|
{
|
|
get
|
|
{
|
|
if (_mergedRoot == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _mergedRoot, MergedNamespaceDeclaration.Create(ImmutableArrayExtensions.AsImmutable<SingleNamespaceDeclaration>((IEnumerable<SingleNamespaceDeclaration>)_table._allOlderRootDeclarations.InInsertionOrder.Select((Lazy<RootSingleNamespaceDeclaration> lazyRoot) => lazyRoot.Value))), null);
|
|
}
|
|
return _mergedRoot;
|
|
}
|
|
}
|
|
|
|
public ISet<string> TypeNames
|
|
{
|
|
get
|
|
{
|
|
if (_typeNames == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _typeNames, GetTypeNames(MergedRoot), null);
|
|
}
|
|
return _typeNames;
|
|
}
|
|
}
|
|
|
|
public ISet<string> NamespaceNames
|
|
{
|
|
get
|
|
{
|
|
if (_namespaceNames == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _namespaceNames, GetNamespaceNames(MergedRoot), null);
|
|
}
|
|
return _namespaceNames;
|
|
}
|
|
}
|
|
|
|
public ImmutableArray<ReferenceDirective> ReferenceDirectives
|
|
{
|
|
get
|
|
{
|
|
if (_referenceDirectives.IsDefault)
|
|
{
|
|
ImmutableInterlocked.InterlockedInitialize(ref _referenceDirectives, ImmutableArrayExtensions.AsImmutable<ReferenceDirective>(MergedRoot.Declarations.OfType<RootSingleNamespaceDeclaration>().SelectMany((RootSingleNamespaceDeclaration r) => r.ReferenceDirectives)));
|
|
}
|
|
return _referenceDirectives;
|
|
}
|
|
}
|
|
|
|
public Cache(DeclarationTable table)
|
|
{
|
|
_table = table;
|
|
}
|
|
}
|
|
|
|
private sealed class RootNamespaceLocationComparer : IComparer<SingleNamespaceDeclaration>
|
|
{
|
|
private readonly CSharpCompilation _compilation;
|
|
|
|
internal RootNamespaceLocationComparer(CSharpCompilation compilation)
|
|
{
|
|
_compilation = compilation;
|
|
}
|
|
|
|
public int Compare(SingleNamespaceDeclaration? x, SingleNamespaceDeclaration? y)
|
|
{
|
|
return ((Compilation)_compilation).CompareSourceLocations(x.SyntaxReference, y.SyntaxReference);
|
|
}
|
|
}
|
|
|
|
public static readonly DeclarationTable Empty = new DeclarationTable(ImmutableSetWithInsertionOrder<Lazy<RootSingleNamespaceDeclaration>>.Empty, null, null);
|
|
|
|
private readonly ImmutableSetWithInsertionOrder<Lazy<RootSingleNamespaceDeclaration>> _allOlderRootDeclarations;
|
|
|
|
private readonly Lazy<RootSingleNamespaceDeclaration>? _latestLazyRootDeclaration;
|
|
|
|
private readonly Cache _cache;
|
|
|
|
private MergedNamespaceDeclaration? _mergedRoot;
|
|
|
|
private ICollection<string>? _typeNames;
|
|
|
|
private ICollection<string>? _namespaceNames;
|
|
|
|
private ICollection<ReferenceDirective>? _referenceDirectives;
|
|
|
|
private static readonly Predicate<Declaration> s_isNamespacePredicate = (Declaration d) => d.Kind == DeclarationKind.Namespace;
|
|
|
|
private static readonly Predicate<Declaration> s_isTypePredicate = (Declaration d) => d.Kind != DeclarationKind.Namespace;
|
|
|
|
public ICollection<string> TypeNames
|
|
{
|
|
get
|
|
{
|
|
if (_typeNames == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _typeNames, GetMergedTypeNames(), null);
|
|
}
|
|
return _typeNames;
|
|
}
|
|
}
|
|
|
|
public ICollection<string> NamespaceNames
|
|
{
|
|
get
|
|
{
|
|
if (_namespaceNames == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _namespaceNames, GetMergedNamespaceNames(), null);
|
|
}
|
|
return _namespaceNames;
|
|
}
|
|
}
|
|
|
|
public IEnumerable<ReferenceDirective> ReferenceDirectives
|
|
{
|
|
get
|
|
{
|
|
if (_referenceDirectives == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _referenceDirectives, GetMergedReferenceDirectives(), null);
|
|
}
|
|
return _referenceDirectives;
|
|
}
|
|
}
|
|
|
|
private DeclarationTable(ImmutableSetWithInsertionOrder<Lazy<RootSingleNamespaceDeclaration>> allOlderRootDeclarations, Lazy<RootSingleNamespaceDeclaration>? latestLazyRootDeclaration, Cache? cache)
|
|
{
|
|
_allOlderRootDeclarations = allOlderRootDeclarations;
|
|
_latestLazyRootDeclaration = latestLazyRootDeclaration;
|
|
_cache = cache ?? new Cache(this);
|
|
}
|
|
|
|
public DeclarationTable AddRootDeclaration(Lazy<RootSingleNamespaceDeclaration> lazyRootDeclaration)
|
|
{
|
|
if (_latestLazyRootDeclaration == null)
|
|
{
|
|
return new DeclarationTable(_allOlderRootDeclarations, lazyRootDeclaration, _cache);
|
|
}
|
|
return new DeclarationTable(_allOlderRootDeclarations.Add(_latestLazyRootDeclaration), lazyRootDeclaration, null);
|
|
}
|
|
|
|
public DeclarationTable RemoveRootDeclaration(Lazy<RootSingleNamespaceDeclaration> lazyRootDeclaration)
|
|
{
|
|
if (_latestLazyRootDeclaration == lazyRootDeclaration)
|
|
{
|
|
return new DeclarationTable(_allOlderRootDeclarations, null, _cache);
|
|
}
|
|
return new DeclarationTable(_allOlderRootDeclarations.Remove(lazyRootDeclaration), _latestLazyRootDeclaration, null);
|
|
}
|
|
|
|
public MergedNamespaceDeclaration GetMergedRoot(CSharpCompilation compilation)
|
|
{
|
|
if (_mergedRoot == null)
|
|
{
|
|
Interlocked.CompareExchange(ref _mergedRoot, CalculateMergedRoot(compilation), null);
|
|
}
|
|
return _mergedRoot;
|
|
}
|
|
|
|
internal MergedNamespaceDeclaration CalculateMergedRoot(CSharpCompilation compilation)
|
|
{
|
|
MergedNamespaceDeclaration mergedRoot = _cache.MergedRoot;
|
|
if (_latestLazyRootDeclaration == null)
|
|
{
|
|
return mergedRoot;
|
|
}
|
|
if (mergedRoot == null)
|
|
{
|
|
return MergedNamespaceDeclaration.Create(_latestLazyRootDeclaration.Value);
|
|
}
|
|
ImmutableArray<SingleNamespaceDeclaration> declarations = mergedRoot.Declarations;
|
|
ArrayBuilder<SingleNamespaceDeclaration> instance = ArrayBuilder<SingleNamespaceDeclaration>.GetInstance(declarations.Length + 1);
|
|
instance.AddRange(declarations);
|
|
instance.Add((SingleNamespaceDeclaration)_latestLazyRootDeclaration.Value);
|
|
if (compilation != null)
|
|
{
|
|
instance.Sort((IComparer<SingleNamespaceDeclaration>)new RootNamespaceLocationComparer(compilation));
|
|
}
|
|
return MergedNamespaceDeclaration.Create(instance.ToImmutableAndFree());
|
|
}
|
|
|
|
private ICollection<string> GetMergedTypeNames()
|
|
{
|
|
ISet<string> typeNames = _cache.TypeNames;
|
|
if (_latestLazyRootDeclaration == null)
|
|
{
|
|
return typeNames;
|
|
}
|
|
return UnionCollection<string>.Create((ICollection<string>)typeNames, (ICollection<string>)GetTypeNames(_latestLazyRootDeclaration.Value));
|
|
}
|
|
|
|
private ICollection<string> GetMergedNamespaceNames()
|
|
{
|
|
ISet<string> namespaceNames = _cache.NamespaceNames;
|
|
if (_latestLazyRootDeclaration == null)
|
|
{
|
|
return namespaceNames;
|
|
}
|
|
return UnionCollection<string>.Create((ICollection<string>)namespaceNames, (ICollection<string>)GetNamespaceNames(_latestLazyRootDeclaration.Value));
|
|
}
|
|
|
|
private ICollection<ReferenceDirective> GetMergedReferenceDirectives()
|
|
{
|
|
ImmutableArray<ReferenceDirective> referenceDirectives = _cache.ReferenceDirectives;
|
|
if (_latestLazyRootDeclaration == null)
|
|
{
|
|
return referenceDirectives;
|
|
}
|
|
return UnionCollection<ReferenceDirective>.Create((ICollection<ReferenceDirective>)referenceDirectives, (ICollection<ReferenceDirective>)_latestLazyRootDeclaration.Value.ReferenceDirectives);
|
|
}
|
|
|
|
private static ISet<string> GetTypeNames(Declaration declaration)
|
|
{
|
|
return GetNames(declaration, s_isTypePredicate);
|
|
}
|
|
|
|
private static ISet<string> GetNamespaceNames(Declaration declaration)
|
|
{
|
|
return GetNames(declaration, s_isNamespacePredicate);
|
|
}
|
|
|
|
private static ISet<string> GetNames(Declaration declaration, Predicate<Declaration> predicate)
|
|
{
|
|
HashSet<string> hashSet = new HashSet<string>();
|
|
Stack<Declaration> stack = new Stack<Declaration>();
|
|
stack.Push(declaration);
|
|
while (stack.Count > 0)
|
|
{
|
|
Declaration declaration2 = stack.Pop();
|
|
if (declaration2 != null)
|
|
{
|
|
if (predicate(declaration2))
|
|
{
|
|
hashSet.Add(declaration2.Name);
|
|
}
|
|
ImmutableArray<Declaration>.Enumerator enumerator = declaration2.Children.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
Declaration current = enumerator.Current;
|
|
stack.Push(current);
|
|
}
|
|
}
|
|
}
|
|
return SpecializedCollections.ReadOnlySet<string>((ISet<string>)hashSet);
|
|
}
|
|
|
|
public static bool ContainsName(MergedNamespaceDeclaration mergedRoot, string name, SymbolFilter filter, CancellationToken cancellationToken)
|
|
{
|
|
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
|
|
return ContainsNameHelper(mergedRoot, (string n) => n == name, filter, (SingleTypeDeclaration t) => t.MemberNames.Value.Contains(name), cancellationToken);
|
|
}
|
|
|
|
public static bool ContainsName(MergedNamespaceDeclaration mergedRoot, Func<string, bool> predicate, SymbolFilter filter, CancellationToken cancellationToken)
|
|
{
|
|
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
|
|
return ContainsNameHelper(mergedRoot, predicate, filter, delegate(SingleTypeDeclaration t)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
|
|
Enumerator<string> enumerator = t.MemberNames.Value.GetEnumerator();
|
|
try
|
|
{
|
|
while (enumerator.MoveNext())
|
|
{
|
|
string current = enumerator.Current;
|
|
if (predicate(current))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
((IDisposable)enumerator/*cast due to constrained. prefix*/).Dispose();
|
|
}
|
|
return false;
|
|
}, cancellationToken);
|
|
}
|
|
|
|
private static bool ContainsNameHelper(MergedNamespaceDeclaration mergedRoot, Func<string, bool> predicate, SymbolFilter filter, Func<SingleTypeDeclaration, bool> typePredicate, CancellationToken cancellationToken)
|
|
{
|
|
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0004: Invalid comparison between Unknown and I4
|
|
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000b: Invalid comparison between Unknown and I4
|
|
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0012: Invalid comparison between Unknown and I4
|
|
bool flag = (filter & 1) == 1;
|
|
bool flag2 = (filter & 2) == 2;
|
|
bool flag3 = (filter & 4) == 4;
|
|
Stack<MergedNamespaceOrTypeDeclaration> stack = new Stack<MergedNamespaceOrTypeDeclaration>();
|
|
stack.Push(mergedRoot);
|
|
while (stack.Count > 0)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
MergedNamespaceOrTypeDeclaration mergedNamespaceOrTypeDeclaration = stack.Pop();
|
|
if (mergedNamespaceOrTypeDeclaration == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (mergedNamespaceOrTypeDeclaration.Kind == DeclarationKind.Namespace)
|
|
{
|
|
if (flag && predicate(mergedNamespaceOrTypeDeclaration.Name))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flag2 && predicate(mergedNamespaceOrTypeDeclaration.Name))
|
|
{
|
|
return true;
|
|
}
|
|
if (flag3)
|
|
{
|
|
ImmutableArray<SingleTypeDeclaration>.Enumerator enumerator = ((MergedTypeDeclaration)mergedNamespaceOrTypeDeclaration).Declarations.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
SingleTypeDeclaration current = enumerator.Current;
|
|
if (typePredicate(current))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ImmutableArray<Declaration>.Enumerator enumerator2 = mergedNamespaceOrTypeDeclaration.Children.GetEnumerator();
|
|
while (enumerator2.MoveNext())
|
|
{
|
|
if (enumerator2.Current is MergedNamespaceOrTypeDeclaration mergedNamespaceOrTypeDeclaration2 && (flag3 || flag2 || mergedNamespaceOrTypeDeclaration2.Kind == DeclarationKind.Namespace))
|
|
{
|
|
stack.Push(mergedNamespaceOrTypeDeclaration2);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|