Blue Print of 2.x

The foundation of the project needed a bit of clean-up and restructuring. The Big Refactoring is now pretty much completed, and with it, summer 2015’s feature freeze:

Feature-freeze until this is completed. We need to implement proper DI/IoC and make the code testable, if not tested. No ifs, no buts.

So we’re ready to start implementing the new features of 2.0. But before, we need to reconnect the pieces, by moving code from the 1.x “RubberduckMenu” and “RefactorMenu” classes, and into these “ICommand” implementations.


 

So, What’s Cooking?

Tons. The new architecture allows us to write code that is aware of the host application. This means Unit Testing commands can be disabled when the host is Outlook, for example (it seems executing VBA code on-demand from a VBE add-in isn’t possible in Outlook – ideas welcome). It also means we can write code inspections that warn about implicit references to Application.ActiveWorkbook in Excel, but that don’t run when the host application is Access, Word, or PowerPoint. Things like that, and…

Regex Search & Replace is coming. We’ll need a way to hijack Ctrl+F and Ctrl+H!

Smart Indenter is coming. The owners of this awesome add-in have graciously offered their source code to the Rubberduck project a while ago already; 2.0 isn’t releasing without an embedded Smart Indenter!

More grammar fixes on the way. This means fewer parser errors, more accurate inspections, navigation and refactorings, i.e. a more reliable tool.

Source Control Integration continues to improve, and early minor releases of 2.x will likely see a new WPF/XAML UI.

More translations have been completed since the last release: 2.0 will speak English, French, Swedish, German, Japanese… and every other translation we receive a PR for in the next.. uh… …6-8 weeks.

Shiny new UI. Docked gridviews are turning into WPF treeviews; the “Rubberduck” menu has been revamped, and under the hood, everything changed. Might as well make 2.0 look like as much change happened!

Code Inspections and Quick-Fixes that take the host application into account, giving recommendations tailored for a given host API. Also, some of the coolest inspections we envisioned as fantasies a year ago, are now possible to implement.

More refactoring tools like inline method, encapsulate field and promote local. The early minor releases of 2.x will likely see a new WPF/XAML UI for the refactorings issued in 1.x.


 

Something really good is cooking.

