Skip to content

Commit 53007cd

Browse files
committed
Extend selected declaration handling
Now, the search order is reference, declaration, single variable declaration statement, single constant declaration statement, containing method, containing module. The difference are the new three steps in the middle, i.e. the two statements and the containing method.
1 parent 21b3a6f commit 53007cd

File tree

3 files changed

+299
-2
lines changed

3 files changed

+299
-2
lines changed

Rubberduck.Parsing/VBA/SelectedDeclarationProvider.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Linq;
3+
using Rubberduck.Parsing.Grammar;
34
using Rubberduck.Parsing.Symbols;
45
using Rubberduck.Parsing.VBA.DeclarationCaching;
56
using Rubberduck.VBEditor;
@@ -71,6 +72,24 @@ public Declaration SelectedDeclaration(QualifiedSelection qualifiedSelection)
7172
return canditateViaDeclaration;
7273
}
7374

75+
var canditateViaVariableDeclaration = SelectedDeclarationViaVariableDeclarationStatement(qualifiedSelection, finder);
76+
if (canditateViaVariableDeclaration != null)
77+
{
78+
return canditateViaVariableDeclaration;
79+
}
80+
81+
var canditateViaConstantDeclaration = SelectedDeclarationViaConstantDeclarationStatement(qualifiedSelection, finder);
82+
if (canditateViaConstantDeclaration != null)
83+
{
84+
return canditateViaConstantDeclaration;
85+
}
86+
87+
var canditateViaContainingMember = SelectedMember(qualifiedSelection);
88+
if (canditateViaContainingMember != null)
89+
{
90+
return canditateViaContainingMember;
91+
}
92+
7493
return SelectedModule(qualifiedSelection);
7594
}
7695

@@ -95,6 +114,75 @@ private static Declaration SelectedDeclarationViaDeclaration(QualifiedSelection
95114
.FirstOrDefault();
96115
}
97116

117+
private static Declaration SelectedDeclarationViaVariableDeclarationStatement(QualifiedSelection qualifiedSelection, DeclarationFinder finder)
118+
{
119+
var variablesInModule = finder.Members(qualifiedSelection.QualifiedName)
120+
.Where(declaration => declaration.DeclarationType == DeclarationType.Variable);
121+
122+
//This is annoying to do in method syntax LINQ. So this FirstOrDefault is done by hand.
123+
foreach (var variableDeclaration in variablesInModule)
124+
{
125+
var declarationSelection = SingleVariableDeclarationStatementSelection(variableDeclaration.Context as VBAParser.VariableSubStmtContext);
126+
if (declarationSelection.HasValue && declarationSelection.Value.Contains(qualifiedSelection.Selection))
127+
{
128+
return variableDeclaration;
129+
}
130+
}
131+
132+
return null;
133+
}
134+
135+
private static Selection? SingleVariableDeclarationStatementSelection(VBAParser.VariableSubStmtContext context)
136+
{
137+
if (context is null)
138+
{
139+
return null;
140+
}
141+
142+
var declaredVariableList = (VBAParser.VariableListStmtContext) context.Parent;
143+
if (declaredVariableList.variableSubStmt().Length != 1)
144+
{
145+
return null;
146+
}
147+
148+
var declarationContext = (VBAParser.VariableStmtContext) declaredVariableList.Parent;
149+
return declarationContext.GetSelection();
150+
}
151+
152+
private static Declaration SelectedDeclarationViaConstantDeclarationStatement(QualifiedSelection qualifiedSelection, DeclarationFinder finder)
153+
{
154+
var constantsInModule = finder.Members(qualifiedSelection.QualifiedName)
155+
.Where(declaration => declaration.DeclarationType == DeclarationType.Constant);
156+
157+
//This is annoying to do in method syntax LINQ. So this FirstOrDefault is done by hand.
158+
foreach (var constantDeclaration in constantsInModule)
159+
{
160+
var declarationSelection = SingleConstantDeclarationStatementSelection(constantDeclaration.Context as VBAParser.ConstSubStmtContext);
161+
if (declarationSelection.HasValue && declarationSelection.Value.Contains(qualifiedSelection.Selection))
162+
{
163+
return constantDeclaration;
164+
}
165+
}
166+
167+
return null;
168+
}
169+
170+
private static Selection? SingleConstantDeclarationStatementSelection(VBAParser.ConstSubStmtContext context)
171+
{
172+
if (context is null)
173+
{
174+
return null;
175+
}
176+
177+
var declarationContext = (VBAParser.ConstStmtContext)context.Parent;
178+
if (declarationContext.constSubStmt().Length != 1)
179+
{
180+
return null;
181+
}
182+
183+
return declarationContext.GetSelection();
184+
}
185+
98186
public ModuleBodyElementDeclaration SelectedMember()
99187
{
100188
return FromActiveSelection(SelectedMember)();

Rubberduck.Refactorings/Common/DeclarationExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4-
using System.Diagnostics.CodeAnalysis;
54
using System.Globalization;
65
using System.Linq;
76
using Antlr4.Runtime;

RubberduckTests/Symbols/SelectedDeclarationProviderTests.cs

Lines changed: 211 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,217 @@ Dim sht As WorkSheet
532532
Assert.AreEqual(expected, actual);
533533
}
534534

