1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Diagnostics ;
4
+ using System . Diagnostics . CodeAnalysis ;
4
5
using System . Linq ;
5
6
using System . Windows . Media . Imaging ;
6
7
using Microsoft . Vbe . Interop ;
7
8
using Rubberduck . Annotations ;
9
+ using Rubberduck . Parsing ;
8
10
using Rubberduck . Parsing . Grammar ;
9
11
using Rubberduck . Parsing . Symbols ;
10
12
using Rubberduck . VBEditor ;
13
+ // ReSharper disable LocalizableElement
11
14
12
15
namespace Rubberduck . Common
13
16
{
@@ -20,6 +23,114 @@ public static BitmapImage BitmapImage(this Declaration declaration)
20
23
return Cache [ declaration ] ;
21
24
}
22
25
26
+ /// <summary>
27
+ /// Returns the Selection of a VariableStmtContext.
28
+ /// </summary>
29
+ /// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
30
+ /// <param name="target"></param>
31
+ /// <returns></returns>
32
+ public static Selection GetVariableStmtContextSelection ( this Declaration target )
33
+ {
34
+ if ( target . DeclarationType != DeclarationType . Variable )
35
+ {
36
+ throw new ArgumentException ( "Target DeclarationType is not Variable." , "target" ) ;
37
+ }
38
+
39
+ var statement = GetVariableStmtContext ( target ) ;
40
+
41
+ return new Selection ( statement . Start . Line , statement . Start . Column ,
42
+ statement . Stop . Line , statement . Stop . Column ) ;
43
+ }
44
+
45
+ /// <summary>
46
+ /// Returns a VariableStmtContext.
47
+ /// </summary>
48
+ /// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
49
+ /// <param name="target"></param>
50
+ /// <returns></returns>
51
+ public static VBAParser . VariableStmtContext GetVariableStmtContext ( this Declaration target )
52
+ {
53
+ if ( target . DeclarationType != DeclarationType . Variable )
54
+ {
55
+ throw new ArgumentException ( "Target DeclarationType is not Variable." , "target" ) ;
56
+ }
57
+
58
+ var statement = target . Context . Parent . Parent as VBAParser . VariableStmtContext ;
59
+ if ( statement == null )
60
+ {
61
+ throw new MissingMemberException ( "Statement not found" ) ;
62
+ }
63
+
64
+ return statement ;
65
+ }
66
+
67
+ /// <summary>
68
+ /// Returns whether a variable declaration statement contains multiple declarations in a single statement.
69
+ /// </summary>
70
+ /// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
71
+ /// <param name="target"></param>
72
+ /// <returns></returns>
73
+ public static bool HasMultipleDeclarationsInStatement ( this Declaration target )
74
+ {
75
+ if ( target . DeclarationType != DeclarationType . Variable )
76
+ {
77
+ throw new ArgumentException ( "Target DeclarationType is not Variable." , "target" ) ;
78
+ }
79
+
80
+ var statement = target . Context . Parent as VBAParser . VariableListStmtContext ;
81
+
82
+ return statement != null && statement . children . OfType < VBAParser . VariableSubStmtContext > ( ) . Any ( ) ;
83
+ }
84
+
85
+ /// <summary>
86
+ /// Returns the number of variable declarations in a single statement.
87
+ /// </summary>
88
+ /// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
89
+ /// <param name="target"></param>
90
+ /// <returns></returns>
91
+ public static int CountOfDeclarationsInStatement ( this Declaration target )
92
+ {
93
+ if ( target . DeclarationType != DeclarationType . Variable )
94
+ {
95
+ throw new ArgumentException ( "Target DeclarationType is not Variable." , "target" ) ;
96
+ }
97
+
98
+ var statement = target . Context . Parent as VBAParser . VariableListStmtContext ;
99
+
100
+ if ( statement != null )
101
+ {
102
+ return statement . children . OfType < VBAParser . VariableSubStmtContext > ( ) . Count ( ) ;
103
+ }
104
+
105
+ throw new ArgumentException ( "'target.Context.Parent' is not type VBAParser.VariabelListStmtContext" , "target" ) ;
106
+ }
107
+
108
+ /// <summary>
109
+ /// Returns the number of variable declarations in a single statement. Adjusted to be 1-indexed rather than 0-indexed.
110
+ /// </summary>
111
+ /// <exception cref="ArgumentException">Throws when target's DeclarationType is not Variable.</exception>
112
+ /// <param name="target"></param>
113
+ /// <returns></returns>
114
+ public static int IndexOfVariableDeclarationInStatement ( this Declaration target )
115
+ {
116
+ if ( target . DeclarationType != DeclarationType . Variable )
117
+ {
118
+ throw new ArgumentException ( "Target DeclarationType is not Variable." , "target" ) ;
119
+ }
120
+
121
+ var statement = target . Context . Parent as VBAParser . VariableListStmtContext ;
122
+
123
+ if ( statement != null )
124
+ {
125
+ return statement . children . OfType < VBAParser . VariableSubStmtContext > ( )
126
+ . ToList ( )
127
+ . IndexOf ( ( VBAParser . VariableSubStmtContext ) target . Context ) + 1 ;
128
+ }
129
+
130
+ // ReSharper disable once LocalizableElement
131
+ throw new ArgumentException ( "'target.Context.Parent' is not type VBAParser.VariabelListStmtContext" , "target" ) ;
132
+ }
133
+
23
134
public static readonly DeclarationType [ ] ProcedureTypes =
24
135
{
25
136
DeclarationType . Procedure ,
@@ -270,7 +381,15 @@ public static Declaration FindInterfaceMember(this IEnumerable<Declaration> decl
270
381
: matches . First ( ) ;
271
382
}
272
383
273
- public static Declaration FindSelection ( this IEnumerable < Declaration > declarations , QualifiedSelection selection , DeclarationType [ ] validDeclarationTypes )
384
+ /// <summary>
385
+ /// Returns the declaration contained in a qualified selection.
386
+ /// To get the selection of a variable or field, use FindVariable(QualifiedSelection)
387
+ /// </summary>
388
+ /// <param name="declarations"></param>
389
+ /// <param name="selection"></param>
390
+ /// <param name="validDeclarationTypes"></param>
391
+ /// <returns></returns>
392
+ public static Declaration FindTarget ( this IEnumerable < Declaration > declarations , QualifiedSelection selection , DeclarationType [ ] validDeclarationTypes )
274
393
{
275
394
var items = declarations . ToList ( ) ;
276
395
@@ -332,5 +451,75 @@ public static Declaration FindSelection(this IEnumerable<Declaration> declaratio
332
451
}
333
452
return target ;
334
453
}
454
+
455
+ /// <summary>
456
+ /// Returns the variable which contains the passed-in QualifiedSelection. Returns null if the selection is not on a variable.
457
+ /// </summary>
458
+ /// <param name="declarations"></param>
459
+ /// <param name="selection"></param>
460
+ /// <returns></returns>
461
+ public static Declaration FindVariable ( this IEnumerable < Declaration > declarations , QualifiedSelection selection )
462
+ {
463
+ var items = declarations . Where ( d => ! d . IsBuiltIn && d . DeclarationType == DeclarationType . Variable ) . ToList ( ) ;
464
+
465
+ var target = items
466
+ . FirstOrDefault ( item => item . IsSelected ( selection ) || item . References . Any ( r => r . IsSelected ( selection ) ) ) ;
467
+
468
+ if ( target != null ) { return target ; }
469
+
470
+ var targets = items . Where ( item => item . ComponentName == selection . QualifiedName . ComponentName ) ;
471
+
472
+ foreach ( var declaration in targets )
473
+ {
474
+ var declarationSelection = new Selection ( declaration . Context . Start . Line ,
475
+ declaration . Context . Start . Column ,
476
+ declaration . Context . Stop . Line ,
477
+ declaration . Context . Stop . Column + declaration . Context . Stop . Text . Length ) ;
478
+
479
+ if ( declarationSelection . Contains ( selection . Selection ) ||
480
+ ! HasMultipleDeclarationsInStatement ( declaration ) && GetVariableStmtContextSelection ( declaration ) . Contains ( selection . Selection ) )
481
+ {
482
+ return declaration ;
483
+ }
484
+
485
+ var reference =
486
+ declaration . References . FirstOrDefault ( r => r . Selection . Contains ( selection . Selection ) ) ;
487
+
488
+ if ( reference != null )
489
+ {
490
+ return reference . Declaration ;
491
+ }
492
+ }
493
+ return null ;
494
+ }
495
+
496
+ /// <summary>
497
+ /// Returns the interface for a QualifiedSelection contained by a statement similar to "Implements IClass1"
498
+ /// </summary>
499
+ /// <param name="declarations"></param>
500
+ /// <param name="selection"></param>
501
+ /// <returns></returns>
502
+ [ SuppressMessage ( "ReSharper" , "LoopCanBeConvertedToQuery" ) ]
503
+ public static Declaration FindInterface ( this IEnumerable < Declaration > declarations , QualifiedSelection selection )
504
+ {
505
+ foreach ( var declaration in declarations . FindInterfaces ( ) )
506
+ {
507
+ foreach ( var reference in declaration . References )
508
+ {
509
+ var implementsStmt = reference . Context . Parent as VBAParser . ImplementsStmtContext ;
510
+
511
+ if ( implementsStmt == null ) { continue ; }
512
+
513
+ if ( reference . QualifiedModuleName == selection . QualifiedName &&
514
+ ( implementsStmt . GetSelection ( ) . Contains ( selection . Selection )
515
+ || reference . Selection . Contains ( selection . Selection ) ) )
516
+ {
517
+ return declaration ;
518
+ }
519
+ }
520
+ }
521
+
522
+ return null ;
523
+ }
335
524
}
336
525
}
0 commit comments