Skip to content

Commit 21b3a6f

Browse files
committed
Move logic for finding selected declarations to SelectedDeclarationProvider
This also removes FindSelectedDeclaration from the DeclarationFinder.
1 parent 241e1fb commit 21b3a6f

File tree

6 files changed

+688
-713
lines changed

6 files changed

+688
-713
lines changed

Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs

Lines changed: 1 addition & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ public class DeclarationFinder
3333
private IDictionary<(QualifiedModuleName module, int annotatedLine), List<IParseTreeAnnotation>> _annotations;
3434
private IDictionary<Declaration, List<ParameterDeclaration>> _parametersByParent;
3535
private IDictionary<DeclarationType, List<Declaration>> _userDeclarationsByType;
36-
private IDictionary<QualifiedSelection, List<Declaration>> _declarationsBySelection;
3736

3837
private IReadOnlyList<IdentifierReference> _identifierReferences;
3938
private IDictionary<QualifiedSelection, List<IdentifierReference>> _referencesBySelection;
@@ -106,12 +105,6 @@ private List<Action> CollectionConstructionActions(IReadOnlyList<Declaration> de
106105
_declarationsByName = declarations
107106
.GroupBy(declaration => declaration.IdentifierName.ToLowerInvariant())
108107
.ToDictionary(),
109-
() =>
110-
_declarationsBySelection = declarations
111-
.Where(declaration => declaration.IsUserDefined)
112-
.GroupBy(GetGroupingKey)
113-
.ToDictionary(),
114-
115108
() =>
116109
_parametersByParent = declarations
117110
.Where(declaration => declaration.DeclarationType == DeclarationType.Parameter)
@@ -274,73 +267,6 @@ private IDictionary<Declaration, List<Declaration>> FindAllHandlersByWithEventFi
274267
return handlersByWithEventsField;
275268
}
276269

277-
public Declaration FindSelectedDeclaration(QualifiedSelection qualifiedSelection)
278-
{
279-
var matches = new List<Declaration>();
280-
281-
// statistically we'll be on an IdentifierReference more often than on a Declaration:
282-
if (_referencesByModule.TryGetValue(qualifiedSelection.QualifiedName, out var referencesInModule))
283-
{
284-
matches = referencesInModule
285-
.Where(reference => reference.IsSelected(qualifiedSelection))
286-
.OrderByDescending(reference => reference.Declaration.DeclarationType)
287-
.Select(reference => reference.Declaration)
288-
.Distinct()
289-
.ToList();
290-
}
291-
292-
if (!matches.Any() && _declarations.TryGetValue(qualifiedSelection.QualifiedName, out var declarationsInModule))
293-
{
294-
matches = declarationsInModule
295-
.Where(declaration => declaration.IsSelected(qualifiedSelection))
296-
.OrderByDescending(declaration => declaration.DeclarationType)
297-
.Distinct()
298-
.ToList();
299-
}
300-
301-
switch (matches.Count)
302-
{
303-
case 0:
304-
return ModuleDeclaration(qualifiedSelection.QualifiedName);
305-
306-
case 1:
307-
return matches.Single();
308-
309-
default:
310-
// they're sorted by type, so a local comes before the procedure it's in
311-
return matches.FirstOrDefault();
312-
}
313-
}
314-
315-
public Declaration FindSelectedDeclaration(ICodePane activeCodePane)
316-
{
317-
if (activeCodePane == null || activeCodePane.IsWrappingNullReference)
318-
{
319-
return null;
320-
}
321-
322-
var qualifiedSelection = activeCodePane.GetQualifiedSelection();
323-
if (!qualifiedSelection.HasValue || qualifiedSelection.Value.Equals(default))
324-
{
325-
return null;
326-
}
327-
328-
return FindSelectedDeclaration(qualifiedSelection.Value);
329-
}
330-
331-
/// <summary>
332-
/// Finds all declarations containing the passed selection.
333-
/// </summary>
334-
/// <param name="selection">The QualifiedSelection to find declarations for.</param>
335-
/// <returns>An IEnumerable of matches.</returns>
336-
public IEnumerable<Declaration> FindDeclarationsContainingSelection(QualifiedSelection selection)
337-
{
338-
return _declarationsBySelection.Keys
339-
.Where(key => key.Contains(selection))
340-
.SelectMany(key => _declarationsBySelection[key])
341-
.Distinct();
342-
}
343-
344270
//This does not need a lock because enumerators over a ConcurrentBag uses a snapshot.
345271
public IEnumerable<Declaration> FreshUndeclared => _newUndeclared.AllValues();
346272
public IReadOnlyDictionary<QualifiedModuleName, IFailedResolutionStore> FreshFailedResolutionStores => _newFailedResolutionStores.ToDictionary(kvp => kvp.Key, kvp => (IFailedResolutionStore)new FailedResolutionStore(kvp.Value));
@@ -1303,7 +1229,7 @@ public IEnumerable<Declaration> FindNewDeclarationNameConflicts(string newName,
13031229
return Enumerable.Empty<Declaration>();
13041230
}
13051231

