EnvDTE.Host/Callback/Impl/AstImpl/CodeElementCallbackProviderBase.cs (112 lines of code) (raw):

using System; using System.Linq; using JetBrains.Annotations; using JetBrains.Collections.Viewable; using JetBrains.EnvDTE.Host.Callback.Util; using JetBrains.EnvDTE.Host.Manager; using JetBrains.Rd.Tasks; using JetBrains.RdBackend.Common.Features.ProjectModel.View; using JetBrains.ReSharper.Psi; using JetBrains.ReSharper.Psi.CSharp.Tree; using JetBrains.ReSharper.Psi.Tree; using JetBrains.ReSharper.Psi.Util; using JetBrains.ReSharper.Resources.Shell; using JetBrains.Rider.Model; using JetBrains.Util; namespace JetBrains.EnvDTE.Host.Callback.Impl.AstImpl { public abstract class CodeElementCallbackProviderBase( AstManager astManager, ProjectModelViewHost host) : IEnvDteCallbackProvider { [NotNull] private ILogger Logger { get; } = JetBrains.Util.Logging.Logger.GetLogger<CodeElementCallbackProvider>(); public void RegisterCallbacks(DteProtocolModel model, IScheduler scheduler) { DoRegisterCallbacks(host, model); } protected abstract void DoRegisterCallbacks( [NotNull] ProjectModelViewHost host, [NotNull] DteProtocolModel model ); [NotNull] protected CodeElementModel CreateNamespaceModel([NotNull] ICSharpTypeDeclaration declaration) { var ns = declaration.OwnerNamespaceDeclaration; int id = astManager.GetOrCreateId(ns); int typeId = PsiElementRegistrar.GetTypeId(ns); return new CodeElementModel(typeId, id); } protected void MapWithAstManager<TRes>( [NotNull] IRdEndpoint<CodeElementModel, TRes> ep, [NotNull] Func<ITreeNode, TRes> psiMapper, [NotNull] Func<IDeclaredElement, TRes> declaredElementMapper, [NotNull] Func<IType, TRes> typeMapper ) => MapWithAstManager<ITreeNode, IDeclaredElement, TRes>(ep, psiMapper, declaredElementMapper, typeMapper); protected void MapWithAstManager<TNode, TElement, TRes>( [NotNull] IRdEndpoint<CodeElementModel, TRes> ep, [NotNull] Func<TNode, TRes> psiMapper, [NotNull] Func<TElement, TRes> declaredElementMapper, [NotNull] Func<IArrayType, TRes> typeMapper ) where TNode : ITreeNode where TElement : IDeclaredElement => ep.SetAsync((lifetime, model) => lifetime.StartReadActionAsync(() => astManager.MapElement( model.Id, psiMapper, declaredElementMapper, typeMapper ))); // More type-safe and change-resistant and less error-prone than the usual switch [CanBeNull] protected static TResult Switch<TResult>( [NotNull] IDeclaredElement element, Func<INamespace, TResult> namespaceMapper, Func<ITypeElement, TResult> typeMapper, Func<IFunction, TResult> functionMapper ) => element switch { INamespace ns => namespaceMapper(ns), ITypeElement type => typeMapper(type), IFunction function => functionMapper(function), _ => default }; [NotNull] protected CodeElementModel CreateCodeElementModel([NotNull] ITreeNode node) { int childId = astManager.GetOrCreateId(node); int childTypeId = PsiElementRegistrar.GetTypeId(node); return new CodeElementModel(childTypeId, childId); } [CanBeNull] protected CodeElementModel ToModel([NotNull] IDeclaredElement typeElement) { var declarations = typeElement.GetDeclarations(); if (declarations.IsEmpty()) { int id = astManager.GetOrCreateId(typeElement); int typeId = PsiElementRegistrar.GetTypeId(typeElement); return new CodeElementModel(typeId, id); } if (declarations.IsSingle()) { var declaration = declarations.Single(); int id = astManager.GetOrCreateId(declaration); int typeId = PsiElementRegistrar.GetTypeId(declaration); return new CodeElementModel(typeId, id); } Logger.Warn("Failed to create a model for base class because it resides in multiple locations"); return null; } [CanBeNull] protected CodeElementModel ToModel([NotNull] IType type) { var element = type.GetTypeElement(); if (element != null) return ToModel(element); int id = astManager.GetOrCreateId((IArrayType)type); return new CodeElementModel(PsiElementRegistrar.ClassDeclarationId, id); } } }