Create a generic type to find implementations in the Resharper plugin

I'm writing a plugin for resharper, which I want to use to move from ConcreteCommand

ConcreteCommandHandler

, where these types of look like

public class ConcreteCommand : ICommand

public class ConcreteCommandHandler : ICommandHandler<ConcreteCommand>

      

I have before how to add a navigation menu item when the cursor is in the instance / definition ICommand

(currently only checking if it contains the name "Command" and not "CommandHandler") and I think I have some code, needed to actually search for a type that inherits something, but my problem is that the only thing I actually have is mine ConcereteCommand

and I need to create (or get a reference) a generic type ICommandHandler<T>

with T

is the type in which in the cursor is currently located.

So, I have 2 things that I still want to know:

  • How can I check if my IDeclaredElement

    implementation is a specific interface (ideally by specifying the fully qualified name on a line from config)?
  • How do I create ITypeElement

    which is the typical type of a specific interface where I can set the generic type from my existing type IDeclaredElement

    so I can then find classes that inherit that?

My existing code looks like this:

[ContextNavigationProvider]
public class CommandHandlerNavigationProvider : INavigateFromHereProvider
{
    public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
    {
        ICollection<IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
        if (declaredElements != null || declaredElements.Any())
        {
            IDeclaredElement declaredElement = declaredElements.First();

            if (IsCommand(declaredElement))
            {
                var solution = dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
                yield return new ContextNavigation("This Command &handler", null, NavigationActionGroup.Other, () => { GotToInheritor(solution,declaredElement); });
            }
        }
    }

    private void GotToInheritor(ISolution solution, IDeclaredElement declaredElement)
    {            
        var inheritorsConsumer = new InheritorsConsumer();
        SearchDomainFactory searchDomainFactory = solution.GetComponent<SearchDomainFactory>();
//How can I create the ITypeElement MyNameSpace.ICommandHandler<(ITypeElement)declaredElement> here?  
      solution.GetPsiServices().Finder.FindInheritors((ITypeElement)declaredElement, searchDomainFactory.CreateSearchDomain(solution, true),                    inheritorsConsumer, NullProgressIndicator.Instance);
    }

    private bool IsCommand(IDeclaredElement declaredElement)
    {
//How can I check if my declaredElement is an implementation of ICommand here?
        string className = declaredElement.ShortName;
        return className.Contains("Command")
               && !className.Contains("CommandHandler");
    }
}

      

+3


source to share


1 answer


Ok managed to handle this with an honest heading in the right direction from @CitizenMatt.

basically my solution looks like this (still needs a little tidying up)



private static readonly List<HandlerMapping> HandlerMappings = new List<HandlerMapping>
{
    new HandlerMapping("HandlerNavigationTest.ICommand", "HandlerNavigationTest.ICommandHandler`1", "HandlerNavigationTest"),
    new HandlerMapping("HandlerNavTest2.IEvent", "HandlerNavTest2.IEventHandler`1", "HandlerNavTest2")
};

public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
{
    ICollection<IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
    if (declaredElements != null && declaredElements.Any())
    {
        IDeclaredElement declaredElement = declaredElements.First();

        ISolution solution = dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
        ITypeElement handlerType = GetHandlerType(declaredElement);
        if (handlerType != null)
        {
            yield return new ContextNavigation("&Handler", null, NavigationActionGroup.Other, () => GoToInheritor(solution, declaredElement as IClass, dataContext, handlerType));
        }
    }
}

private static ITypeElement GetHandlerType(IDeclaredElement declaredElement)
{
    var theClass = declaredElement as IClass;
    if (theClass != null)
    {
        foreach (IPsiModule psiModule in declaredElement.GetPsiServices().Modules.GetModules())
        {
            foreach (var handlerMapping in HandlerMappings)
            {
                IDeclaredType commandInterfaceType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandledType, psiModule, theClass.ResolveContext);

                ITypeElement typeElement = commandInterfaceType.GetTypeElement();
                if (typeElement != null)
                {
                    if (theClass.IsDescendantOf(typeElement))
                    {
                        IDeclaredType genericType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandlerType, psiModule, theClass.ResolveContext);
                        ITypeElement genericTypeElement = genericType.GetTypeElement();
                        return genericTypeElement;
                    }
                }
            }

        }
    }

    return null;
}

private static void GoToInheritor(ISolution solution, IClass theClass, IDataContext dataContext, ITypeElement genericHandlerType)
{
    var inheritorsConsumer = new InheritorsConsumer();
    var searchDomainFactory = solution.GetComponent<SearchDomainFactory>();

    IDeclaredType theType = TypeFactory.CreateType(theClass);
    IDeclaredType commandHandlerType = TypeFactory.CreateType(genericHandlerType, theType);
    ITypeElement handlerTypeelement = commandHandlerType.GetTypeElement();
    solution.GetPsiServices().Finder.FindInheritors(handlerTypeelement, searchDomainFactory.CreateSearchDomain(solution, true),
        inheritorsConsumer, NullProgressIndicator.Instance);
    var potentialNavigationPoints = new List<INavigationPoint>();
    foreach (ITypeElement inheritedInstance in inheritorsConsumer.FoundElements)
    {
        IDeclaredType[] baseClasses = inheritedInstance.GetAllSuperTypes();
        foreach (IDeclaredType declaredType in baseClasses)
        {
            if (declaredType.IsInterfaceType())
            {
                if (declaredType.Equals(commandHandlerType))
                {
                    var navigationPoint = new DeclaredElementNavigationPoint(inheritedInstance);
                    potentialNavigationPoints.Add(navigationPoint);
                }
            }
        }
    }

    if (potentialNavigationPoints.Any())
    {
        NavigationOptions options = NavigationOptions.FromDataContext(dataContext, "Which handler do you want to navigate to?");
        NavigationManager.GetInstance(solution).Navigate(potentialNavigationPoints, options);
    }
} 

public class InheritorsConsumer : IFindResultConsumer<ITypeElement>
{
    private const int MaxInheritors = 50;

    private readonly HashSet<ITypeElement> elements = new HashSet<ITypeElement>();

    public IEnumerable<ITypeElement> FoundElements
    {
        get { return elements; }
    } 

    public ITypeElement Build(FindResult result)
    {
        var inheritedElement = result as FindResultInheritedElement;
        if (inheritedElement != null)
            return (ITypeElement) inheritedElement.DeclaredElement;
        return null;
    }

    public FindExecution Merge(ITypeElement data)
    {
        elements.Add(data);
        return elements.Count < MaxInheritors ? FindExecution.Continue : FindExecution.Stop;
    }
}

      

And that prevents me from navigating multiple handlers if they exist. It currently depends on the interfaces for the processed type and the handler type being in the same assembly. But that seems reasonable enough to me at the moment.

+1


source







All Articles