1306-
var identifierMatches = MatchName(newName).Where(match => match.ProjectId == renameTarget.ProjectId);
1232+
var identifierMatches = MatchName(newName).Where(match => match.ProjectId == renameTarget.ProjectId).ToList();
13071233

13081234
if (!identifierMatches.Any())
13091235
{

Rubberduck.Parsing/VBA/ISelectedDeclarationProvider.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ public interface ISelectedDeclarationProvider
88
Declaration SelectedDeclaration();
99
Declaration SelectedDeclaration(QualifiedModuleName module);
1010
Declaration SelectedDeclaration(QualifiedSelection qualifiedSelection);
11+
ModuleBodyElementDeclaration SelectedMember();
12+
ModuleBodyElementDeclaration SelectedMember(QualifiedModuleName module);
13+
ModuleBodyElementDeclaration SelectedMember(QualifiedSelection qualifiedSelection);
1114
ProjectDeclaration SelectedProject();
15+
ProjectDeclaration SelectedProject(QualifiedSelection qualifiedSelection);
1216
ModuleDeclaration SelectedModule();
13-
ModuleBodyElementDeclaration SelectedMember();
17+
ModuleDeclaration SelectedModule(QualifiedSelection qualifiedSelection);
1418
}
1519
}
Lines changed: 97 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Linq;
1+
using System;
2+
using System.Linq;
23
using Rubberduck.Parsing.Symbols;
4+
using Rubberduck.Parsing.VBA.DeclarationCaching;
35
using Rubberduck.VBEditor;
46
using Rubberduck.VBEditor.Utility;
57

