What’s Cooking for Rubberduck 2.5.x

If you’ve been following the project all along, this isn’t going to be news, but we kind of missed the v2.4.2 milestone we were slated to release back in April, and here we are with our [next] branch (“pre-release” builds) being a whopping 580+ commits ahead of [master] (“green-release” builds). These commits change a lot of things… so much that v2.4.1 will end up being the only “green-release” of the 2.4.x release cycle, and we’ve decided next release will have to be 2.5.0 – but what is it specifically that warrants such delays and the +1 on the minor version number?

ITypeLib

Perhaps the most important set of changes since v1.2 where we introduced an ANTLR-generated parser, this internal API was actually introduced last year, but until relatively recently it was only used to make the unit testing feature fully host-agnostic (i.e. unit testing works in every host application since) and to retrieve project-level precompiler constants, which closed an otherwise desperate gaping hole in Rubberduck’s understanding of the code that’s in the editor. We are also using it to retrieve and manipulate project references, and possibly in other places I don’t recall at the moment.

But this internal API unlocks much more power than that, and until very recently we hadn’t really started tapping into it. During the v2.5.x cycle, we’ll be using it to instantly populate the Code Explorer toolwindow with tree nodes that still drill down to member level – of course Rubberduck won’t know where a procedure is referenced or be able to refactor anything until parsing has actually occurred, but the project should be instantly navigatable regardless.

We have already begun leveraging this ITypeLib API to augment resolver capabilities, notably with regards to member and module attributes: we can now read most of their values without needing to export anything to any temp file.

So what this API does, is that it taps into VBA/VB6’s internal storage: you may not realize, but compiling your VBA code, internally, creates a COM type library. With this API we can safely query this type library and model user code modules and their members just like any other COM type library, e.g. project references. This means Rubberduck is be able to know what interfaces a document module implements – in other words, when we fully leverage this API we will be able to tell that Sheet1 is a Worksheet and that ThisWorkbook is a Workbook… which means a library-specific inspection like “sheet accessed using string” can now work exactly as intended. We already correctly identify event handler procedures in document modules thanks to these new capabilities; it might seem simple on the surface, but knowing that Sheet1 is a Worksheet and that this Worksheet_Change procedure is handling the Change event of that Worksheet interface, requires looking well beyond the code… and a side-effect of this, is that “procedure not used” no longer fires inspection results for them (the inspection already ignored event handler procedures… all it needed was for the resolver to recognize event handlers in document modules as such).

Default Member Resolution

Once again, a tremendous amount of effort went into augmenting resolver capabilities. This piece of the puzzle is the cornerstone that makes everything else fall into place: if we’re able to issue an inspection result when a variable is never referenced, it’s because the resolver processed all the parse trees and located no references to that variable. But it’s much more than just unused variables: the resolver is the literal central nervous system of Rubberduck – if the resolver doesn’t work well, everything else falls apart.

Except, resolving VBA code correctly is hard. We have an inspection that means to flag missing Set keywords, and until recently it would fire false positives whenever implicit default member calls were involved. What’s that? Picture this code:

Range("A1") = Range("B1")

What’s really happening is this:

Global.Range("A1").[_Default] = Global.Range("A1").[_Default]

But in order to know that, Rubberduck needs to know much more about the code than just what the code is saying: it needs to know that Range is an implicitly-qualified member call on Global (or is it? what if that very same code is in the code-behind of the Sheet3 module?), and that it has a default member that’s the target of this assignment on the left-hand side, and the provider of a value on the right-hand side; it needs to know that this default member yields a Variant (and not another object, which may have its own default member, which might yield an object, which may have a default member, which… so yeah, recursive resolution). And once it knows all that, it can warn you about implicit default member assignments, and soon about any implicit default member call – and help you make them explicit!

Bang notation now also resolves correctly. You write this:

Dim rs As ADODB.Recordset
Set rs = conn.Execute(procName)
Debug.Print rs!Field1