We’re also looking at implementing a more VBA-like Assert class, that would be more permissive with AreEqual and AreNotEqual than the current (C#-like strict) implementation is. Test results will be copied to clipboard or exported/serialized to XML with a simple click.

If you write some C# and would like to contribute to Rubberduck, note that our GitHub repository has a bunch of up-for-grabs issues opened, a lot of which are critical (i.e. no fix, no release) – the faster all functionalities work off the new command architecture, the faster we can deliver a pre-release…

Stay tuned!

Resolver: still not perfect

I just found another bug in the rewritten 1.4.x resolver, and as much as I want to fix it (and I will)… part of me can’t help thinking if you encounter this bug, your code has greater problems than mine.

Picture this code:

Sub Foo()
     Dim Foo As New Foo
     With Foo
         With .Foo
             .Foo = 42
         End With 
         Bar .Foo.Foo
     End With
End Sub

Believe it or not, it compiles… and the 1.4.1 resolver works perfectly and correctly identifies who’s who and who’s calling what. Now what if we added a recursive call?

Sub Foo()
     Dim Foo As New Foo
     With Foo
         With .Foo
             .Foo = 42
         End With 
         Bar .Foo.Foo
     End With
     Foo
End Sub

The bug here, is that this Foo gets resolved as a call to the local variable, so renaming the procedure to DoSomething would leave that Foo unchanged.

Not too bad. I mean, nobody in their right minds would ever do that. (right?)

However, it gets worse: if we change Sub to Function, in the name of being able to identify a function’s return value, a matching identifier within the body of a function (or property getter) is resolved to the function (or getter) itself… so this part needs to be refined at bit.

Function Foo()
     Dim Foo As New Foo
     With Foo
         With .Foo
             .Foo = 42
         End With 
         Bar .Foo.Foo
     End With
     Foo
End Function

Every single Foo here, with the sole exception of the local declaration, resolves to a reference to the function.

I hope this bug doesn’t affect your code… for your sake – and that of whoever will be maintaining your code in the future.

If it does… v1.4.2 with certainly include a fix for this issue.


Update

The non-resolving recursive call isn’t a bug:

it's a local!

There’s a new duck in town!

…and it rocks.

The past few months have been tough. We were facing some serious ANTLR grammar bugs, and our identifier resolver had even more serious bugs, which meant false positives in code inspections, a rename refactoring that wouldn’t always rename all references, and a StackOverflowException if you were unlucky… which blew up Rubberduck, the VBE, and the Office host app with it, without warning.

That’s why 1.3 remained a “pre-release”.

Rubberduck 1.4 has none of these issues. Oh, our ANTLR grammar is still far from perfect (line numbers, and “precompiler” #IF statements come to mind) – but a number of bugs were fixed, and the resolver was completely rewritten. It’s not as perfect as we’d like it to be, but it correctly resolved everything we threw at it, without a single exception.

So, what’s so cool about it?


 

#Refactor

Extract Method has been around since version 1.2, and Rename was pre-released (albeit with some issues) with 1.3; Rubberduck 1.4 introduces two new refactorings:

  • Reorder Parameters in a procedure, and automatically adjust all call sites.
  • Remove Parameters from a procedure’s signature, and automatically adjust all call sites.

Rename can be used from the Project Explorer, Code Pane or Form Designer context menus, as well as from the Code Explorer to rename a project, a component (form, module, class), a procedure, variable, line label, …anything. This completely eliminates all excuses to keep meaningless identifiers in your code.


 

#Navigate

The Code Explorer was already a nice feature in 1.2, but Rubberduck 1.4 takes navigation to a whole new level.

  • Find Symbol lets you search for anything – and go to its declaration.
  • Find all references displays all call sites of any identifier.
  • Go to implementation lets you navigate implementations of an interface or interface members. Rubberduck considers any class referenced by an Implements statement as an interface.

One cool thing is that we’ve created declarations for pretty much everything in the Standard VBA library, so you can use find all references to list all usages of, say, MsgBox, or Err.Raise.


#Git

That’s right. We’ve talked about it for a while. Well, it’s here. Integrated source control, right there in the VBE. Commit, push, pull, merge, branch, to and from local or remote repositories on GitHub.


And so much more…

If you’ve never used a previous version of Rubberduck, now is the time.

Every VBA programmer needs a Rubberduck.

DOWNLOAD

Rubberduck, or Gummianka, le petit canard en caoutchouc

Next release rocks. Like, if you’re running 1.22, you’re not going to believe everything that’s coming at you in 1.4 – and if you’re running 1.3x, …you’re not going to believe it either.

The feature set is becoming massive, and that’s thoroughly awesome. We are currently in the final stages of stabilizing the next release and polishing everything. There’s a ton of amazing stuff coming, but one of the coolest things is that, thanks to the awesomeness of Code Review community members…

…we are proud to announce localization in French and Swedish, and a German translation is under way.

If a language isn’t supported on your system, it won’t show up in the display language dropdown:

Options-Localized

More announcements to come, stay tuned!

You’ve waited long enough.

The wait is over!

I have to say that this release has been… exhausting. Correctly resolving identifier references has proven to be much, much more complicated than I had originally anticipated. VBA has multiple ways of making this hard: with blocks are but one example; user-defined-type fields are but another.

But it’s done. And as far as I could tell, it works.

Why did you tag it as “pre-release” then?

Because resolving identifier references in VBA is hard, and what I released is not without issues; it’s not perfect and still needs some work, but I believe most normal use cases are covered.

For example, this code will blow up with a wonderful StackOverflowException:

Class1

Public Function Foo() As Class2
    Set Foo = New Class2
End Function

Class2

Public Sub Foo()
End Sub

ThisWorkbook

Public Sub DoSomething()
    Dim Foo As New Class1
    With Foo
            .Foo
    End With
End Sub

It compiles, VBA resolves it. And it’s fiendish, and nobody in their right minds would do anything near as ambiguous as that. But it’s legal, and it blows up.

That’s why I tagged it as a “pre-release”: because there are a number of hair-pulling edge cases that just didn’t want to cooperate.

See, finding all references to “foobar” works very well here:

Public Sub DoSomething()
    Dim foobar As New Class1
    With foobar
        With .Foo
            .Bar
        End With
    End With
End Sub

…and finding all references to “Foo” in the below code will not blow up, but the “.Foo” in the 2nd with block resolves as a reference to the local variable “Foo”:

Public Sub DoSomething()
    Dim Foo As New Class1
    With Foo
        With .Foo
            .Bar
        End With
    End With
End Sub

And of course, there are a number of other issues still.

Here’s a non-exhaustive list of relatively minor known issues we’re postponing to 1.31 or other future release – please don’t hesitate to submit a new issue if you find anything that doesn’t work as you’d expect.

There can be only one

Rubberduck doesn’t [yet] handle cross-project references; while all opened VBA projects are parsed and navigatable, they’re all “silos”, as project references aren’t taken into account; this means if project A is referencing project B, and project A contains the only usage of a procedure defined in project B, then that procedure will fire up a code inspection saying the procedure is never used.

It also means “find all references” and “rename” will miss it.

self-referencing Parameters

“Find all references” has been seen listing the declaration of a parameter in its list of references. Not a biggie, but not intended either. There’s no explanation for that one, yet – in fact it’s possible you never even encounter this issue.

Selection Glitches From Code Inspection Results

We know what causes it: the length of the selection is that of the last word/token in the parser context associated with the inspection result. That’s like 80% fixed! Now the other 80% is a little bit tricky…

Performance

Code inspections were meant to get faster. They got more accurate instead. This needs a tune-up. You can speed up inspections by turning off the most expensive ones… although these are often the most useful ones, too.

Function return vAlue not assigned

There has been instances of [hard-to-repro] object-typed property getters that fire up an inspection result, when they shouldn’t. Interestingly this behavior hasn’t been reproduced in smaller projects. This inspection is important because a function (or property getter) that’s not assigned, will not return anything – and that’s more than likely a bug waiting to be discovered.

Parameter can be passed by value

This inspection is meant to indicate that a ByRef parameter is not assigned a value, and could safely be passed ByVal. However if such a parameter is passed to another procedure as a ByRef parameter, Rubberduck should assume that the parameter is assigned. That bit is not yet implemented, so that inspection result should be taken with a grain of salt (like all code inspection results in any static code analysis tool anyway).

This inspection will not fire up a result if the parameter isn’t a primitive type, for performance reason (VBA performance); if performance is critical for your VBA code, passing parameters by reference may yield better results.

Special Thanks to Rob Bovey and Stephen Bullen

Twitter is awesome: you share something with the world, and then the world shares something with you. Thanks to the awesomeness of Ross McLean, we are pleased to announce that Rubberduck 2.0 will include automagic indentation

…Powered by smart indenter

Yes! The original author and current maintainer of the magic indenting freeware tool downloaded by dozens of thousands of happy customers have kindly supplied us with the VB6 source code, and we’re going to put it to good use, port it to .NET, embed the almighty indentation algorithm into Rubberduck, and try to keep as much as possible of the formidable set of configuration settings that make Smart Indenter such a wonder.

To be continued…

While we’re waiting…

I cannot wait to release the next version. Seriously. You have no idea how much it itches.

It’s coming, no worries; we only have a few tiny little adjustments to make and we’re ready.

In the mean time, v1.22 had over 160 downloads (probably 170 by the time I publish this post), which is more than anything I would have expected. After all, in the past 30 days I’ve fixed so many bugs I’ve come to see 1.22 as an under-featured buggy tool – code inspections are definitely promising, but the parser has (had!) too many issues for a lot of them to be reliable. Fortunately version 1.3 changes that.

We’ve had awesome feedback already, some on GitHub, some via our contact us form on rubberduck-vba.com, some on Twitter… but hardly any here.

So I’m going to include some new features of v1.3 here (just to skew the results a bit – and I’m also biting my tongue on very cool things coming up for v2.0), and ask you…

Comments are welcome!

Naming is hard. Renaming is easy.

There are only two hard things in Computer Science: cache invalidation and naming things.

— Phil Karlton

How many VBA modules declare variables looking like this:

Dim v As Long, vWSs As Variant, Mrange As Range, Vrange As Range

Or like this:

Dim i As Long
Dim LR As Long

How many procedures have cryptic names that only the author knows what they mean?

How many Times did you refrain from renaming a procedure in fear of breaking the code?

Fear no more. Renaming doesn’t have to be the hardest part of using meaningful names in code.

With the next release of Rubberduck, finding a meaningful name is going to be the hardest part – I’m please to announce that Rubberduck 1.3 will feature a rename refactoring:

rename-const

Awesome. How does it work?

I’m tempted to say “Magic!” here. Rubberduck uses the current selection (/caret location) to guess what you’re trying to rename. If you’re on a constant usage, it knows to rename the constant and every single one of its references; if you’re just inside a procedure scope, it guesses you want to rename the procedure and affect every single call site; if you’re somewhere in the declarations section of a module, it lets you rename the module itself, and automatically adjusts every explicit reference to it.

The Rubberduck/Refactor menu will feature a new “Rename” button, accessible with Alt+B,R,R (Rubberduck/Refactor/Rename).

The Code Explorer‘s context menu will also feature a “Rename” button, so that any module/member can be renamed without even looking at the actual code.

Lastly, we’ll hijack the code pane context menu and add our “Refactor” menu in there, too.

Naming is hard. Renaming doesn’t have to be!

Rubberduck 1.3: When the VBE becomes a real IDE

Parsing is hard!

Rubberduck parsing is being refined again. The first few releases used a hand-made, regex-based parser. That was not only unmaintainable and crippled with bugs, it also had fairly limited capabilities – sure we could locate procedures, variables, parameters… but the task was daunting and, honestly, unachievable.

Version 1.2 changed everything. We ditched the regex solution and introduced a dependency on ANTLR4 for C#, using an admittedly buggy grammar intended for parsing VB6 code. Still, the generated lexer/parser was well beyond anything we could have done with regular expressions, and we could implement code inspections that wouldn’t have been possible otherwise. That was awesome… but then new flaws emerged as we realized we needed more than that.

Version 1.3 will change everything again. Oh, we’re still using ANTLR and a (now modified) buggy grammar definition, but then we’re no longer going to be walking the parse tree all the time – we’re walking it once to collect all declarations, and then once to collect all usages of every single identifier we can find.


What does that mean?

Imagine a table where, for every declaration, you lay down information such as the code module where you found it, the exact location in the code file, the scope it’s in, whether it’s a class module, a standard module, a procedure, a function, a property get/let/setter, an event, a parameter, a local variable, a global constant, etc. – and then whether it has a return/declared type, what that type is, whether it’s assigned a reference upon declaration (“As New”) – basically, on that table lays the entire code’s wireframe.

Then imagine that, for everything on that table, you’re able to locate every single reference to that identifier, whether it’s an assignment, and exactly where that reference is located – at which position in which code file and in which scope.

The result is the ability to make the difference between an array index assignment and a function call. If VBA can figure out the code, so can Rubberduck.

This means the next few versions will start seeing very cool features such as…

  • Find all references – from a context menu in the Code Explorer tree view, or heck, why not from a context menu in the code pane itself!
  • GoTo implementations – easily navigate to all classes that implement a specific interface you’ve written.
  • GoTo anything – type an identifier name in a box, and instantly navigate to its declaration… wherever that is.
  • Safe delete – remove an identifier (or module/class) only if it’s not used anywhere; and if it’s used somewhere, navigate to that usage and fix it before breaking the code.
  • Rename refactoring – rename foo to bar, and only the “foo” you mean to rename; this isn’t a Find & Replace, not even a RegEx search – it’s a full-fledged “rename” refactoring à la Visual Studio!

Not to mention everything else that’s in store for v1.3 (did I say IDE-Integrated GitHub Source Control?) – stay tuned!

Code Explorer – does it replace the VBE’s Project Explorer?

Version 1.21 will feature a Code Explorer getting closer to where we envision it:

Just like the Project Explorer we can now toggle folders on and off, and components are sorted alphabetically. We can add standard and class modules, even test modules, open the designer when a form is selected – we can even run all tests from there if we want.

The Code Explorer is a bit of an hybrid between the VBE’s Project Explorer and Object Browser windows – we see all the members of every module, and we can double-click navigate anywhere.

We’re planning to implement a number of refactorings in 1.3, and some of them are going to be available from the Code Explorer‘s context menu. 1.3 will also integrate GitHub source control, and the Code Explorer‘s context menu will be usable to commit or undo changes to a specific file – importing and exporting files is also going to be in that menu by then.

What else would you use the Code Explorer for? Does the Code Explorer replace the VBE’s Project Explorer for you?