EnvDTE.Host/Manager/AstManager.cs (56 lines of code) (raw):
using System;
using JetBrains.Annotations;
using JetBrains.Application.Parts;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Tree;
namespace JetBrains.EnvDTE.Host.Manager
{
/// <summary>
/// Maintains the ids to be used in protocol AST
/// </summary>
[SolutionComponent(Instantiation.DemandAnyThreadSafe)]
public class AstManager
{
[NotNull]
private AstContainer<IDeclaredElement> DetachedAstContainer { get; }
[NotNull]
private AstContainer<ITreeNode> PsiContainer { get; }
[NotNull]
private AstContainer<IArrayType> TypeContainer { get; }
public AstManager()
{
var source = new IdSource();
DetachedAstContainer = new AstContainer<IDeclaredElement>(source);
PsiContainer = new AstContainer<ITreeNode>(source);
TypeContainer = new AstContainer<IArrayType>(source);
}
[NotNull]
public TResult MapElement<TNode, TElement, TResult>(
int id,
[NotNull] Func<TNode, TResult> psiMapper,
[NotNull] Func<TElement, TResult> declaredElementMapper,
[NotNull] Func<IArrayType, TResult> typeMapper
)
where TNode : ITreeNode
where TElement : IDeclaredElement =>
TryMapWith(id, PsiContainer, psiMapper)
?? TryMapWith(id, DetachedAstContainer, declaredElementMapper)
?? TryMapWith(id, TypeContainer, typeMapper)
?? throw new InvalidOperationException($"Attempted to map non-existing element with id {id}");
[CanBeNull]
private static TResult TryMapWith<TNode, TBaseNode, TResult>(
int id,
[NotNull] AstContainer<TBaseNode> container,
[NotNull] Func<TNode, TResult> mapper
)
where TNode : TBaseNode
where TBaseNode : class
{
var node = container.TryGetElement(id);
if (node == null) return default;
if (node is TNode correct) return mapper(correct);
throw new InvalidOperationException($"Wrong node type. Expected {typeof(TNode)}, actual {node.GetType()}");
}
public int GetOrCreateId([NotNull] ITreeNode node) => PsiContainer.GetOrCreateId(node);
public int GetOrCreateId([NotNull] IDeclaredElement element) => DetachedAstContainer.GetOrCreateId(element);
public int GetOrCreateId([NotNull] IArrayType type) => TypeContainer.GetOrCreateId(type);
}
}