Rubberduck sees this:

Dim rs As ADODB.Recordset
Set rs = conn.Execute(procName)
Debug.Print rs.Fields.Item("Field1").Value

…and this means we’ll soon be able to offer quickfixes/refactorings that turn one notation into the other, and vice-versa.

This is where Rubberduck’s resolver is at, and I need to pinch myself to believe just how crazy wicked awesome it’s becoming – it’s not perfect, but I’m positive, and I’ll repeat this even though it’s been the case for a very long while, but no other VBIDE add-in understands VBA as deeply as Rubberduck.

Moq.Mock<T>

Rubberduck uses the Moq framework for its thousands of unit tests. With it, we’re able to inject “mock” implementations of any abstract dependency: unit testing isn’t complete without a mocking framework, and there’s none for VBA, …for now.

The amount of work involved is astounding, but the important and hard parts are working and we’re just a few road-bumps away from having a COM-visible Moq wrapper API that VBA code can consume to mock any class – your Class1 module or ISomething interface, a ListObject Excel table, any Word.Range, ADODB.Connection, or Scripting.FileSystemObject. This is a massive and complete game-changer that takes unit testing VBA code to a whole new level of credibility.


Timeline

To be honest, there isn’t really any timeline on the table: the 2.5.0 green-release will happen when it does. In the meantime you’ll want to keep an eye on pre-release builds: in the next couple of weeks we’ll be polishing the new features, reviewing what few inspection false positives remain, address a number of prioritized bugs (the all-or-nothing collapsing/expanding of grouping grids, for one), and then we’ll be ready.

There’s plenty of work for all levels and skills, you’re welcome to help us!

3 thoughts on “What’s Cooking for Rubberduck 2.5.x”

  1. I would be happy to assist in any way that I could. Have put together small C# applications, am familiar with the language. Have never worked on a programming project as a part of a team. I think I could be useful if small, discrete problems were there to be handle. I do not want to cause more headaches than I solve and will quickly bow out or tell you that I am wasting your time if I feel that this will be case (maybe a year or two more :-p of experience)

    Best, Evan

    Liked by 1 person

    1. Hey Evan,
      Would you be surprised if I told you that more than a handful of contributors have written their very first lines of C# (coming from VBA) while contributing to Rubberduck, starting with the project’s co-founder, my friend Chris McClellan! We are always happy to help and hand-hold new contributors of all skill levels, from forking the repository to taking your first (second, third… twentieth) pull request to the finish line!
      There’s work for everyone, at various levels of complexity (we try to “rate” the difficulty of each with labels, but that’s obviously subjective): there’s low-level COM and Win32 pointer stuff, mind-blowingly difficult abstractions around the VB6/VBA language itself, but then there’s also everything that builds on top of that, code inspection ideas (some super simple, others we don’t even know how to go about yet), a ton of tiny little things that need tweaks here & there, and so on; have you had a peek at some of the 800 currently open issues? A little over 150 are bugs that need attention (some could be duplicates), the rest are all feature requests, ideas, discussions…
      …and that’s just code-wise: beyond the code, the project’s wiki could use a refresher (some screenshots already date back a few years!), new translations are of course always welcome, and if nothing speaks to you then that’s fine too, you can always just “star” the repository and help bring us closer to taking the #1 spot on GitHub for repositories mentioning “VBA”!
      See the “contributing” wiki page for info about the initial setup, and don’t hesitate to create a new “support” issue if you have any questions!
      https://github.com/rubberduck-vba/Rubberduck/wiki/Contributing
      Note: we are currently building with Visual Studio 2017 (Community Edition [free for open-source work] is fine)… which puts us in a bit of a limbo until .net core 3.0 is officially released, since apparently Microsoft took down the download link for VS2017 and until we can adjust our build process to work with the latest & greatest, Rubberduck unfortunately won’t build in VS2019.

      Liked by 1 person

Leave a comment