1- using System . Collections . Generic ;
2- using System . Linq ;
3- using Rubberduck . Parsing . VBA ;
1+ using Antlr4 . Runtime . Misc ;
42using Antlr4 . Runtime . Tree ;
53using Rubberduck . Parsing . Grammar ;
6- using Rubberduck . VBEditor ;
7- using Antlr4 . Runtime . Misc ;
84using 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 ;
1010
1111namespace Rubberduck . Navigation . CodeMetrics
1212{
1313 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 ( ) { }
2116
2217 public IEnumerable < ModuleMetricsResult > ModuleMetrics ( RubberduckParserState state )
2318 {
2419 if ( state == null || ! state . AllUserDeclarations . Any ( ) )
2520 {
26- // must not return Enumerable.Empty
21+ // can not explicitly return Enumerable.Empty, this is equivalent
2722 yield break ;
2823 }
2924
@@ -42,8 +37,9 @@ public ModuleMetricsResult GetModuleResult(RubberduckParserState state, Qualifie
4237
4338 private ModuleMetricsResult GetModuleResult ( QualifiedModuleName qmn , IParseTree moduleTree , DeclarationFinder declarationFinder )
4439 {
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 ) ;
4743 ParseTreeWalker . Default . Walk ( cmListener , moduleTree ) ;
4844 return cmListener . GetMetricsResult ( qmn ) ;
4945 }
@@ -52,31 +48,36 @@ private ModuleMetricsResult GetModuleResult(QualifiedModuleName qmn, IParseTree
5248 private class CodeMetricsListener : VBAParserBaseListener
5349 {
5450 private readonly DeclarationFinder _finder ;
55- private readonly IIndenterSettings _indenterSettings ;
5651
5752 private Declaration _currentMember ;
53+ private int _currentNestingLevel = 0 ;
54+ private int _currentMaxNesting = 0 ;
5855 private List < CodeMetricsResult > _results = new List < CodeMetricsResult > ( ) ;
5956 private List < CodeMetricsResult > _moduleResults = new List < CodeMetricsResult > ( ) ;
6057
6158 private List < MemberMetricsResult > _memberResults = new List < MemberMetricsResult > ( ) ;
6259
63- public CodeMetricsListener ( DeclarationFinder finder , IIndenterSettings indenterSettings )
60+ public CodeMetricsListener ( DeclarationFinder finder )
6461 {
6562 _finder = finder ;
66- _indenterSettings = indenterSettings ;
6763 }
68-
69- public override void EnterEndOfLine ( [ NotNull ] VBAParser . EndOfLineContext context )
64+ public override void EnterBlock ( [ NotNull ] VBAParser . BlockContext context )
7065 {
71- int followingIndentationLevel = 0 ;
72- // we have a proper newline
73- if ( context . NEWLINE ( ) != null )
66+ _currentNestingLevel ++ ;
67+ if ( _currentNestingLevel > _currentMaxNesting )
7468 {
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 ;
7870 }
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 ) ) ;
8081 }
8182
8283 public override void EnterIfStmt ( [ NotNull ] VBAParser . IfStmtContext context )
@@ -160,27 +161,15 @@ public override void ExitPropertySetStmt([NotNull] VBAParser.PropertySetStmtCont
160161 {
161162 ExitMeasurableMember ( ) ;
162163 }
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- }
170164
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-
180165 private void ExitMeasurableMember ( )
181166 {
167+ Debug . Assert ( _currentNestingLevel == 0 , "Unexpected Nesting Level when exiting Measurable Member" ) ;
168+ _results . Add ( new CodeMetricsResult ( 0 , 0 , _currentMaxNesting ) ) ;
182169 _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 ;
184173 _currentMember = null ;
185174 }
186175
0 commit comments