1
+ using Rubberduck . Parsing . Grammar ;
2
+ using Rubberduck . Parsing . Symbols ;
3
+ using System ;
4
+ using System . Collections . Generic ;
5
+ using System . Linq ;
6
+ using System . Text ;
7
+ using System . Threading . Tasks ;
8
+
9
+ namespace Rubberduck . Refactorings . Common
10
+ {
11
+ public static class ModuleBodyElementDeclarationExtensions
12
+ {
13
+ /// <summary>
14
+ /// Returns ModuleBodyElementDeclaration signature with an ImprovedArgument list
15
+ /// 1. Explicitly declares Property Let\Set value parameter as ByVal
16
+ /// 2. Ensures UserDefined Type parameters are declared either explicitly or implicitly as ByRef
17
+ /// </summary>
18
+ /// <param name="declaration"></param>
19
+ /// <returns></returns>
20
+ public static string FullMemberSignature ( this ModuleBodyElementDeclaration declaration ,
21
+ string accessibility = null ,
22
+ string newIdentifier = null )
23
+ {
24
+ var accessibilityToken = declaration . Accessibility . Equals ( Accessibility . Implicit )
25
+ ? Tokens . Public
26
+ : $ "{ declaration . Accessibility . ToString ( ) } ";
27
+
28
+ var asTypeClause = declaration . AsTypeName == null
29
+ ? string . Empty
30
+ : $ " { Tokens . As } { declaration . AsTypeName } ";
31
+
32
+ var fullSignatureFormat = RetrieveFullSignatureFormat ( declaration ) ;
33
+
34
+ var fullSignature = string . Format ( fullSignatureFormat ,
35
+ accessibility ?? accessibilityToken ,
36
+ newIdentifier ?? declaration . IdentifierName ,
37
+ ImprovedArgumentList ( declaration ) ,
38
+ asTypeClause ) ;
39
+
40
+ return fullSignature . Trim ( ) ;
41
+ }
42
+
43
+ public static string AsCodeBlock ( this ModuleBodyElementDeclaration declaration ,
44
+ string content = null ,
45
+ string accessibility = null ,
46
+ string newIdentifier = null )
47
+ {
48
+ var endStatement = string . Empty ;
49
+ switch ( declaration . Context )
50
+ {
51
+ case VBAParser . SubStmtContext _:
52
+ endStatement = $ "{ Tokens . End } { Tokens . Sub } ";
53
+ break ;
54
+ case VBAParser . FunctionStmtContext _:
55
+ endStatement = $ "{ Tokens . End } { Tokens . Function } ";
56
+ break ;
57
+ case VBAParser . PropertyGetStmtContext _:
58
+ case VBAParser . PropertyLetStmtContext _:
59
+ case VBAParser . PropertySetStmtContext _:
60
+ endStatement = $ "{ Tokens . End } { Tokens . Property } ";
61
+ break ;
62
+ default :
63
+ throw new ArgumentException ( ) ;
64
+ }
65
+
66
+ if ( content != null )
67
+ {
68
+ return string . Format ( "{0}{1}{2}{1}{3}{1}" ,
69
+ FullMemberSignature ( declaration , accessibility , newIdentifier ) ,
70
+ Environment . NewLine ,
71
+ content ,
72
+ endStatement ) ;
73
+ }
74
+
75
+ return string . Format ( "{0}{1}{2}{1}" ,
76
+ FullMemberSignature ( declaration , accessibility , newIdentifier ) ,
77
+ Environment . NewLine ,
78
+ endStatement ) ;
79
+ }
80
+
81
+ /// <summary>
82
+ /// 1. Explicitly declares Property Let\Set value parameter as ByVal
83
+ /// 2. Ensures UserDefined Type parameters are declared either explicitly or implicitly as ByRef
84
+ /// </summary>
85
+ /// <param name="declaration"></param>
86
+ /// <returns></returns>
87
+ public static string ImprovedArgumentList ( this ModuleBodyElementDeclaration declaration )
88
+ {
89
+ var arguments = Enumerable . Empty < string > ( ) ;
90
+ if ( declaration is IParameterizedDeclaration parameterizedDeclaration )
91
+ {
92
+ arguments = parameterizedDeclaration . Parameters
93
+ . OrderBy ( parameter => parameter . Selection )
94
+ . Select ( parameter => BuildParameterDeclaration (
95
+ parameter ,
96
+ parameter . Equals ( parameterizedDeclaration . Parameters . LastOrDefault ( ) )
97
+ && declaration . DeclarationType . HasFlag ( DeclarationType . Property )
98
+ && ! declaration . DeclarationType . Equals ( DeclarationType . PropertyGet ) ) ) ;
99
+ }
100
+ return $ "{ string . Join ( ", " , arguments ) } ";
101
+ }
102
+
103
+ private static string BuildParameterDeclaration ( ParameterDeclaration parameter , bool forceExplicitByValAccess )
104
+ {
105
+ var accessibility = parameter . IsImplicitByRef
106
+ ? string . Empty
107
+ : parameter . IsByRef
108
+ ? Tokens . ByRef
109
+ : Tokens . ByVal ;
110
+
111
+ if ( forceExplicitByValAccess )
112
+ {
113
+ accessibility = Tokens . ByVal ;
114
+ }
115
+
116
+ if ( accessibility . Equals ( Tokens . ByVal )
117
+ && ( parameter . AsTypeDeclaration ? . DeclarationType . HasFlag ( DeclarationType . UserDefinedType ) ?? false ) )
118
+ {
119
+ accessibility = Tokens . ByRef ;
120
+ }
121
+
122
+ var name = parameter . IsArray
123
+ ? $ "{ parameter . IdentifierName } ()"
124
+ : parameter . IdentifierName ;
125
+
126
+ var optional = parameter . IsParamArray
127
+ ? Tokens . ParamArray
128
+ : parameter . IsOptional
129
+ ? Tokens . Optional
130
+ : string . Empty ;
131
+
132
+ var defaultValue = parameter . DefaultValue ;
133
+
134
+ return $ "{ FormatStandardElement ( optional ) } { FormatStandardElement ( accessibility ) } { FormatStandardElement ( name ) } { FormattedAsTypeName ( parameter . AsTypeName ) } { FormattedDefaultValue ( defaultValue ) } ". Trim ( ) ;
135
+ }
136
+
137
+ private static string RetrieveFullSignatureFormat ( Declaration declaration )
138
+ {
139
+ var fullSignatureFormat = $ "{{0}} THE_MEMBER_TYPE {{1}}({{2}}){{3}}";
140
+
141
+ switch ( declaration . Context )
142
+ {
143
+ case VBAParser . SubStmtContext _:
144
+ fullSignatureFormat = fullSignatureFormat . Replace ( "THE_MEMBER_TYPE" , Tokens . Sub ) ;
145
+ break ;
146
+ case VBAParser . FunctionStmtContext _:
147
+ fullSignatureFormat = fullSignatureFormat . Replace ( "THE_MEMBER_TYPE" , Tokens . Function ) ;
148
+ break ;
149
+ case VBAParser . PropertyGetStmtContext _:
150
+ fullSignatureFormat = fullSignatureFormat . Replace ( "THE_MEMBER_TYPE" , $ "{ Tokens . Property } { Tokens . Get } ") ;
151
+ break ;
152
+ case VBAParser . PropertyLetStmtContext _:
153
+ fullSignatureFormat = fullSignatureFormat . Replace ( "THE_MEMBER_TYPE" , $ "{ Tokens . Property } { Tokens . Let } ") ;
154
+ break ;
155
+ case VBAParser . PropertySetStmtContext _:
156
+ fullSignatureFormat = fullSignatureFormat . Replace ( "THE_MEMBER_TYPE" , $ "{ Tokens . Property } { Tokens . Set } ") ;
157
+ break ;
158
+ default :
159
+ throw new ArgumentException ( ) ;
160
+ }
161
+ return fullSignatureFormat ;
162
+ }
163
+
164
+ private static string FormatStandardElement ( string element ) => string . IsNullOrEmpty ( element )
165
+ ? string . Empty
166
+ : $ "{ element } ";
167
+
168
+ private static string FormattedAsTypeName ( string AsTypeName ) => string . IsNullOrEmpty ( AsTypeName )
169
+ ? string . Empty
170
+ : $ "As { AsTypeName } ";
171
+
172
+ private static string FormattedDefaultValue ( string DefaultValue ) => string . IsNullOrEmpty ( DefaultValue )
173
+ ? string . Empty
174
+ : $ "= { DefaultValue } ";
175
+ }
176
+ }
0 commit comments