GithubHelp home page GithubHelp logo

rubberduck-vba / rubberduck Goto Github PK

View Code? Open in Web Editor NEW
1.9K 102.0 294.0 103.36 MB

Every programmer needs a rubberduck. COM add-in for the VBA & VB6 IDE (VBE).

Home Page: https://rubberduckvba.com

License: GNU General Public License v3.0

C# 94.64% ANTLR 0.45% Inno Setup 0.75% PowerShell 0.03% Batchfile 0.01% C++ 0.24% C 1.90% Java 0.03% VBA 0.44% Rich Text Format 0.45% Visual Basic 6.0 1.07%
vba c-sharp ide metaprogramming static-code-analysis refactorings unit-testing vba-ide indentation parsing

rubberduck's Introduction

Links

Support us on ko-fi.com

Releases


Copyright © 2014-2023 Rubberduck project contributors.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.


What is Rubberduck?

The Visual Basic Editor (VBE) has stood still for over 20 years, and there is no chance a first-party update to the legacy IDE ever brings it up to speed with modern-day tooling. Rubberduck aims to bring the VBE into this century by doing exactly that.

Read more about contributing here:

contribute!

The add-in has many features - below is a quick overview. See https://rubberduckvba.com/features for more details.

Enhanced Navigation

The Rubberduck command bar displays docstring for the current member.

command bar

The Code Explorer drills down to member level, has a search bar, and lets you visualize your project as a virtual folder hierarchy organized just the way you need it.

All references to any identifier, whether defined in your project or any of its library references, are one click away. If it has a name, it can be navigated to.

Static Code Analysis, Refactorings

Rubberduck analyses your code in various configurable ways and can help avoid beginner mistakes, keep a consistent programming style, and find all sorts of potential bugs and problems. Many code inspections were implemented due to frequently-asked VBA questions on Stack Overflow, and on many occasions, an automatic quick-fix is available.

Rename variables to meaningful identifiers without worrying about breaking something. Promote local variables to parameters, extract interfaces and methods from a selection, encapsulate fields into properties, reorder and/or delete parameters, and automatically update all callers.

Unit Testing

Write code that provably works, by invoking it from small test procedures that setup the conditions for a test case and assert that the expected outcome happened. Rubberduck provides a rich MSTest-inspired API, and soon an experimental mocking framework (a COM-visible wrapper around Moq) that can automatically implement VBA interfaces and configure mock objects.

test explorer

Smart Indenter

A port of the popular 32-bit add-in by Office Automation Ltd., whose legacy VB6 source code was generously made freely available for Rubberduck under GPLv3 by the legendary Stephen Bullen and Rob Bovey themselves! Rubberduck will prompt to import your Smart Indenter settings on first load if detected.

Annotations

Special comments that become a game changer with Rubberduck processing them: organize modules in your project using @Folder annotations, synchronize VB_Description and VB_PredeclaredId hidden attributes without manually exporting, editing, and re-importing modules with @Description and @PredeclaredId annotations.

More?

Of course there's more! There's tooling to help synchronizing the project with files in a folder (useful for source/version control!), some auto-completion features like self-closing parentheses and quotes; there's a regular expression assistant, a replacement for the VBE's add/remove references dialog, and so many other things to discover, and yet even more to implement.


Tips

Rubberduck isn't a lightweight add-in and consumes a large amount of memory. So much, that working with a very large project could be problematic with a 32-bit host, and sometimes even with a 64-bit host. Here are a few tips to get the best out of your ducky.

  • Start small: explore the features with a small test project first.
  • Refresh often: refresh Rubberduck's parser every time you pause to read after modifying a module. The fewer files modified since the last parse, the faster the next parse.
  • Review inspection settings: there are many inspections, and some of them may produce a lot of results if they're directly targeting something that's part of your coding style. Spawning tens of thousands of inspection results can significantly degrade performance.
  • Avoid late binding: Rubberduck cannot resolve identifier references and thus cannot understand the code as well if even the VBA compiler is deferring all validations to run-time. Declare and return explicit data types, and cast from Object and Variant to a more specific type whenever possible.

Join us on our Discord server for support, questions, contributions, or just to come and say hi!

For more information please see Getting Started in the project's wiki, and follow the project's blog for project updates and advanced VBA OOP reading material.


Roadmap

After over two years without an "official" new release, Rubberduck version jumped from 2.5.2 to 2.5.9, adding minor but interesting features to an already impressive array.

