1
- using System . Collections . Generic ;
2
- using System . Linq ;
3
- using Rubberduck . Parsing . VBA ;
1
+ using Antlr4 . Runtime . Misc ;
4
2
using Antlr4 . Runtime . Tree ;
5
3
using Rubberduck . Parsing . Grammar ;
6
- using Rubberduck . VBEditor ;
7
- using Antlr4 . Runtime . Misc ;
8
4
using Rubberduck . Parsing . Symbols ;
9
- using Rubberduck . SmartIndenter ;
5
+ using Rubberduck . Parsing . VBA ;
6
+ using Rubberduck . VBEditor ;
7
+ using System . Collections . Generic ;
8
+ using System . Diagnostics ;
9
+ using System . Linq ;
10
10
11
11
namespace Rubberduck . Navigation . CodeMetrics
12
12
{
13
13
public class CodeMetricsAnalyst : ICodeMetricsAnalyst
14
- {
15
- private readonly IIndenterSettings _indenterSettings ;
16
-
17
- public CodeMetricsAnalyst ( IIndenterSettings indenterSettings )
18
- {
19
- _indenterSettings = indenterSettings ;
20
- }
14
+ {
15
+ public CodeMetricsAnalyst ( ) { }
21
16
22
17
public IEnumerable < ModuleMetricsResult > ModuleMetrics ( RubberduckParserState state )
23
18
{
24
19
if ( state == null || ! state . AllUserDeclarations . Any ( ) )
25
20
{
26
- // must not return Enumerable.Empty
21
+ // can not explicitly return Enumerable.Empty, this is equivalent
27
22
yield break ;
28
23
}
29
24
@@ -42,8 +37,9 @@ public ModuleMetricsResult GetModuleResult(RubberduckParserState state, Qualifie
42
37
43
38
private ModuleMetricsResult GetModuleResult ( QualifiedModuleName qmn , IParseTree moduleTree , DeclarationFinder declarationFinder )
44
39
{
45
- // Consider rewrite as visitor? That should make subtrees easier and allow us to expand metrics
46
- var cmListener = new CodeMetricsListener ( declarationFinder , _indenterSettings ) ;
40
+ // FIXME rewrite as visitor, see discussion on pulls#3522
41
+ // That should make subtrees easier and allow us to expand metrics
42
+ var cmListener = new CodeMetricsListener ( declarationFinder ) ;
47
43
ParseTreeWalker . Default . Walk ( cmListener , moduleTree ) ;
48
44
return cmListener . GetMetricsResult ( qmn ) ;
49
45
}
@@ -52,31 +48,36 @@ private ModuleMetricsResult GetModuleResult(QualifiedModuleName qmn, IParseTree
52
48
private class CodeMetricsListener : VBAParserBaseListener
53
49
{
54
50
private readonly DeclarationFinder _finder ;
55
- private readonly IIndenterSettings _indenterSettings ;
56
51
57
52
private Declaration _currentMember ;
53
+ private int _currentNestingLevel = 0 ;
54
+ private int _currentMaxNesting = 0 ;
58
55
private List < CodeMetricsResult > _results = new List < CodeMetricsResult > ( ) ;
59
56
private List < CodeMetricsResult > _moduleResults = new List < CodeMetricsResult > ( ) ;
60
57
61
58
private List < MemberMetricsResult > _memberResults = new List < MemberMetricsResult > ( ) ;
62
59
63
- public CodeMetricsListener ( DeclarationFinder finder , IIndenterSettings indenterSettings )
60
+ public CodeMetricsListener ( DeclarationFinder finder )
64
61
{
65
62
_finder = finder ;
66
- _indenterSettings = indenterSettings ;
67
63
}
68
-
69
- public override void EnterEndOfLine ( [ NotNull ] VBAParser . EndOfLineContext context )
64
+ public override void EnterBlock ( [ NotNull ] VBAParser . BlockContext context )
70
65
{
71
- int followingIndentationLevel = 0 ;
72
- // we have a proper newline
73
- if ( context . NEWLINE ( ) != null )
66
+ _currentNestingLevel ++ ;
67
+ if ( _currentNestingLevel > _currentMaxNesting )
74
68
{
75
- // the last whitespace, which is the one in front of the next line's contents
76
- var followingWhitespace = context . whiteSpace ( ) . LastOrDefault ( ) ;
77
- followingIndentationLevel = IndentationLevelFromWhitespace ( followingWhitespace ) ;
69
+ _currentMaxNesting = _currentNestingLevel ;
78
70
}
79
- ( _currentMember == null ? _moduleResults : _results ) . Add ( new CodeMetricsResult ( 1 , 0 , followingIndentationLevel ) ) ;
71
+ }
72
+
73
+ public override void ExitBlock ( [ NotNull ] VBAParser . BlockContext context )
74
+ {
75
+ _currentNestingLevel -- ;
76
+ }
77
+
78
+ public override void EnterEndOfLine ( [ NotNull ] VBAParser . EndOfLineContext context )
79
+ {
80
+ ( _currentMember == null ? _moduleResults : _results ) . Add ( new CodeMetricsResult ( 1 , 0 , 0 ) ) ;
80
81
}
81
82
82
83
public override void EnterIfStmt ( [ NotNull ] VBAParser . IfStmtContext context )
@@ -160,27 +161,15 @@ public override void ExitPropertySetStmt([NotNull] VBAParser.PropertySetStmtCont
160
161
{
161
162
ExitMeasurableMember ( ) ;
162
163
}
163
-
164
- public override void EnterBlockStmt ( [ NotNull ] VBAParser . BlockStmtContext context )
165
- {
166
- // there is a whitespace context here after the option of a statementLabel.
167
- // we need to account for that
168
- _results . Add ( new CodeMetricsResult ( 0 , 0 , IndentationLevelFromWhitespace ( context . whiteSpace ( ) ) ) ) ;
169
- }
170
164
171
- private int IndentationLevelFromWhitespace ( VBAParser . WhiteSpaceContext wsContext )
172
- {
173
- if ( wsContext == null ) return 0 ;
174
- // the only thing that contains underscores is the line-continuation at this point
175
- var lineContinuation = wsContext . children . LastOrDefault ( ( tree ) => tree . GetText ( ) . Contains ( "_" ) ) ;
176
- var index = lineContinuation != null ? wsContext . children . IndexOf ( lineContinuation ) : 0 ;
177
- return ( wsContext ? . ChildCount ?? 0 - index ) / _indenterSettings . IndentSpaces ;
178
- }
179
-
180
165
private void ExitMeasurableMember ( )
181
166
{
167
+ Debug . Assert ( _currentNestingLevel == 0 , "Unexpected Nesting Level when exiting Measurable Member" ) ;
168
+ _results . Add ( new CodeMetricsResult ( 0 , 0 , _currentMaxNesting ) ) ;
182
169
_memberResults . Add ( new MemberMetricsResult ( _currentMember , _results ) ) ;
183
- _results = new List < CodeMetricsResult > ( ) ; // reinitialize to drop results
170
+ // reset state
171
+ _results = new List < CodeMetricsResult > ( ) ;
172
+ _currentMaxNesting = 0 ;
184
173
_currentMember = null ;
185
174
}
186
175
0 commit comments