Rubberduck: Code Metrics faceplanting

Created on 21 Feb 2019  路  3Comments  路  Source: rubberduck-vba/Rubberduck

Rubberduck version information
Version 2.4.0.4532
OS: Microsoft Windows NT 10.0.17763.0, x64
Host Product: Microsoft Office x64
Host Version: 16.0.11231.20174
Host Executable: MSACCESS.EXE

Description
After a lengthy session, I managed to arrive to a state where code metrics would not run correctly, throwing an exception. Because the code metrics is run as part of parsing, the exception runs up all the parsing stack, resulting in a parser state of Unexpected error

To Reproduce
Not sure yet. Will update.

Expected behavior
Code metrics should not throw exceptions to the parser. Ever. Let it faceplant without pulling down everyone down.

Logfile

2019-02-21 07:18:54.1670;ERROR-2.4.0.4532;Rubberduck.Parsing.VBA.ParseCoordinator;Unexpected exception thrown in parsing run. (thread 47).;System.InvalidOperationException: Sequence contains no elements
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at Rubberduck.CodeAnalysis.CodeMetrics.CyclomaticComplexityListener.ExitFunctionStmt(FunctionStmtContext context) in C:\projects\rubberduck\Rubberduck.CodeAnalysis\CodeMetrics\CyclomaticComplexityMetric.cs:line 62
   at Rubberduck.Parsing.Grammar.VBAParser.FunctionStmtContext.ExitRule(IParseTreeListener listener) in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 8858
   at Rubberduck.Parsing.VBA.CombinedParseTreeListener.ExitEveryRule(ParserRuleContext ctx) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\CombinedParseTreeListener.cs:line 30
   at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
   at Rubberduck.CodeAnalysis.CodeMetrics.CodeMetricsAnalyst.TraverseModuleTree(IParseTree parseTree, DeclarationFinder declarationFinder, QualifiedModuleName moduleName) in C:\projects\rubberduck\Rubberduck.CodeAnalysis\CodeMetrics\CodeMetricsAnalyst.cs:line 54
   at Rubberduck.CodeAnalysis.CodeMetrics.CodeMetricsAnalyst.<>c__DisplayClass2_0.<GetMetrics>b__0(KeyValuePair`2 moduleTree) in C:\projects\rubberduck\Rubberduck.CodeAnalysis\CodeMetrics\CodeMetricsAnalyst.cs:line 31
   at System.Linq.Enumerable.<SelectManyIterator>d__17`2.MoveNext()
   at Rubberduck.CodeAnalysis.CodeMetrics.CodeMetricsAnalyst.<GetMetrics>d__2.MoveNext() in C:\projects\rubberduck\Rubberduck.CodeAnalysis\CodeMetrics\CodeMetricsAnalyst.cs:line 31
   at System.Linq.Lookup`2.Create[TSource](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at System.Linq.GroupedEnumerable`3.GetEnumerator()
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at Rubberduck.CodeAnalysis.CodeMetrics.CodeMetricsViewModel.Synchronize(IEnumerable`1 declarations) in C:\projects\rubberduck\Rubberduck.Core\CodeAnalysis\CodeMetrics\CodeMetricsViewModel.cs:line 66
   at Rubberduck.CodeAnalysis.CodeMetrics.CodeMetricsViewModel.OnStateChanged(Object sender, ParserStateEventArgs e) in C:\projects\rubberduck\Rubberduck.Core\CodeAnalysis\CodeMetrics\CodeMetricsViewModel.cs:line 61
   at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
   at Rubberduck.Parsing.VBA.RubberduckParserState.OnStateChanged(Object requestor, CancellationToken token, ParserState state, ParserState oldStatus) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\RubberduckParserState.cs:line 402
   at Rubberduck.Parsing.VBA.RubberduckParserState.SetStatusAndFireStateChanged(Object requestor, ParserState status, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\RubberduckParserState.cs:line 617
   at Rubberduck.Parsing.VBA.ParserStateManagerBase.SetStatusAndFireStateChanged(Object requestor, ParserState status, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParserStateManagerBase.cs:line 52
   at Rubberduck.Parsing.VBA.ParseCoordinator.ExecuteCommonParseActivities(IReadOnlyCollection`1 toParse, IReadOnlyCollection`1 toReresolveReferencesInput, IReadOnlyCollection`1 newProjectIds, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 336
   at Rubberduck.Parsing.VBA.ParseCoordinator.ParseAllInternal(Object requestor, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 511
   at Rubberduck.Parsing.VBA.ParseCoordinator.ParseAll(Object requestor) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 415

Additional context
Restarting the program and reparsing worked. This may be due to having had parsing using bad code module. Furthermore, I was changing the name via the properties toolwindows. The parsing starts as soon as I type a letter and get cancelled when I type the next. It's conceivable that while I was renaming, it got confused about what's what and code metrics picks it up. Once it arrives into that state, reparsing does not apparently help; only restarting.

bug difficulty-02-ducky feature-code-metrics regression up-for-grabs

Most helpful comment

It might be a good idea to wrap the execution of the event handlers in RubberduckParserState.OnStateChanged into a try catch block and then log and swallow all exceptions there, with the exception of OperationCanceledException.

All 3 comments

Sounds like CodeMetricsAnalyst could try/catch its work and wrap any exception inside some CodeMetricsException (with the original exception as the InnerException), and then we could catch that in OnStateChanged (?), log it, and not break the entire parser state.

Wouldn't fix it, but would help segregating state-change handlers' exceptions from the rest of the parse run.

It might be a good idea to wrap the execution of the event handlers in RubberduckParserState.OnStateChanged into a try catch block and then log and swallow all exceptions there, with the exception of OperationCanceledException.

I'm almost positive the failing line of code is this one: https://github.com/rubberduck-vba/Rubberduck/blob/next/Rubberduck.Core/Navigation/CodeExplorer/CodeExplorerItemViewModel.cs#L44

I suspect what is happening is that a Declaration is passing the equity test there that shouldn't be. That would prevent the node from being removed from the active tree, and since the context on the Declaration is the one that is being evaluated against the now current parse tree, the context search fails in the listener.

Ref #4714

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  3Comments

Gener4tor picture Gener4tor  路  3Comments

retailcoder picture retailcoder  路  3Comments

connerk picture connerk  路  3Comments

Hosch250 picture Hosch250  路  3Comments