The road ahead

Rubberduck 2.x is now planned to end at 2.5.9.x, perhaps with a number of small revisions and bug fixes, but nothing major should be expected, as the developers' attention is shifting to the 3.0 project:

  • Parsing and understanding VBA code is moving to a language (LSP) server
  • We're making a new editor inside (for now) the Visual Basic Editor that will be the LSP client
  • Baseline server-side feature set for 3.0 is everything 2.5.9 does
  • Baseline client-side feature set for 3.0 is the 2.5.x UI (perhaps tweaked a bit/lot) hosted in the Rubberduck Editor

Fully controlling the editor opens Rubberduck to everything we ever dreamed of:

  • In-editor syntax and static code analysis reporting and quick-fixing
  • Full editor theming, custom syntax highlighting

See the Rubberduck3 repository for more information.

rubberduck's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rubberduck's Issues

Decouple TestExplorerWindow from TestEngine

The TestExplorerWindow and TestEngine are tightly bound together. For example:

    public TestMenu(VBE vbe, AddIn addInInstance):base(vbe, addInInstance)
    {
        TestExplorerWindow testExplorer = new TestExplorerWindow();
        toolWindow = CreateToolWindow("Test Explorer", testExplorer);
        _engine = new TestEngine(vbe, testExplorer, toolWindow);
    }

And

    public void Run(TestMethod test)
    {
        _explorer.ClearProgress();
        var tests = new Dictionary<TestMethod, TestResult> { { test, null } };

        _explorer.SetPlayList(tests);
        AssignResults(tests.Keys);

        _lastRun = tests.Keys;
        ShowExplorerWindow();
    }

Test Engine should raise events that the TestExplorerWindow listens for. When these events are raised, TestExplorer can make itself visible.

Use of undeclared identifier

[Warning]

Detect when code is using undeclared identifiers.

Public Sub Foo()
    bar = 123 'not declared anywhere
End Sub

Related: #15 Use Option Explicit.

ProcedureNode

There might be an issue with the ProcedureSyntax regex; only properties get picked up.

RubberDuck Settings dialog

Add a form to allow users to configure the add-in. Form should use a tab control to allow for future expansion of settings. Begin with a UI for ToDo list settings.

GoSub can be extracted to procedure

[Suggestion]

GoSub...Return statements should trigger a recommendation to refactor/extract procedure/function (depending on context):

    foo = GetFoo(123)
    If foo Then GoSub DoSomething
    Exit Sub

DoSomething:
    bar = 456
    Return

Should be refactored to:

    foo = GetFoo(123)
    If foo Then bar = DoSomething
    Exit Sub
Private Function DoSomething() As Integer
    DoSomething = 456
End Function

Variant type may not be intentional

[Warning]

In multiple declarations, a common mistake is to only declare the type for the last identifier:

Dim foo, bar As String

This declares foo as a Variant. Recommend explicit typing:

Dim foo As Variant, bar As String

DeclarationNode

Current DeclarationNode code should be the base type for declaration nodes, and be a child node under a new node type that supports multiple child nodes.

  • Parser should generate a DeclarationNode with as many child nodes as there are declarations in the parsed instruction / logical code line.

Parser is skipping syntaxes with SyntaxType.IsChildNodeSyntax, so:

  • ConstantSyntax, DimSyntax, GlobalFieldSyntax, PrivateFieldSyntax and PublicFieldSyntax should be derived from SyntaxBase, with SyntaxType.IsChildNodeSyntax.
  • Need to implement a DeclarationSyntax class not derived from SyntaxBase but implementing ISyntax (because SyntaxBase.CreateNode only passes a single Instruction), and then include this DeclarationSyntax class in the parser's grammar.

Handle runtime errors

Detect On Error Resume Next instructions, and recommend adding an error-handling subroutine instead.

    On Error Resume Next
    foo(42) = "bar"

Can be written as:

    On Error GoTo ErrHandler
    foo(42) = "bar"

    Exit Sub
ErrHandler:
    If Err.Number = 9 Then 'Subscript out of range
        Err.Clear
        Resume Next
    End If

Rubberduck may not be able to detect exactly which runtime error to handle. Perhaps the quickfix snippet can look like this:

    On Error GoTo {ErrorHandlerLabel}

    {code}

    Exit {Sub|Function|Property}
{ErrorHandlerLabel}:
    If Err.Number > 0 Then 'todo: handle specific error
        Err.Clear
        Resume Next
    End If

