It would be most helpful if the reporting of resolver errors could include the line of VBA code that caused the error (even just a line number in the source code would be helpful).
Or am I just missing an option somewhere?
At present I can't use RubberDuck as I can never get past the resolver errors as I can't see errors in my code that Rubber Duck is getting stuck on
The resolver works with sub-expression trees though; it's aware of the current scope, but getting a line number could be tricky, especially since we have multiple threads (tasks actually) each working on a module. As for logging user code, we tried to avoid it as much as possible - some companies are very protective of the code they own, no matter how trivial.
Resolver errors in code that parses correctly are (very) likely a bug on our part, and always log an ERROR level entry - if you have logging enabled, you should have the details of the exception in there. Enabling TRACE level will produce more verbiage, but can reveal more useful information about what happened.
You can access the logs from the Settings dialog.
We haven't made reporting resolver bugs a feature, because these errors shouldn't be happening; logging is the best way for us to really identify the issue, because the problem is in our code, not yours.
Can you reproduce the error and upload the log file's contents here?
I have always had resolver errors until I found out that the problem came from arrays of arrays.
To further explain the issue, here is a code that throws a resolver error in Rubberduck 2.0.13:
Option Explicit
Public Sub Test()
Dim varTemp() As Variant
ReDim varTemp(0)
varTemp(0) = Array(0)
Debug.Print varTemp(0)(0)
End Sub
@jjth thanks for that MCVE!
2017-07-07 14:39:01.0875;ERROR-2.0.13.32288;Rubberduck.Parsing.VBA.ParseCoordinator;Exception thrown resolving 'VBAProject.Module1' (thread 7).;System.NullReferenceException: Object reference not set to an instance of an object.
at Rubberduck.Parsing.Binding.IndexDefaultBinding.ResolveLExpressionIsVariablePropertyFunctionNoParameters(IBoundExpression lExpression) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Binding\IndexDefaultBinding.cs:line 133
at Rubberduck.Parsing.Binding.IndexDefaultBinding.Resolve(IBoundExpression lExpression) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Binding\IndexDefaultBinding.cs:line 91
at Rubberduck.Parsing.Binding.IndexDefaultBinding.Resolve() in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Binding\IndexDefaultBinding.cs:line 79
at Rubberduck.Parsing.Binding.DefaultBindingContext.Resolve(Declaration module, Declaration parent, ParserRuleContext expression, IBoundExpression withBlockVariable, StatementResolutionContext statementContext) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Binding\DefaultBindingContext.cs:line 29
at Rubberduck.Parsing.Symbols.IdentifierReferenceResolver.ResolveDefault(ParserRuleContext expression, StatementResolutionContext statementContext, Boolean isAssignmentTarget, Boolean hasExplicitLetStatement) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Symbols\IdentifierReferenceResolver.cs:line 156
at Rubberduck.Parsing.Symbols.IdentifierReferenceResolver.ResolveOutputList(OutputListContext outputList) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Symbols\IdentifierReferenceResolver.cs:line 503
at Rubberduck.Parsing.Symbols.IdentifierReferenceResolver.Resolve(DebugPrintStmtContext context) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Symbols\IdentifierReferenceResolver.cs:line 807
at Rubberduck.Parsing.Symbols.IdentifierReferenceListener.EnterDebugPrintStmt(DebugPrintStmtContext context) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Symbols\IdentifierReferenceListener.cs:line 329
at Rubberduck.Parsing.Grammar.VBAParser.DebugPrintStmtContext.EnterRule(IParseTreeListener listener) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\Grammar\VBAParser.cs:line 3736
at Antlr4.Runtime.Tree.ParseTreeWalker.EnterRule(IParseTreeListener listener, IRuleNode r)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Antlr4.Runtime.Tree.ParseTreeWalker.Walk(IParseTreeListener listener, IParseTree t)
at Rubberduck.Parsing.VBA.ParseCoordinator.ResolveReferences(DeclarationFinder finder, QualifiedModuleName qualifiedName, IParseTree tree, CancellationToken token) in C:\Users\Mathieu\Documents\GitHub\Rubberduck (main)\Rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 591
2017-07-07 14:39:01.1495;DEBUG-2.0.13.32288;Rubberduck.Parsing.VBA.RubberduckParserState;Module 'Module1' state is changing to 'ResolverError' (thread 7);
Looks like we have a null reference exception thrown in IndexDefaultBinding, more precisely right here:
IBoundExpression boundExpression = null;
var asTypeName = lExpression.ReferencedDeclaration.AsTypeName;
We assume that a lExpression has a ReferencedDeclaration reference. Should be an easy exception to avoid, but I don't think resolving that expression is possible - so we'll bail out if there's no ReferencedDeclaration and move on; that should fix the issue. Except...
@MDoerner any thoughts on how we could try to resolve these? This code reproduces the issue, too:
Option Explicit
Public Sub Test()
Dim varTemp(0) As Variant
Set varTemp(0) = New Scripting.Dictionary
Debug.Print varTemp(0)("Key1")
End Sub
This resolves fine:
Option Explicit
Public Sub Test()
Dim varTemp(0) As Variant
Set varTemp(0) = New Scripting.Dictionary
Debug.Print varTemp(0).Count
End Sub
But we're not resolving .Count to Dictionary.Count, so that means if we replaced Scripting.Dictionary with a custom collection class, we'd have unresolved references, i.e. renaming the member would leave the code broken, which is a problem... except I'm not sure we can even try to resolve those, without tracking variant assignments and seeing that varTemp(0) contains a Scripting.Dictionary despite varTemp being declared as a Variant array. Quite a tough one.
The obvious work-around is to introduce a correctly typed local variable to capture the object reference retrieved from the first array index, and then have another instruction retrieve the nested subscript.
I will have to have a closer look at this.
I can already say that the way the type is determined in the code posted is problematic in more situations than the array of arrays. E.g. this should also be a problem for a function returning an array or an object with a default member taking arguments.
Maybe we should extend the LExpressionContext with the logic for deriving the type.
However, an index on a Variant. will never be resolved correctly. The problem is that there are situations in which it is entirely impossible to determine the value type of a Variant at compile time, e.g. if a procedure has a Variant argument.
from #3552 :
locData(i, j + 1) = locLinesList(i)(j)
Failing resolution of the type, I think the resolver should simply "move on" - that's what the resolver logic does by returning a null here... IOW catch that NullReferenceException and basically treat the expression as unresolvable.
Perhaps log a DEBUG or TRACE level entry with the exception and its stack trace and an INFO entry that mentions something like "Could not resolve a type for expression '{0}'" and put the expression text in there (can/should we do that?), so we have something to visually ensure we're only hitting that path on jagged arrays / index-of-an-index.
Much appreciated. This fix is working for me. #3552
All the examples should now resolve to unbound member calls. Can we close this?
Most helpful comment
Much appreciated. This fix is working for me. #3552