Static code analysis can find hundreds of opportunities in VBA code.
Rubberduck builds its own internal representation of the code, and then proceeds to analyze it. Each individual inspection can easily be disabled, or configured to issue inspection results at different severity levels ranging from Hint
to Error
.
Use the Inspection Results toolwindow to review Rubberduck’s findings, search, filter, regroup results by inspection, location, type, or severity. Each inspection result comes with a detailed description of what’s being flagged and why, so you can make an enlightened decision.
Unless configured otherwise, Rubberduck automatically runs inspections after the a parser/resolver cycle completes (regardless of whether the inspection results toolwindow is displayed or not).
For the best experience, it would be recommended to first try Rubberduck with an empty project, add a new module, and write, say, a loop that counts 1 to 10 and outputs to the debug pane - then to parse that and review the inspection results; carefully review the inspection settings, and consider disabling the inspections that irreconcilably clash with your preferences: use meaningful names alone can easily produce hundreds upon hundreds of results if you’re not that much into using vowels, or if you, say, prefix all your variable names; these inspections can be re-enabled anytime you’re ready!
These inspections look for a wide range of potential issues, from missing Option Explicit
to undeclared or unused variables.
Flags Rubberduck annotations used in a component type that is incompatible with that annotation.
Default severity: Warning
Some annotations can only be used in a specific type of module; others cannot be used in certain types of modules.
Warns about late-bound WorksheetFunction calls made against the extended interface of the Application object.
Default severity: Suggestion
An early-bound, equivalent function exists in the object returned by the Application.WorksheetFunction property; late-bound member calls will fail at run-time with error 438 if there is a typo (a typo fails to compile for an early-bound member call); given invalid inputs, these late-bound member calls return a Variant/Error value that cannot be coerced into another type. The equivalent early-bound member calls raise a more VB-idiomatic, trappable runtime error given the same invalid inputs: trying to compare or assign a Variant/Error to another data type will throw error 13 "type mismatch" at run-time. A Variant/Error value cannot be coerced into any other data type, be it for assignment or comparison.
This inspection will only run if the Excel library is referenced.
Locates arguments passed to functions or procedures for object parameters which the do not have a compatible declared type.
Default severity: Warning
The VBA compiler does not check whether different object types are compatible. Instead there is a runtime error whenever the types are incompatible.
Warns about parameters passed by value being assigned a new value in the body of a procedure.
Default severity: Warning
Debugging is easier if the procedure's initial state is preserved and accessible anywhere within its scope. Mutating the inputs destroys the initial state, and makes the intent ambiguous: if the calling code is meant to be able to access the modified values, then the parameter should be passed ByRef; the ByVal modifier might be a bug.
Warns about a local variable that is assigned and never read. Or, warns about a local variable that is assigned and then re-assigned before using the previous value.
Default severity: Suggestion
An assignment that is never used is a meaningless statement that was likely used by an execution path in a prior version of the module.
Indicates that the value of a hidden VB attribute is out of sync with the corresponding Rubberduck annotation comment.
Default severity: Warning
Keeping Rubberduck annotation comments in sync with the hidden VB attribute values, surfaces these hidden attributes in the VBE code panes; Rubberduck can rewrite the attributes to match the corresponding annotation comment.
Locates 'Const' declarations that are never referenced.
Default severity: Warning
Declarations that are never used should be removed.
Locates indexed default member calls for which the corresponding object does not have a suitable suitable default member.
Default severity: Warning
The VBA compiler does not check whether the necessary default member is present. Instead there is a runtime error whenever the runtime type fails to have the default member.
Identifies empty module member blocks.
Default severity: Warning
Methods containing no executable statements are misleading as they appear to be doing something which they actually don't. This might be the result of delaying the actual implementation for a later stage of development, and then forgetting all about that.
Locates instances of member calls made against the result of a Range.Find/FindNext/FindPrevious method, without prior validation.
Default severity: Warning
Range.Find methods return a Range object reference that refers to the cell containing the search string; this object reference will be Nothing if the search didn't turn up any results, and a member call against Nothing will raise run-time error 91.
This inspection will only run if the Excel library is referenced.
Locates public User-Defined Function procedures accidentally named after a cell reference.
Default severity: Warning
Another good reason to avoid numeric suffixes: if the function is meant to be used as a UDF in a cell formula, the worksheet cell by the same name takes precedence and gets the reference, and the function is never invoked.
This inspection will only run if the Excel library is referenced.
Warns when a user function's return value is discarded at all its call sites.
Default severity: Warning
A 'Function' procedure normally means its return value to be captured and consumed by the calling code. It's possible that not all call sites need the return value, but if the value is systematically discarded then this means the function is side-effecting, and thus should probably be a 'Sub' procedure instead.
Warns when a user function's return value is not used at a call site.
Default severity: Warning
A 'Function' procedure normally means its return value to be captured and consumed by the calling code.
Identifies Functions or Properties referenced by the TruePart(second argument) or FalsePart(third argument) of the IIf built-in function.
Default severity: Warning
All arguments of any function/procedure call are always evaluated before the function is invoked so that their respective values can be passed as parameters. Even so, the IIf Function's behavior is sometimes mis-interpreted to expect that ONLY the 'TruePart' or ONLY the 'FalsePart' expression will be evaluated based on the result of the first argument expression. Consequently, the IIf Function can be a source of unanticipated side-effects and errors if the user does not account for the fact that both the TruePart and FalsePart arguments are always evaluated.
Identifies class modules that define an interface with one or more members containing a concrete implementation.
Default severity: Suggestion
Interfaces provide an abstract, unified programmatic access to different objects; concrete implementations of their members should be in a separate module that 'Implements' the interface.
Highlights implicit ByRef modifiers in user code.
Default severity: Hint
VBA parameters are implicitly ByRef, which differs from modern VB (VB.NET) and most other programming languages which are implicitly ByVal. So, explicitly identifing VBA parameter mechanisms (the ByRef and ByVal modifiers) can help surface potentially unexpected language results. The inspection does not flag an implicit parameter mechanism for the last parameter of Property mutators (Let or Set). VBA applies a ByVal parameter mechanism to the last parameter in the absence (or presence!) of a modifier. Exception: UserDefinedType parameters must always be passed as ByRef.
Locates unqualified Workbook.Worksheets/Sheets/Names member calls inside workbook document modules, that implicitly refer to the host workbook.
Default severity: Warning
Implicit references inside a workbook document module can easily be mistaken for implicit references to the active workbook (ActiveWorkbook), which is the behavior in all other module types. By explicitly qualifying these member calls with 'Me', the ambiguity can be resolved. If the intent is to actually refer to the active workbook, qualify with 'ActiveWorkbook' to prevent a bug.
Locates unqualified Worksheet.Range/Cells/Columns/Rows member calls inside worksheet modules, that implicitly refer to the containing sheet component.
Default severity: Warning
Implicit references inside a worksheet document module can easily be mistaken for implicit references to the active worksheet (ActiveSheet), which is the behavior in all other module types. By explicitly qualifying these member calls with 'Me', the ambiguity can be resolved. If the intent is to refer to the active worksheet, qualify with 'ActiveSheet' to prevent a bug.
Identifies the use of non-indexed default member accesses.
Default severity: Warning
Default member accesses hide away the actually called member. This is especially misleading if there is no indication in the expression that such a call is made and can cause errors in which a member was forgotten to be called to go unnoticed.
Warns about constants that don't have an explicitly defined type.
Default severity: Warning
All constants have a declared type, whether a type is specified or not. The implicit type is determined by the compiler based on the value, which is not always the expected type.
Identifies the use of indexed default member accesses that require a recursive default member resolution.
Default severity: Warning
Default member accesses hide away the actually called member. This is especially misleading if there is no indication in the expression that such a call is made and the final default member is not on the interface of the object itself. In particular, this can cause errors in which a member was forgotten to be called to go unnoticed.
Identifies the use of indexed default member accesses for which the default member cannot be determined at compile time.
Default severity: Warning
Default member accesses hide away the actually called member. This is especially misleading if there is no indication in the expression that such a call is made and if the default member cannot be determined from the declared type of the object. As a consequence, errors in which a member was forgotten to be called can go unnoticed and should there not be a suitable default member at runtime, an error 438 'Object doesn't support this property or method' will be raised.
Identifies the use of indexed default member accesses.
Default severity: Warning
An indexed default member access hides away the actually called member.
Identifies the use of indexed default member accesses that require a recursive default member resolution.
Default severity: Warning
An indexed default member access hides away the actually called member. This is especially problematic if the corresponding parameterized default member is not on the interface of the object itself.
Identifies the use of indexed default member accesses for which the default member cannot be determined at compile time.
Default severity: Warning
An indexed default member access hides away the actually called member. This is especially problematic if the default member cannot be determined from the declared type of the object. Should there not be a suitable default member at runtime, an error 438 'Object doesn't support this property or method' will be raised.
Identifies obsolete 16-bit integer variables.
Default severity: Hint
Modern processors are optimized for processing 32-bit integers; internally, a 16-bit integer is still stored as a 32-bit value. Unless code is interacting with APIs that require a 16-bit integer, a Long (32-bit integer) should be used instead.
Flags invalid or misplaced Rubberduck annotation comments.
Default severity: Warning
Rubberduck is correctly parsing an annotation, but that annotation is illegal in that context and couldn't be bound to a code element.
Identifies uses of 'IsMissing' involving non-variant, non-optional, or array parameters.
Default severity: Warning
'IsMissing' only returns True when an optional Variant parameter was not supplied as an argument. This inspection flags uses that attempt to use 'IsMissing' for other purposes, resulting in conditions that are always False.
Identifies uses of 'IsMissing' involving a non-parameter argument.
Default severity: Warning
'IsMissing' only returns True when an optional Variant parameter was not supplied as an argument. This inspection flags uses that attempt to use 'IsMissing' for other purposes, resulting in conditions that are always False.
Identifies line labels that are never referenced, and therefore superfluous.
Default severity: Warning
Line labels are useful for GoTo, GoSub, Resume, and On Error statements; but the intent of a line label can be confusing if it isn't referenced by any such instruction.
Warns about member calls against an extensible interface, that cannot be validated at compile-time.
Default severity: Warning
Extensible COM types can have members attached at run-time; VBA cannot bind these member calls at compile-time. If there is an early-bound alternative way to achieve the same result, it should be preferred.
Flags the value-parameter of a property mutators that are declared with an explict ByRef modifier.
Default severity: Warning
Regardless of the presence or absence of an explicit ByRef or ByVal modifier, the value-parameter of a property mutator is always treated as though it had an explicit ByVal modifier. Exception: UserDefinedType and Array parameters are always passed by reference.
Warns about a malformed Rubberduck annotation that is missing one or more arguments.
Default severity: Error
Some annotations require arguments; if the required number of arguments isn't specified, the annotation is nothing more than an obscure comment.
Indicates that a hidden VB attribute is present for a member, but no Rubberduck annotation is documenting it.
Default severity: Warning
Rubberduck annotations mean to document the presence of hidden VB attributes; this inspection flags members that do not have a Rubberduck annotation corresponding to the hidden VB attribute.
Indicates that a hidden VB attribute is present for a module, but no Rubberduck annotation is documenting it.
Default severity: Warning
Rubberduck annotations mean to document the presence of hidden VB attributes; this inspection flags modules that do not have a Rubberduck annotation corresponding to the hidden VB attribute.
Warns about 'Function' and 'Property Get' procedures whose return value is not assigned.
Default severity: Error
Both 'Function' and 'Property Get' accessors should always return something. Omitting the return assignment is likely a bug.
Warns about assignments that appear to be assigning an object reference without the 'Set' keyword.
Default severity: Error
Omitting the 'Set' keyword will Let-coerce the right-hand side (RHS) of the assignment expression. If the RHS is an object variable, then the assignment is implicitly assigning to that object's default member, which may raise run-time error 91 at run-time.
Identifies places in which an object is used but a procedure is required and a default member exists on the object.
Default severity: Warning
Providing an object where a procedure is required leads to an implicit call to the object's default member. This behavior is not obvious, and most likely unintended.
Warns about 'Declare' statements that are using the obsolete/unsupported 'CDecl' calling convention on Windows.
Default severity: Warning
The CDecl calling convention is only implemented in VBA for Mac; if Rubberduck can see it (Rubberduck only runs on Windows), then the declaration is using an unsupported (no-op) calling convention on Windows.
Flags 'While...Wend' loops as obsolete.
Default severity: Warning
'While...Wend' loops were made obsolete when 'Do While...Loop' statements were introduced. 'While...Wend' loops cannot be exited early without a GoTo jump; 'Do...Loop' statements can be conditionally exited with 'Exit Do'.
Flags modules that omit Option Explicit.
Default severity: Error
This option makes variable declarations mandatory. Without it, a typo gets compiled as a new on-the-spot Variant/Empty variable with a new name. Omitting this option amounts to refusing the little help the VBE can provide with compile-time validation.
Identifies parameter declarations that are not used.
Default severity: Warning
Declarations that are not used anywhere should probably be removed.
Locates procedures that are never invoked from user code.
Default severity: Warning
Unused procedures are dead code that should probably be removed. Note, a procedure may be effectively "not used" in code, but attached to some Shape object in the host document: in such cases the inspection result should be ignored.
Locates places in which a procedure needs to be called but an object variables has been provided that does not have a suitable default member.
Default severity: Warning
The VBA compiler does not check whether the necessary default member is present. Instead there is a runtime error whenever the runtime type fails to have the default member.
Identifies Property assigment references where Set or Let Property Members do not exist.
Default severity: Warning
In general, the VBE editor catches this type of error and will not compile. However, there are a few scenarios where the error is overlooked by the compiler and an error is generated at runtime. To avoid the runtime error scenarios, the inspection flags all assignment references of a read-only property.
Identifies redundant ByRef modifiers.
Default severity: DoNotShow
This inspection will not run by default, it must be manually enabled in Code Inspections configuration settings.
Out of convention or preference, explicit ByRef modifiers could be considered redundant since they are the implicit default. This inspection can ensure the consistency of the convention.
Identifies auto-assigned object declarations.
Default severity: Suggestion
Auto-assigned objects are automatically re-created as soon as they are referenced. It is therefore impossible to set one such reference to 'Nothing' and then verifying whether the object 'Is Nothing': it will never be. This behavior is potentially confusing and bug-prone.
Locates assignments to object variables for which the RHS does not have a compatible declared type.
Default severity: Warning
The VBA compiler does not check whether different object types are compatible. Instead there is a runtime error whenever the types are incompatible.
Identifies identifiers that hide/"shadow" other identifiers otherwise accessible in that scope.
Default severity: DoNotShow
This inspection will not run by default, it must be manually enabled in Code Inspections configuration settings.
Global namespace contains a number of perfectly legal identifier names that user code can use. But using these names in user code effectively "hides" the global ones. In general, avoid shadowing global-scope identifiers if possible.
Locates 'Stop' instructions in user code.
Default severity: Suggestion
While a great debugging tool, 'Stop' instructions should not be reachable in production code; this inspection makes it easy to locate them all.