@@ -18,67 +20,124 @@ public SelectedDeclarationProvider(ISelectionProvider selectionProvider, IDeclar
1820

1921
public Declaration SelectedDeclaration()
2022
{
21-
var selection = _selectionProvider.ActiveSelection();
22-
return SelectedDeclaration(selection);
23+
return FromActiveSelection(SelectedDeclaration)();
2324
}
2425

25-
private Declaration SelectedDeclaration(QualifiedSelection? qualifiedSelection)
26+
private Func<T> FromActiveSelection<T>(Func<QualifiedSelection, T> func)
27+
where T: class
2628
{
27-
return qualifiedSelection.HasValue
28-
? SelectedDeclaration(qualifiedSelection.Value)
29-
: null;
29+
return () =>
30+
{
31+
var activeSelection = _selectionProvider.ActiveSelection();
32+
return activeSelection.HasValue
33+
? func(activeSelection.Value)
34+
: null;
35+
};
3036
}
3137

3238
public Declaration SelectedDeclaration(QualifiedModuleName module)
3339
{
34-
var selection = _selectionProvider.Selection(module);
35-
return SelectedDeclaration(module, selection);
40+
return FromModuleSelection(SelectedDeclaration)(module);
3641
}
3742

38-
private Declaration SelectedDeclaration(QualifiedModuleName module, Selection? selection)
43+
private Func<QualifiedModuleName, T> FromModuleSelection<T>(Func<QualifiedSelection, T> func)
44+
where T : class
3945
{
40-
return selection.HasValue
41-
? SelectedDeclaration(new QualifiedSelection(module, selection.Value))
42-
: null;
46+
return (module) =>
47+
{
48+
var selection = _selectionProvider.Selection(module);
49+
if (!selection.HasValue)
50+
{
51+
return null;
52+
}
53+
var qualifiedSelection = new QualifiedSelection(module, selection.Value);
54+
return func(qualifiedSelection);
55+
};
4356
}
4457

4558
public Declaration SelectedDeclaration(QualifiedSelection qualifiedSelection)
4659
{
47-
return _declarationFinderProvider.DeclarationFinder?.FindSelectedDeclaration(qualifiedSelection);
60+
var finder = _declarationFinderProvider.DeclarationFinder;
61+
62+
var canditateViaReference = SelectedDeclarationViaReference(qualifiedSelection, finder);
63+
if (canditateViaReference != null)
64+
{
65+
return canditateViaReference;
66+
}
67+
68+
var canditateViaDeclaration = SelectedDeclarationViaDeclaration(qualifiedSelection, finder);
69+
if (canditateViaDeclaration != null)
70+
{
71+
return canditateViaDeclaration;
72+
}
73+
74+
return SelectedModule(qualifiedSelection);
4875
}
4976

50-
public ProjectDeclaration SelectedProject()
77+
private static Declaration SelectedDeclarationViaReference(QualifiedSelection qualifiedSelection, DeclarationFinder finder)
5178
{
52-
var activeSelection = _selectionProvider.ActiveSelection();
53-
return activeSelection.HasValue
54-
? _declarationFinderProvider.DeclarationFinder?
55-
.UserDeclarations(DeclarationType.Project)
56-
.OfType<ProjectDeclaration>()
57-
.FirstOrDefault(project => project.ProjectId.Equals(activeSelection.Value.QualifiedName.ProjectId))
58-
: null;
79+
var referencesInModule = finder.IdentifierReferences(qualifiedSelection.QualifiedName);
80+
return referencesInModule
81+
.Where(reference => reference.IsSelected(qualifiedSelection))
82+
.Select(reference => reference.Declaration)
83+
.OrderByDescending(declaration => declaration.DeclarationType)
84+
// they're sorted by type, so a local comes before the procedure it's in
85+
.FirstOrDefault();
5986
}
6087

61-
public ModuleDeclaration SelectedModule()
88+
private static Declaration SelectedDeclarationViaDeclaration(QualifiedSelection qualifiedSelection, DeclarationFinder finder)
6289
{
63-
var activeSelection = _selectionProvider.ActiveSelection();
64-
return activeSelection.HasValue
65-
? _declarationFinderProvider.DeclarationFinder?
66-
.UserDeclarations(DeclarationType.Module)
67-
.OfType<ModuleDeclaration>()
68-
.FirstOrDefault(module => module.QualifiedModuleName.Equals(activeSelection.Value.QualifiedName))
69-
: null;
90+
var declarationsInModule = finder.Members(qualifiedSelection.QualifiedName);
91+
return declarationsInModule
92+
.Where(declaration => declaration.IsSelected(qualifiedSelection))
93+
.OrderByDescending(declaration => declaration.DeclarationType)
94+
// they're sorted by type, so a local comes before the procedure it's in
95+
.FirstOrDefault();
7096
}
7197

7298
public ModuleBodyElementDeclaration SelectedMember()
7399
{
74-
var activeSelection = _selectionProvider.ActiveSelection();
75-
return activeSelection.HasValue
76-
? _declarationFinderProvider.DeclarationFinder?
77-
.UserDeclarations(DeclarationType.Member)
78-
.OfType<ModuleBodyElementDeclaration>()
79-
.FirstOrDefault(member => member.QualifiedModuleName.Equals(activeSelection.Value.QualifiedName)
80-
&& member.Context.GetSelection().Contains(activeSelection.Value.Selection))
81-
: null;
100+
return FromActiveSelection(SelectedMember)();
101+
}
102+
103+
public ModuleBodyElementDeclaration SelectedMember(QualifiedModuleName module)
104+
{
105+
return FromModuleSelection(SelectedMember)(module);
106+
}
107+
108+
public ModuleBodyElementDeclaration SelectedMember(QualifiedSelection qualifiedSelection)
109+
{
110+
return _declarationFinderProvider.DeclarationFinder?
111+
.UserDeclarations(DeclarationType.Member)
112+
.OfType<ModuleBodyElementDeclaration>()
113+
.FirstOrDefault(member => member.QualifiedModuleName.Equals(qualifiedSelection.QualifiedName)
114+
&& member.Context.GetSelection().Contains(qualifiedSelection.Selection));
115+
}
116+
117+
public ModuleDeclaration SelectedModule()
118+
{
119+
return FromActiveSelection(SelectedModule)();
120+
}
121+
122+
public ModuleDeclaration SelectedModule(QualifiedSelection qualifiedSelection)
123+
{
124+
return _declarationFinderProvider.DeclarationFinder?
125+
.UserDeclarations(DeclarationType.Module)
126+
.OfType<ModuleDeclaration>()
127+
.FirstOrDefault(module => module.QualifiedModuleName.Equals(qualifiedSelection.QualifiedName));
128+
}
129+
130+
public ProjectDeclaration SelectedProject()
131+
{
132+
return FromActiveSelection(SelectedProject)();
133+
}
134+
135+
public ProjectDeclaration SelectedProject(QualifiedSelection qualifiedSelection)
136+
{
137+
return _declarationFinderProvider.DeclarationFinder?
138+
.UserDeclarations(DeclarationType.Project)
139+
.OfType<ProjectDeclaration>()
140+
.FirstOrDefault(project => project.ProjectId.Equals(qualifiedSelection.QualifiedName.ProjectId));
82141
}
83142
}
84143
}

RubberduckTests/Refactoring/MockIoC/MockRefactoringContainerTests.cs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
using System.Collections.Generic;
22
using Moq;
33
using NUnit.Framework;
4+
using Rubberduck.Parsing.VBA;
45
using Rubberduck.Refactorings;
56
using Rubberduck.Refactorings.Rename;
67
using Rubberduck.UI.Refactorings.Rename;
78
using Rubberduck.VBEditor;
9+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
10+
using Rubberduck.VBEditor.Utility;
811
using RubberduckTests.Mocks;
912

