1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using Rubberduck . Parsing ;
5
+ using Rubberduck . Parsing . Grammar ;
6
+ using Rubberduck . Parsing . VBA ;
7
+ using Rubberduck . VBEditor ;
8
+
9
+ namespace Rubberduck . Inspections
10
+ {
11
+ public class ProcedureShouldBeFunctionInspectionResult : CodeInspectionResultBase
12
+ {
13
+ private readonly IEnumerable < CodeInspectionQuickFix > _quickFixes ;
14
+
15
+ public ProcedureShouldBeFunctionInspectionResult ( IInspection inspection , RubberduckParserState state , QualifiedContext < VBAParser . ArgListContext > argListQualifiedContext , QualifiedContext < VBAParser . SubStmtContext > subStmtQualifiedContext )
16
+ : base ( inspection ,
17
+ string . Format ( inspection . Description , subStmtQualifiedContext . Context . ambiguousIdentifier ( ) . GetText ( ) ) ,
18
+ subStmtQualifiedContext . ModuleName ,
19
+ subStmtQualifiedContext . Context . ambiguousIdentifier ( ) )
20
+ {
21
+ _quickFixes = new [ ]
22
+ {
23
+ new ChangeProcedureToFunction ( state , argListQualifiedContext , subStmtQualifiedContext , QualifiedSelection ) ,
24
+ } ;
25
+ }
26
+
27
+ public override IEnumerable < CodeInspectionQuickFix > QuickFixes { get { return _quickFixes ; } }
28
+ }
29
+
30
+ public class ChangeProcedureToFunction : CodeInspectionQuickFix
31
+ {
32
+ private readonly RubberduckParserState _state ;
33
+ private readonly QualifiedContext < VBAParser . ArgListContext > _argListQualifiedContext ;
34
+ private readonly QualifiedContext < VBAParser . SubStmtContext > _subStmtQualifiedContext ;
35
+ private readonly QualifiedContext < VBAParser . ArgContext > _argQualifiedContext ;
36
+
37
+ public ChangeProcedureToFunction ( RubberduckParserState state ,
38
+ QualifiedContext < VBAParser . ArgListContext > argListQualifiedContext ,
39
+ QualifiedContext < VBAParser . SubStmtContext > subStmtQualifiedContext ,
40
+ QualifiedSelection selection )
41
+ : base ( subStmtQualifiedContext . Context , selection , InspectionsUI . ProcedureShouldBeFunctionInspectionQuickFix )
42
+ {
43
+ _state = state ;
44
+ _argListQualifiedContext = argListQualifiedContext ;
45
+ _subStmtQualifiedContext = subStmtQualifiedContext ;
46
+ _argQualifiedContext = new QualifiedContext < VBAParser . ArgContext > ( _argListQualifiedContext . ModuleName ,
47
+ _argListQualifiedContext . Context . arg ( )
48
+ . First ( a => a . BYREF ( ) != null || ( a . BYREF ( ) == null && a . BYVAL ( ) == null ) ) ) ;
49
+ }
50
+
51
+ public override void Fix ( )
52
+ {
53
+ UpdateSignature ( ) ;
54
+ UpdateCalls ( ) ;
55
+ }
56
+
57
+ private void UpdateSignature ( )
58
+ {
59
+ var argListText = _argListQualifiedContext . Context . GetText ( ) ;
60
+ var subStmtText = _subStmtQualifiedContext . Context . GetText ( ) ;
61
+ var argText = _argQualifiedContext . Context . GetText ( ) ;
62
+
63
+ var newArgText = argText . Contains ( "ByRef " ) ? argText . Replace ( "ByRef " , "ByVal " ) : "ByVal " + argText ;
64
+
65
+ var newFunctionWithoutReturn = subStmtText . Insert ( subStmtText . IndexOf ( argListText , StringComparison . Ordinal ) + argListText . Length ,
66
+ _argQualifiedContext . Context . asTypeClause ( ) . GetText ( ) )
67
+ . Replace ( "Sub" , "Function" )
68
+ . Replace ( argText , newArgText ) ;
69
+
70
+ var newfunctionWithReturn = newFunctionWithoutReturn
71
+ . Insert ( newFunctionWithoutReturn . LastIndexOf ( Environment . NewLine , StringComparison . Ordinal ) ,
72
+ " " + _subStmtQualifiedContext . Context . ambiguousIdentifier ( ) . GetText ( ) +
73
+ " = " + _argQualifiedContext . Context . ambiguousIdentifier ( ) . GetText ( ) ) ;
74
+
75
+ var rewriter = _state . GetRewriter ( _subStmtQualifiedContext . ModuleName . Component ) ;
76
+ rewriter . Replace ( _subStmtQualifiedContext . Context . Start , newfunctionWithReturn ) ;
77
+
78
+ var module = _argListQualifiedContext . ModuleName . Component . CodeModule ;
79
+
80
+ module . DeleteLines ( _subStmtQualifiedContext . Context . Start . Line ,
81
+ _subStmtQualifiedContext . Context . Stop . Line - _subStmtQualifiedContext . Context . Start . Line + 1 ) ;
82
+ module . InsertLines ( _subStmtQualifiedContext . Context . Start . Line , newfunctionWithReturn ) ;
83
+ }
84
+
85
+ private void UpdateCalls ( )
86
+ {
87
+ var procedureName = _subStmtQualifiedContext . Context . ambiguousIdentifier ( ) . GetText ( ) ;
88
+
89
+ var procedure =
90
+ _state . AllDeclarations . SingleOrDefault ( d =>
91
+ ! d . IsBuiltIn &&
92
+ d . IdentifierName == procedureName &&
93
+ d . Context is VBAParser . SubStmtContext &&
94
+ d . ComponentName == _subStmtQualifiedContext . ModuleName . ComponentName &&
95
+ d . Project == _subStmtQualifiedContext . ModuleName . Project ) ;
96
+
97
+ if ( procedure == null ) { return ; }
98
+
99
+ foreach ( var reference in procedure . References . OrderByDescending ( o => o . Selection . StartLine ) . ThenByDescending ( d => d . Selection . StartColumn ) )
100
+ {
101
+ var module = reference . QualifiedModuleName . Component . CodeModule ;
102
+
103
+ var referenceParent = reference . Context . Parent as VBAParser . ICS_B_ProcedureCallContext ;
104
+ if ( referenceParent == null ) { continue ; }
105
+
106
+ var referenceText = reference . Context . Parent . GetText ( ) ;
107
+ var newCall = referenceParent . argsCall ( ) . argCall ( ) . ToList ( ) . ElementAt ( _argListQualifiedContext . Context . arg ( ) . ToList ( ) . IndexOf ( _argQualifiedContext . Context ) ) . GetText ( ) +
108
+ " = " + _subStmtQualifiedContext . Context . ambiguousIdentifier ( ) . GetText ( ) +
109
+ "(" + referenceParent . argsCall ( ) . GetText ( ) + ")" ;
110
+
111
+ var oldLines = module . Lines [ reference . Selection . StartLine , reference . Selection . LineCount ] ;
112
+
113
+ var newText = oldLines . Remove ( reference . Selection . StartColumn - 1 , referenceText . Length )
114
+ . Insert ( reference . Selection . StartColumn - 1 , newCall ) ;
115
+
116
+ module . DeleteLines ( reference . Selection . StartLine , reference . Selection . LineCount ) ;
117
+ module . InsertLines ( reference . Selection . StartLine , newText ) ;
118
+ }
119
+ }
120
+ }
121
+ }
0 commit comments