patterncsharpMinor
GoTo Implementation: First-class navigation for the VBE
Viewed 0 times
thenavigationfirstgotoforvbeimplementationclass
Problem
ReSharper has a very handy feature that's particularly useful when coding against abstractions. Since coding against abstractions is something that can also be done in VBA, the next release of rubberduck is going to include that functionality as well:
The click handler for the code pane context menu simply calls the paremeterless overload of
There's also a public overload that takes a
```
public void FindAllImplementations(Declaration target)
{
The click handler for the code pane context menu simply calls the paremeterless overload of
FindAllImplementations:private void _findAllImplementationsContextMenu_Click(CommandBarButton Ctrl, ref bool CancelDefault)
{
FindAllImplementations();
}
private void FindAllImplementations()
{
var selection = IDE.ActiveCodePane.GetSelection();
var progress = new ParsingProgressPresenter();
var parseResult = progress.Parse(_parser, IDE.ActiveVBProject);
var implementsStatement = parseResult.Declarations.FindInterfaces()
.SelectMany(i => i.References.Where(reference => reference.Context.Parent is VBAParser.ImplementsStmtContext))
.SingleOrDefault(r => r.QualifiedModuleName == selection.QualifiedName && r.Selection.Contains(selection.Selection));
if (implementsStatement != null)
{
FindAllImplementations(implementsStatement.Declaration, parseResult);
}
var member = parseResult.Declarations.FindInterfaceImplementationMembers()
.SingleOrDefault(m => m.Selection.Contains(selection.Selection));
if (member == null)
{
member = parseResult.Declarations.FindInterfaceMembers()
.SingleOrDefault(m => m.Project == selection.QualifiedName.Project
&& m.ComponentName == selection.QualifiedName.ComponentName
&& m.Selection.Contains(selection.Selection));
}
if (member == null)
{
return;
}
FindAllImplementations(member, parseResult);
}There's also a public overload that takes a
Declaration target, so that the functionality can be used from the Code Explorer's own context menu:```
public void FindAllImplementations(Declaration target)
{
Solution
var member = parseResult.Declarations.FindInterfaceImplementationMembers()
.SingleOrDefault(m => m.Selection.Contains(selection.Selection));
if (member == null)
{
member = parseResult.Declarations.FindInterfaceMembers()
.SingleOrDefault(m => m.Project == selection.QualifiedName.Project
&& m.ComponentName == selection.QualifiedName.ComponentName
&& m.Selection.Contains(selection.Selection));
}This has a crash-causing bug. You need to change the top
.SingleOrDefault() to match the bottom one.Right here, you need to ensure the members are of the same interface - not just have the same name:
if (isInterface)
{
return parseResult.Declarations.FindInterfaceImplementationMembers(target.IdentifierName);
}
var member = parseResult.Declarations.FindInterfaceMember(target);
return parseResult.Declarations.FindInterfaceImplementationMembers(member.IdentifierName);Otherwise, you return all the
IClass2_DoSomethings along with the IClass1_DoSomethings.A simple
.Where() will fix it:if (isInterface)
{
return parseResult.Declarations.FindInterfaceImplementationMembers(target.IdentifierName)
.Where(item => item.IdentifierName == target.ComponentName + "_" + target.IdentifierName);
}
var member = parseResult.Declarations.FindInterfaceMember(target);
return parseResult.Declarations.FindInterfaceImplementationMembers(member.IdentifierName)
.Where(item => item.IdentifierName == member.ComponentName + "_" + member.IdentifierName);Thanks for helping me develop patches for these problems, @Mat's Mug
Code Snippets
var member = parseResult.Declarations.FindInterfaceImplementationMembers()
.SingleOrDefault(m => m.Selection.Contains(selection.Selection));
if (member == null)
{
member = parseResult.Declarations.FindInterfaceMembers()
.SingleOrDefault(m => m.Project == selection.QualifiedName.Project
&& m.ComponentName == selection.QualifiedName.ComponentName
&& m.Selection.Contains(selection.Selection));
}if (isInterface)
{
return parseResult.Declarations.FindInterfaceImplementationMembers(target.IdentifierName);
}
var member = parseResult.Declarations.FindInterfaceMember(target);
return parseResult.Declarations.FindInterfaceImplementationMembers(member.IdentifierName);if (isInterface)
{
return parseResult.Declarations.FindInterfaceImplementationMembers(target.IdentifierName)
.Where(item => item.IdentifierName == target.ComponentName + "_" + target.IdentifierName);
}
var member = parseResult.Declarations.FindInterfaceMember(target);
return parseResult.Declarations.FindInterfaceImplementationMembers(member.IdentifierName)
.Where(item => item.IdentifierName == member.ComponentName + "_" + member.IdentifierName);Context
StackExchange Code Review Q#91785, answer score: 4
Revisions (0)
No revisions yet.