Configure project location

In order to support source control integration, Rubberduck will need to export/import all code files to/from a given folder. Making this folder the workbook's location may not always be possible; first thing to do is to determine where the local repository is going to be located; we need a feature that will enable the user to specify that.

Unreacheable code detected

[Warning]

Rubberduck should detect unreacheable code, and warn about it.

DoSomething 123
Exit Sub

DoSomethingElse 456 'unreacheable code (not under a label, and/or no reacheable jump to that label)
DoSomething 123
Err.Raise SomeError

DoSomethingElse 456 'unreacheable code (unless On Error Resume Next is specified)
DoSomething 123
If False Then
    DoSomethingElse 456 'unreacheable code (condition expression must be statically evaluatable)
End If

Toggle Default Member Attribute

Related: #52 (same prerequesites about importing/exporting code files)

This feature allows marking a class member as its "default member"; the feature should ensure there's only ever a single member marked as such.

Warn user when changing a class' default member, as this is a breaking change.

Explicit type conversion is redundant

[Suggestion]

Warn when an identifier of a given type is being explicitly converted to that same type. Conversion can be removed.

Dim a As Integer, b As Integer
a = CInt(b)

Condition can be a single instruction

[Suggestion]

When an If block contains only a single instruction, recommend making it a single instruction:

If condition Then
    instruction
End If

Can be written as:

If condition Then instruction

Related: #25 If block body can be on separate line

Variable type not declared.

[Warning]

Variable declared without a type. Variable is implicitly typed as variant.

Variable declarations without a type will be implicitly typed as a variant. Recommend explicit declaration.

Dim someString

Related to #27

GitHub integration

