Skip to content

Commit 81f1817

Browse files
authored
Merge pull request #5743 from retailcoder/fixfindsymbol
Restores FindSymbol search feature, enhances *Search Results* view.
2 parents 7cda15e + bb20c7f commit 81f1817

22 files changed

+582
-267
lines changed

Rubberduck.CodeAnalysis/Inspections/Concrete/UnreachableCaseEvaluation/UnreachableCaseInspector.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -98,23 +98,24 @@ public UnreachableCaseInspector(
9898

9999
private UnreachableCaseInspection.CaseInspectionResultType? InvalidRangeExpressionsType(ICollection<IRangeClauseExpression> rangeClauseExpressions)
100100
{
101-
if (rangeClauseExpressions.Any(expr => expr.IsMismatch))
101+
var usableClauses = rangeClauseExpressions.Where(expr => expr != null).ToList();
102+
if (usableClauses.Any(expr => expr.IsMismatch))
102103
{
103104
return UnreachableCaseInspection.CaseInspectionResultType.MismatchType;
104105
}
105106

106-
if (rangeClauseExpressions.Any(expr => expr.IsOverflow))
107+
if (usableClauses.Any(expr => expr.IsOverflow))
107108
{
108109
return UnreachableCaseInspection.CaseInspectionResultType.Overflow;
109110
}
110111

111-
if (rangeClauseExpressions.All(expr => expr.IsInherentlyUnreachable))
112+
if (usableClauses.All(expr => expr.IsInherentlyUnreachable))
112113
{
113114
return UnreachableCaseInspection.CaseInspectionResultType.InherentlyUnreachable;
114115
}
115116

116-
if (rangeClauseExpressions.All(expr =>
117-
expr.IsUnreachable || expr.IsMismatch || expr.IsOverflow || expr.IsInherentlyUnreachable))
117+
if (usableClauses.All(expr =>
118+
expr.IsUnreachable || expr.IsMismatch|| expr.IsOverflow || expr.IsInherentlyUnreachable))
118119
{
119120
return UnreachableCaseInspection.CaseInspectionResultType.Unreachable;
120121
}

Rubberduck.Core/UI/CodeExplorer/CodeExplorerControl.xaml

+5-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
<converters:AnnotationToCodeStringConverter x:Key="AnnotationToCodeString" />
5959
<converters:AnnotateDeclarationCommandParameterToTupleConverter x:Key="AnnotateDeclarationCommandParameterToTuple" />
6060
<converters:AnnotateDeclarationCommandCEVisibilityConverter x:Key="AnnotateDeclarationCommandVisibility" />
61+
<converters:DeclarationToDeclarationTypeStringConverter x:Key="DeclarationTypeNameConverter" />
6162

6263
<CompositeCollection x:Key="AddModuleCommands" x:Shared="False">
6364
<MenuItem Header="{Resx ResxName=Rubberduck.Resources.CodeExplorer.CodeExplorerUI, Key=CodeExplorer_AddExistingFileText}"
@@ -604,7 +605,8 @@
604605
</HierarchicalDataTemplate.Resources>
605606
<StackPanel Orientation="Horizontal">
606607
<Grid>
607-
<Image Style="{StaticResource ToolbarIconStyle}">
608+
<Image Style="{StaticResource ToolbarIconStyle}"
609+
ToolTip="{Binding Converter={StaticResource DeclarationTypeNameConverter}}">
608610
<Image.Source>
609611
<MultiBinding Converter="{StaticResource NodeToIcon}">
610612
<MultiBinding.Bindings>
@@ -616,7 +618,8 @@
616618
</MultiBinding>
617619
</Image.Source>
618620
</Image>
619-
<Image Source="{Binding Declaration, Converter={StaticResource AccessibilityToIcon}}" Style="{StaticResource ToolbarIconStyle}" />
621+
<Image Source="{Binding Declaration, Converter={StaticResource AccessibilityToIcon}}" Style="{StaticResource ToolbarIconStyle}"
622+
ToolTip="{Binding Converter={StaticResource DeclarationTypeNameConverter}}"/>
620623
</Grid>
621624
<TextBlock Style="{StaticResource TreeViewItemStyleModified}" />
622625
</StackPanel>

Rubberduck.Core/UI/CodeExplorer/Commands/CodeExplorerFindAllReferencesCommand.cs

+11-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using Rubberduck.AddRemoveReferences;
44
using Rubberduck.Navigation.CodeExplorer;
5+
using Rubberduck.Parsing.Symbols;
56
using Rubberduck.Parsing.VBA;
67
using Rubberduck.UI.Controls;
78
using Rubberduck.VBEditor.Events;
@@ -43,20 +44,26 @@ private bool SpecialEvaluateCanExecute(object parameter)
4344

4445
protected override void OnExecute(object parameter)
4546
{
46-
if (_state.Status != ParserState.Ready ||
47-
!(parameter is ICodeExplorerNode node) ||
48-
node.Declaration == null)
47+
if (_state.Status != ParserState.Ready
48+
|| !(parameter is ICodeExplorerNode node)
49+
|| node.Declaration == null)
4950
{
5051
return;
5152
}
5253

54+
if (!(node.Parent.Declaration is ProjectDeclaration projectDeclaration))
55+
{
56+
Logger.Error($"The specified ICodeExplorerNode expected to be a direct child of a node whose declaration is a ProjectDeclaration.");
57+
return;
58+
}
59+
5360
if (parameter is CodeExplorerReferenceViewModel reference)
5461
{
5562
if (!(reference.Reference is ReferenceModel model))
5663
{
5764
return;
5865
}
59-
_finder.FindAllReferences(node.Parent.Declaration, model.ToReferenceInfo());
66+
_finder.FindAllReferences(projectDeclaration, model.ToReferenceInfo());
6067
return;
6168
}
6269

Rubberduck.Core/UI/Command/ComCommands/FindSymbolCommand.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ namespace Rubberduck.UI.Command.ComCommands
1515
public class FindSymbolCommand : ComCommandBase
1616
{
1717
private readonly RubberduckParserState _state;
18-
private readonly DeclarationIconCache _iconCache;
1918
private readonly NavigateCommand _navigateCommand;
2019

2120
public FindSymbolCommand(
@@ -26,14 +25,12 @@ public FindSymbolCommand(
2625
: base(vbeEvents)
2726
{
2827
_state = state;
29-
_iconCache = iconCache;
30-
3128
_navigateCommand = new NavigateCommand(selectionService);
3229
}
3330

3431
protected override void OnExecute(object parameter)
3532
{
36-
var viewModel = new FindSymbolViewModel(_state.AllUserDeclarations, _iconCache);
33+
var viewModel = new FindSymbolViewModel(_state.AllUserDeclarations);
3734
var view = new FindSymbolDialog(viewModel);
3835
{
3936
viewModel.Navigate += (sender, e) => { view.Hide(); };

Rubberduck.Core/UI/Command/MenuItems/CommandBars/RubberduckCommandBar.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ await Task.Run(async () =>
8585
token.ThrowIfCancellationRequested();
8686

8787
var argRefCount = e.Declaration is ParameterDeclaration parameter ? parameter.ArgumentReferences.Count() : 0;
88-
var refCount = e.Declaration?.References.Count() ?? 0 + argRefCount;
89-
var description = e.Declaration?.DescriptionString ?? string.Empty;
88+
var refCount = (e.Declaration?.References.Count() ?? 0) + argRefCount;
89+
var description = e.Declaration?.DescriptionString.Trim() ?? string.Empty;
9090
token.ThrowIfCancellationRequested();
9191

9292
//& renders the next character as if it was an accelerator.

Rubberduck.Core/UI/Controls/FindAllReferencesAction.cs

+93-73
Original file line numberDiff line numberDiff line change
@@ -50,82 +50,58 @@ private void _state_StateChanged(object sender, ParserStateEventArgs e)
5050
_uiDispatcher.InvokeAsync(UpdateTab);
5151
}
5252

53-
public void FindAllReferences(Declaration declaration)
53+
public void FindAllReferences(Declaration target)
5454
{
5555
if (_state.Status != ParserState.Ready)
5656
{
57+
_logger.Debug($"ParserState is {_state.Status}. This action requires a Ready state.");
5758
return;
5859
}
5960

60-
var viewModel = CreateViewModel(declaration);
61-
if (!viewModel.SearchResults.Any())
61+
var viewModel = CreateViewModel(target);
62+
if (!Confirm(target.IdentifierName, viewModel.SearchResults.Count))
6263
{
63-
_messageBox.NotifyWarn(string.Format(RubberduckUI.AllReferences_NoneFound, declaration.IdentifierName), RubberduckUI.Rubberduck);
6464
return;
6565
}
6666

67-
if (viewModel.SearchResults.Count == 1)
68-
{
69-
_navigateCommand.Execute(viewModel.SearchResults.Single().GetNavigationArgs());
70-
return;
71-
}
72-
73-
_viewModel.AddTab(viewModel);
74-
_viewModel.SelectedTab = viewModel;
75-
76-
try
77-
{
78-
var presenter = _presenterService.Presenter(_viewModel);
79-
presenter.Show();
80-
}
81-
catch (Exception e)
82-
{
83-
_logger.Error(e);
84-
}
67+
ShowResults(viewModel);
8568
}
8669

87-
public void FindAllReferences(Declaration declaration, ReferenceInfo reference)
70+
public void FindAllReferences(ProjectDeclaration project, ReferenceInfo reference)
8871
{
89-
if (_state.Status != ParserState.Ready ||
90-
!(declaration is ProjectDeclaration project))
72+
if (_state.Status != ParserState.Ready)
9173
{
74+
_logger.Debug($"ParserState is {_state.Status}. This action requires a Ready state.");
9275
return;
9376
}
9477

95-
var usages = _state.DeclarationFinder.FindAllReferenceUsesInProject(project, reference, out var referenceProject)
96-
.Select(usage =>
97-
new SearchResultItem(usage.ParentNonScoping,
98-
new NavigateCodeEventArgs(usage.QualifiedModuleName, usage.Selection),
99-
GetModuleLine(usage.QualifiedModuleName, usage.Selection.StartLine)))
100-
.ToList();
101-
102-
if (declaration is ParameterDeclaration parameter)
78+
var usages = _state.DeclarationFinder.FindAllReferenceUsesInProject(project, reference, out var referenceProject).ToList();
79+
if (referenceProject == null)
10380
{
104-
usages.AddRange(parameter.ArgumentReferences.Select(usage =>
105-
new SearchResultItem(usage.ParentNonScoping,
106-
new NavigateCodeEventArgs(usage.QualifiedModuleName, usage.Selection),
107-
GetModuleLine(usage.QualifiedModuleName, usage.Selection.StartLine))));
81+
return;
10882
}
109-
110-
if (!usages.Any())
83+
if (!Confirm(referenceProject.IdentifierName, usages.Count))
11184
{
112-
_messageBox.NotifyWarn(string.Format(RubberduckUI.AllReferences_NoneFoundReference, referenceProject.IdentifierName), RubberduckUI.Rubberduck);
11385
return;
11486
}
11587

116-
if (usages.Count > 1000 &&
117-
!_messageBox.ConfirmYesNo(string.Format(RubberduckUI.AllReferences_PerformanceWarning, referenceProject.IdentifierName, usages.Count),
118-
RubberduckUI.PerformanceWarningCaption))
88+
var viewModel = CreateViewModel(project, referenceProject.IdentifierName, usages);
89+
ShowResults(viewModel);
90+
}
91+
92+
private void ShowResults(SearchResultsViewModel viewModel)
93+
{
94+
if (viewModel.SearchResults.Count == 1)
11995
{
96+
viewModel.NavigateCommand.Execute(viewModel.SearchResults[0].GetNavigationArgs());
12097
return;
12198
}
12299

123-
var viewModel = CreateViewModel(project, referenceProject, usages);
124-
_viewModel.AddTab(viewModel);
125-
_viewModel.SelectedTab = viewModel;
126-
127100
try
128101
{
102+
_viewModel.AddTab(viewModel);
103+
_viewModel.SelectedTab = viewModel;
104+
129105
var presenter = _presenterService.Presenter(_viewModel);
130106
presenter.Show();
131107
}
@@ -135,51 +111,95 @@ public void FindAllReferences(Declaration declaration, ReferenceInfo reference)
135111
}
136112
}
137113

138-
private string GetModuleLine(QualifiedModuleName module, int line)
114+
private bool Confirm(string identifier, int referencesFound)
139115
{
140-
var component = _state.ProjectsProvider.Component(module);
141-
using (var codeModule = component.CodeModule)
116+
const int threshold = 1000;
117+
if (referencesFound == 0)
142118
{
143-
return codeModule.GetLines(line, 1).Trim();
119+
_messageBox.NotifyWarn(
120+
string.Format(RubberduckUI.AllReferences_NoneFoundReference, identifier),
121+
RubberduckUI.Rubberduck);
122+
return false;
144123
}
145-
}
146124

147-
private SearchResultsViewModel CreateViewModel(ProjectDeclaration project, ProjectDeclaration reference, IEnumerable<SearchResultItem> results)
148-
{
149-
var viewModel = new SearchResultsViewModel(_navigateCommand,
150-
string.Format(RubberduckUI.SearchResults_AllReferencesTabFormat, reference.IdentifierName), project, results);
125+
if (referencesFound > threshold)
126+
{
127+
return _messageBox.ConfirmYesNo(
128+
string.Format(RubberduckUI.AllReferences_PerformanceWarning, identifier, referencesFound),
129+
RubberduckUI.PerformanceWarningCaption);
130+
}
151131

152-
return viewModel;
132+
return true;
153133
}
154134

155-
private SearchResultsViewModel CreateViewModel(Declaration declaration)
135+
136+
private SearchResultsViewModel CreateViewModel(Declaration declaration, string identifier = null, IEnumerable<IdentifierReference> references = null)
156137
{
157-
var results = declaration.References
138+
var nameRefs = (references ?? declaration.References)
158139
.Where(reference => !reference.IsArrayAccess)
159140
.Distinct()
160-
.Select(reference =>
161-
new SearchResultItem(
162-
reference.ParentNonScoping,
163-
new NavigateCodeEventArgs(reference.QualifiedModuleName, reference.Selection),
164-
GetModuleLine(reference.QualifiedModuleName, reference.Selection.StartLine)))
165-
.Concat((declaration is ParameterDeclaration parameter)
166-
? parameter.ArgumentReferences.Select(argument =>
167-
new SearchResultItem(
168-
argument.ParentNonScoping,
169-
new NavigateCodeEventArgs(argument.QualifiedModuleName, argument.Selection),
170-
GetModuleLine(argument.QualifiedModuleName, argument.Selection.StartLine)))
171-
: Enumerable.Empty<SearchResultItem>());
141+
.GroupBy(reference => reference.QualifiedModuleName)
142+
.ToDictionary(group => group.Key);
143+
144+
var argRefs = (declaration is ParameterDeclaration parameter
145+
? parameter.ArgumentReferences
146+
: Enumerable.Empty<ArgumentReference>())
147+
.Distinct()
148+
.GroupBy(argRef => argRef.QualifiedModuleName)
149+
.ToDictionary(group => group.Key);
150+
151+
var results = new List<SearchResultItem>();
152+
var modules = nameRefs.Keys.Concat(argRefs.Keys).Distinct();
153+
foreach (var qualifiedModuleName in modules)
154+
{
155+
var component = _state.ProjectsProvider.Component(qualifiedModuleName);
156+
if (component == null)
157+
{
158+
_logger.Warn($"Could not retrieve the IVBComponent for module '{qualifiedModuleName}'.");
159+
continue;
160+
}
161+
var module = component.CodeModule;
162+
163+
if (nameRefs.TryGetValue(qualifiedModuleName, out var identifierReferences))
164+
{
165+
foreach (var identifierReference in identifierReferences)
166+
{
167+
var (context, selection) = identifierReference.HighlightSelection(module);
168+
var result = new SearchResultItem(
169+
identifierReference.ParentNonScoping,
170+
new NavigateCodeEventArgs(qualifiedModuleName, identifierReference.Selection),
171+
context, selection);
172+
results.Add(result);
173+
}
174+
}
175+
176+
if (argRefs.TryGetValue(qualifiedModuleName, out var argReferences))
177+
{
178+
foreach (var argumentReference in argReferences)
179+
{
180+
var (context, selection) = argumentReference.HighlightSelection(module);
181+
var result = new SearchResultItem(
182+
argumentReference.ParentNonScoping,
183+
new NavigateCodeEventArgs(qualifiedModuleName, argumentReference.Selection),
184+
context, selection);
185+
results.Add(result);
186+
}
187+
}
188+
}
172189

173190
var accessor = declaration.DeclarationType.HasFlag(DeclarationType.PropertyGet) ? "(get)"
174191
: declaration.DeclarationType.HasFlag(DeclarationType.PropertyLet) ? "(let)"
175192
: declaration.DeclarationType.HasFlag(DeclarationType.PropertySet) ? "(set)"
176193
: string.Empty;
177194

178-
var tabCaption = $"{declaration.IdentifierName} {accessor}".Trim();
195+
var tabCaption = $"{identifier ?? declaration.IdentifierName} {accessor}".Trim();
179196

180197

181198
var viewModel = new SearchResultsViewModel(_navigateCommand,
182-
string.Format(RubberduckUI.SearchResults_AllReferencesTabFormat, tabCaption), declaration, results);
199+
string.Format(RubberduckUI.SearchResults_AllReferencesTabFormat, tabCaption), declaration,
200+
results.OrderBy(item => item.ParentScope.QualifiedModuleName.ToString())
201+
.ThenBy(item => item.Selection)
202+
.ToList());
183203

184204
return viewModel;
185205
}

0 commit comments

Comments
 (0)