1013
namespace RubberduckTests.Refactoring.MockIoC
@@ -41,9 +44,8 @@ public void CanResolve_Actual()
4144
var container = RefactoringContainerInstaller.GetContainer();
4245
var factory = container.Resolve<IRefactoringPresenterFactory>();
4346

44-
var declaration =
45-
state.DeclarationFinder.FindSelectedDeclaration(
46-
new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
47+
var declaration = SelectedDeclarationProvider(vbe.Object, state)
48+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
4749

4850
var model = new RenameModel(declaration);
4951
var presenter = factory.Create<IRenamePresenter, RenameModel>(model);
@@ -59,12 +61,12 @@ public void CanMutateMock_Indirect_View()
5961
var parser = MockParser.Create(vbe.Object);
6062
using (var state = parser.State)
6163
{
62-
var actualTarget = state.DeclarationFinder
63-
.FindSelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(2, 2)));
64+
var actualTarget = SelectedDeclarationProvider(vbe.Object, state)
65+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(2, 2)));
6466
var actual = new RenameModel(actualTarget);
6567

66-
var initialTarget = state.DeclarationFinder.FindSelectedDeclaration(
67-
new QualifiedSelection(new QualifiedModuleName(component), new Selection(3, 3)));
68+
var initialTarget = SelectedDeclarationProvider(vbe.Object, state)
69+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(3, 3)));
6870
var initial = new RenameModel(initialTarget);
6971

7072
var container = RefactoringContainerInstaller.GetContainer();
@@ -79,8 +81,8 @@ public void CanMutateMock_Indirect_View()
7981
mockView.SetupGet(m => m.DataContext).Returns(actual);
8082

8183
var factory = container.Resolve<IRefactoringPresenterFactory>();
82-
var target = state.DeclarationFinder.FindSelectedDeclaration(
83-
new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
84+
var target = SelectedDeclarationProvider(vbe.Object, state)
85+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
8486
var model = new RenameModel(target);
8587
var presenter = (RenamePresenter)factory.Create<IRenamePresenter, RenameModel>(model);
8688
var expected = presenter.Dialog.View.DataContext;
@@ -95,14 +97,14 @@ public void CanMutateMock_Direct_Dialog()
9597
var parser = MockParser.Create(vbe.Object);
9698
using (var state = parser.State)
9799
{
98-
var actualTarget = state.DeclarationFinder
99-
.FindSelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(2, 2)));
100+
var actualTarget = SelectedDeclarationProvider(vbe.Object, state)
101+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(2, 2)));
100102
var actual = new RenameModel(actualTarget);
101103
var container = RefactoringContainerInstaller.GetContainer();
102104
var factory = container.Resolve<IRefactoringPresenterFactory>();
103105

104-
var target = state.DeclarationFinder
105-
.FindSelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
106+
var target = SelectedDeclarationProvider(vbe.Object, state)
107+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
106108
var model = new RenameModel(target);
107109
var presenter = (RenamePresenter)factory.Create<IRenamePresenter, RenameModel>(model);
108110

@@ -121,14 +123,14 @@ public void CanMutateMock_Indirect_Dialog()
121123
var parser = MockParser.Create(vbe.Object);
122124
using (var state = parser.State)
123125
{
124-
var actualTarget = state.DeclarationFinder
125-
.FindSelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(2, 2)));
126+
var actualTarget = SelectedDeclarationProvider(vbe.Object, state)
127+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(2, 2)));
126128
var actual = new RenameModel(actualTarget);
127129
var container = RefactoringContainerInstaller.GetContainer();
128130
var factory = container.Resolve<IRefactoringPresenterFactory>();
129131

130-
var target = state.DeclarationFinder
131-
.FindSelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
132+
var target = SelectedDeclarationProvider(vbe.Object, state)
133+
.SelectedDeclaration(new QualifiedSelection(new QualifiedModuleName(component), new Selection(1, 1)));
132134
var model = new RenameModel(target);
133135
var presenter = (RenamePresenter)factory.Create<IRenamePresenter, RenameModel>(model);
134136

@@ -143,5 +145,11 @@ public void CanMutateMock_Indirect_Dialog()
143145
Assert.AreEqual(actual, expected);
144146
}
145147
}
148+
149+
private ISelectedDeclarationProvider SelectedDeclarationProvider(IVBE vbe, RubberduckParserState state)
150+
{
151+
var selectionProvider = new SelectionService(vbe, state.ProjectsProvider);
152+
return new SelectedDeclarationProvider(selectionProvider, state);
153+
}
146154
}
147155
}

0 commit comments

Comments
 (0)