A "Commit" feature will export all code files to a local repository (see #48), and a "Push" feature will send these files to a remote one, all through through command-line API calls.

A "Sync" feature will download source code from the remote repository, update the local ones, and import the modified files back into the VBA Project.

Split declaration and assignment

[Suggestion]

Rubberduck should recommend splitting declaration and assignment.

Dim foo = New Bar

Can be written as:

Dim foo
foo = New Bar

Revert condition to reduce nesting

[Suggestion]

When a procedure's body is wrapped with an If statement, Rubberduck should recommend reverting the condition to reduce nesting.

Public Sub Foo()
    If Bar Then
        'body
    End If
End Sub

Can be written as:

Public Sub Foo()
    If Not Bar Then
        Exit Sub
    End If
    'body
End Sub

Use CodeBlockNode to determine indentation level?

The parsed code tree contains CodeBlockNode items, which should add an indentation level. Each node in the tree contains an Instruction which knows about its StartColumn, and each Instruction knows about a LogicalCodeLine, which knows about its StartLine.

Using the parsed code tree may seem like a good idea for the indenter, but there are complications:

  • A LogicalCodeLine can refer to more than 1 line of code
  • An Instruction may not be the only instruction on a code line; its StartColumn isn't necessarily its indentation level.

Indentation applies to code lines - not to logical code lines, not to instructions. Should the code tree be modified to accomodate this? Or should we find another way of determining code indentation?

Option Explicit should be specified first

[Suggestion]

When multiple options are specified, Option Explicit should be first.

Option Base 1
Option Explicit

Can be written as:

Option Explicit
Option Base 1

TestExplorer window is visible by default

Steps to reproduce:

  • Open up Excel, Alt+F11 to bring up VBA; TestExplorer dockable window is shown in the last state and position it was last time you closed the IDE. Great.
  • Close the immediate pane if it's visible.
  • Close the TestExplorer window.
  • Close the IDE and exit Excel.
  • Reopen Excel.
  • Bring up the VBA editor: the immediate pane is gone, but the TestExplorer persists and is still visible.
  • Maybe user settings aren't correctly saved. Resize the TestExplorer window, then close it.
  • Close and reopen Excel.
  • Bring up the VBA editor: the TestExplorer window is correctly sized the way you had it, but it's still visible although user settings surely say it should be hidden.

Join declaration and assignment

[Suggestion]

When a New reference is being assigned only once, recommend joining declaration and assignment:

Dim foo As Bar
Set foo = New Bar

Can be written as:

Dim foo As New Bar

Note: assignment only needs to be in the same scope - not necessarily in the instruction that immediately follows the declaration.

Related: #17 Split declaration and assignment

Use meaningful names

Detect when an identifier is named after its type and followed by a number, e.g. Label1 or TextBox1, or when there are multiple identifiers with the same name, only with a different number suffix, like foo1, foo2, foo3.

More formally:

  • Identifier is less than 3 characters long
  • Identifier ends with a number
  • Identifier contains no vowel (suggest better name from lookup "dictionary" of disemvoweled words?)

Use Option Explicit

[Warning]

Code modules should always have Option Explicit somewhere in their declarations section.

Import code files from local repository

related: #48 - Rubberduck will need to be able to synchronize changes by finding all code files in the local repository, removing all project components with the same name, and importing the code files back into the VBA project.

multiple opened projects named VBProject will break the fully-qualified method calls

Test methods are called with a fully-qualified syntax ProjectName.ModuleName.TestMethodName - however if there are two or more projects with the same name, VBA will not be able to resolve the method call and an exception will be thrown.
If the test method is added from the Test Explorer, an exception will be thrown when an existing TestMethod (ProjectName.ModuleName.TestMethodName) is added to the session.

Procedure description attribute

This feature allows the user to enter a short description for a module member, to appear in the object browser when it is selected.

related: #48 & #49 (same prerequesites, although like #52 it can work off temporary files)

Use of obsolete Call instruction

[Warning]

Call is obsolete, only included in the language for backward compatibility; replace with inline procedure call.

Call DoSomething

Becomes

DoSomething

Indentation is not accounted for

Instruction.StartColumn should account for indentation and return the position of the first non-whitespace character in the instruction.

Multiple conditionals operating on the same variable can be converted to Select Case block

[Suggestion]

Rubberduck should be able to determine whether a If..ElseIf block is checking the same variable against different values, and recommend converting the entire block into a Select Case block.

If foo = 123 Then
    '...
Else If foo = 456 Then
    '...
Else If foo = 789 Then
    '...
End If

Can be converted to:

Select Case foo
    Case 123:
        '...
    Case 456:
        '...
    Case 789:
        '...
End Select

Toggle DefaultInstanceId attribute

Provide a way to toggle the value of a class module's default instance ID, effectively toggling between "normal" and "static" class behavior.

Warn user when toggling the attribute to False, because such a change is a breaking change.

Somewhat related to #48 and #49, to import/export code files - although this specific feature can work off temporary files, import/export functionality should be reused here.

Property with public mutator (Let/Set) should expose a public accessor (Get)

[Warning]

Properties that expose no public getter but have public mutators, should be complemented with a getter.

Public Property Let Foo(ByVal value As String)
    this.Foo = value
End Property

When Property Let is the only Public member for Foo, Rubberduck should recommend adding this:

Public Property Get Foo() As String
    Foo = this.Foo
End Property

Parameter is passed ByRef implicitly

[Suggestion]

If parameter is assigned in the body of the procedure, Rubberduck should suggest passing ByRef explicitly; if parameter is not assigned, Rubberduck should suggest passing it ByVal.

Iterator getter attribute

Allows user to mark a class' NewEnum member {Property Get) as being an iterator, which allows using the class in a For Each loop construct.

Warn user when toggling this off, as it is a breaking change.

Options should be specified at the top of code module

[Suggestion]

When options are specified after declarations in a code module, Rubberduck should recommend moving them to the top.

Private foo As Bar
Option Base 1
Option Explicit

Can be written as:

Option Base 1
Option Explicit

Private foo As Bar

Make ToDo List comments configurable

Using app.Config custom section and new class to read the config file, allow users to add attributes to be picked up by the ToDo List. Priority level of attribute should also be configurable.

Assert.AreEqual fails when comparing a constant and a function result

Module 1

Option Explicit

Public Function Add(a As Long, b As Long) As Long
    Add = a + b
End Function

TestModule1

'@TestModule
Option Explicit
Private Assert As New RetailCoderVBE.AssertClass

'@TestMethod
Public Sub OnePlusOneEqualsTwo()
    Dim actual As Long, expected As Long
    expected = 2
    actual = Add(1, 1)

    Assert.AreEqual expected, actual

    Assert.AreEqual expected, Module1.Add(1, 1)

    Assert.AreEqual expected, Add(1, 1)

    Assert.AreEqual 2, 2
End Sub

'@TestMethod
Public Sub Bug()

    Assert.AreEqual 2, Add(1, 1)

End Sub

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.