535-
private (Declaration specifiedDeclaration, Declaration selectedDeclaration) DeclarationsFromParse(
535+
[Category("Resolver")]
536+
[Test]
537+
public void SelectionInsideConstantDeclaration_ConstantSelected()
538+
{
539+
const string code = @"
540+
Private Const myConst As Long = 42
541+
542+
Private myModuleVariable As Long
543+
544+
545+
Public Sub DoIt()
546+
Dim myLocalVariable As Long
547+
548+
myModuleVariable = myLocalVariable
549+
End Sub";
550+
var vbe = new MockVbeBuilder()
551+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
552+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(2, 2))
553+
.AddProjectToVbeBuilder()
554+
.Build();
555+
556+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.Constant, "myConst");
557+
558+
Assert.AreEqual(expected, actual);
559+
}
560+
561+
[Category("Resolver")]
562+
[Test]
563+
[TestCase(4, 2, "myModuleVariable")]
564+
[TestCase(8, 6, "myLocalVariable")]
565+
public void SelectionInsideVariableDeclaration_VariableSelected(int selectedLine, int selectedColumn, string expectedVariableName)
566+
{
567+
const string code = @"
568+
Private Const myConst As Long = 42
569+
570+
Private myModuleVariable As Long
571+
572+
573+
Public Sub DoIt()
574+
Dim myLocalVariable As Long
575+
576+
myModuleVariable = myLocalVariable
577+
End Sub";
578+
var vbe = new MockVbeBuilder()
579+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
580+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(selectedLine, selectedColumn))
581+
.AddProjectToVbeBuilder()
582+
.Build();
583+
584+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.Variable, expectedVariableName);
585+
586+
Assert.AreEqual(expected, actual);
587+
}
588+
589+
[Category("Resolver")]
590+
[Test]
591+
public void SelectionInsideModuleBodyElementAndOnNothingElse_ModuleBodyElementSelected()
592+
{
593+
const string code = @"
594+
Private Const myConst As Long = 42
595+
596+
Private myModuleVariable As Long
597+
598+
599+
Public Sub DoIt()
600+
Dim myLocalVariable As Long
601+
602+
myModuleVariable = myLocalVariable
603+
End Sub";
604+
var vbe = new MockVbeBuilder()
605+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
606+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(9, 5))
607+
.AddProjectToVbeBuilder()
608+
.Build();
609+
610+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.Procedure, "DoIt");
611+
612+
Assert.AreEqual(expected, actual);
613+
}
614+
615+
[Category("Resolver")]
616+
[Test]
617+
public void SelectionInsideVariableDeclaringReDimButNotOnIdentifier_ContainingModuleBodyElementSelected()
618+
{
619+
const string code = @"
620+
Private Const myConst As Long = 42
621+
622+
Private myModuleVariable As Long
623+
624+
625+
Public Sub DoIt()
626+
ReDim arr(23 To 42) As Long
627+
628+
myModuleVariable = arr(33)
629+
End Sub";
630+
var vbe = new MockVbeBuilder()
631+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
632+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(8, 7))
633+
.AddProjectToVbeBuilder()
634+
.Build();
635+
636+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.Procedure, "DoIt");
637+
638+
Assert.AreEqual(expected, actual);
639+
}
640+
641+
[Category("Resolver")]
642+
[Test]
643+
public void SelectionInsideVariableDeclarationStatementForMultipleLocalVariables_ContainingModuleBodyElementSelected()
644+
{
645+
const string code = @"
646+
Private Const myConst As Long = 42
647+
648+
Private myModuleVariable As Long
649+
650+
651+
Public Sub DoIt()
652+
Dim myLocalVariable As Long, myOtherLocalVariable As String
653+
654+
myModuleVariable = myLocalVariable
655+
End Sub";
656+
var vbe = new MockVbeBuilder()
657+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
658+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(8, 6))
659+
.AddProjectToVbeBuilder()
660+
.Build();
661+
662+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.Procedure, "DoIt");
663+
664+
Assert.AreEqual(expected, actual);
665+
}
666+
667+
[Category("Resolver")]
668+
[Test]
669+
public void SelectionOutsideModuleBodyElementAndOnNothingElse_ModuleSelected()
670+
{
671+
const string code = @"
672+
Private Const myConst As Long = 42
673+
674+
Private myModuleVariable As Long
675+
676+
677+
Public Sub DoIt()
678+
Dim myLocalVariable As Long
679+
680+
myModuleVariable = myLocalVariable
681+
End Sub";
682+
var vbe = new MockVbeBuilder()
683+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
684+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(6, 1))
685+
.AddProjectToVbeBuilder()
686+
.Build();
687+
688+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.ProceduralModule, "TestModule");
689+
690+
Assert.AreEqual(expected, actual);
691+
}
692+
693+
[Category("Resolver")]
694+
[Test]
695+
public void SelectionInsideVariableDeclarationStatementForMultipleModuleVariables_ModuleSelected()
696+
{
697+
const string code = @"
698+
Private Const myConst As Long = 42
699+
700+
Private myModuleVariable As Long, myOtherModuleVariable As String
701+
702+
703+
Public Sub DoIt()
704+
Dim myLocalVariable As Long
705+
706+
myModuleVariable = myLocalVariable
707+
End Sub";
708+
var vbe = new MockVbeBuilder()
709+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
710+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(4, 2))
711+
.AddProjectToVbeBuilder()
712+
.Build();
713+
714+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.ProceduralModule, "TestModule");
715+
716+
Assert.AreEqual(expected, actual);
717+
}
718+
719+
[Category("Resolver")]
720+
[Test]
721+
public void SelectionInsideConstantDeclarationStatementForMultipleModuleConstants_ModuleSelected()
722+
{
723+
const string code = @"
724+
Private Const myConst As Long = 42, myOtherConstant As Long = 23
725+
726+
Private myModuleVariable As Long
727+
728+
729+
Public Sub DoIt()
730+
Dim myLocalVariable As Long
731+
732+
myModuleVariable = myLocalVariable
733+
End Sub";
734+
var vbe = new MockVbeBuilder()
735+
.ProjectBuilder("TestProject", ProjectProtection.Unprotected)
736+
.AddComponent("TestModule", ComponentType.StandardModule, code, new Selection(2, 2))
737+
.AddProjectToVbeBuilder()
738+
.Build();
739+
740+
var (expected, actual) = DeclarationsFromParse(vbe.Object, DeclarationType.ProceduralModule, "TestModule");
741+
742+
Assert.AreEqual(expected, actual);
743+
}
744+
745+
private static (Declaration specifiedDeclaration, Declaration selectedDeclaration) DeclarationsFromParse(
536746
IVBE vbe,
537747
DeclarationType declarationType,
538748
string declarationName,

0 commit comments

Comments
 (0)