Code review rules: Complete reference

This is a complete reference of the code audit rules supported by Project Analyzer. For a more introductory approach please refer to Code review rules.

Contents

  1. Alphabetical rule list
  2. Complete reference list
  3. Comment directives
  4. Comment directives, combination types

1. Alphabetical rule list

Add-in model changed in VB.NET

ADO required for data binding in VB.NET

Array must start at 0 in VB.NET

As Any not allowed in VB.NET

As New doesn't auto-instantiate if object released in VB.NET

As New unsupported for arrays in VB.NET

Assigned object not used

Assigned value not used

Assignment to self

Base address unoptimal

ByRef parameter read only, consider ByVal

ByRef parameter returns a value

ByRef property params unsupported by VB.NET

ByVal parameter not read

ByVal parameter written to

ByVal/ByRef missing

ByVal/ByRef not allowed in API calls in VB.NET

Call statement found

Cancel button missing

Case branch(es) missing for Enum

Case Else missing

Case overlap

Case useless

Child reuses ancestor member name

Choose function found

Class Instancing changes in VB.NET

Class looks like Interface

Class not inherited

Class not instantiated

Class/Structure nested inside Interface

Click event missing

COM method not callable from VB.NET

COM+/MTS not upgradable to VB.NET

Compilation unoptimized

Condition always True or False

Condition always True or False at run-time

Conditional block excluded

Conditionals nested too deeply

Consider short-circuited logic

Consider using Image control

Constant available

Constant declared in code

Constant missing type declaration

Constant users all dead

Constructor missing

Control not enabled

Control not visible

Control outside visible area

Control unsupported by VB.NET

CreateObject found

CType slower than DirectCast

CVDate found, use CDate

Cyclic recursion found

Cyclomatic complexity exceeds limit

Data-only class found

Dataless class found

DDE unsupported by VB.NET

Dead class

Dead compiler constant

Dead constant

Dead enum

Dead enum constant

Dead interface

Dead line label or number

Dead module

Dead parameter

Dead procedure/declaration/event

Dead procedure/declaration/event (callers all dead)

Dead return value

Dead Structure

Dead type field

Dead variable

Declare contains ordinal number

Default button missing

Default name

DefType statement found

Delayed error handling

Diagonal line unsupported by VB.NET

DoEvents() returns no value in VB.NET

Dollar would increase performance

Drag-and-drop requires rewrite for VB.NET

Empty block

Empty procedure/module

Encapsulate non-private variable as property

End statement found

Enum constant expected

Enum constant users all dead

Enum has implicit member value(s)

Enum missing zero value

Enum users all dead

Enum with duplicate value

Error event missing

Error handler missing

Event behavior changes in VB.NET

Event handler called directly

Event handler should be Private

Event log model differs in VB.NET

Event not raised

Events not handled

Excess scope

Exit statement found

Exit Sub|Function|Property found

File with several classes or modules

Finalize found

Finalize missing

Finalize missing MyBase.Finalize

Fixed file number found

Fixed-length string used

For conditions illogical

For index variable not local

For with Step 1 found

Form missing HelpContextID

Form missing Icon

Function missing type declaration

Function/Property with type character

Global found, use Public

Global variable found

GoSub statement found

GoTo statement found

Hard-coded path found

Hotkey conflict

Hotkey missing

IDisposable not implemented

IIf function found

Implementation called directly

Implementation should be Private

Implemented interface not used

Implicit variable

Informat'l complexity exceeds limit

Informat'l fan-in x fan-out exceeds limit

Inheritance limited

Initialized arrays in UDTs unsupported by VB.NET

Initializer missing for local variable

Initializer missing for variable

Interface ambiguous

Interface class contains code

Interface class instantiated

Interface duplicated

Interface members missing

Interface not implemented

Len/LenB is faster than = "" or <> ""

Let statement found

Line too long

Lines of code exceed file limit

Lines of code exceed proc. limit

Literal "" found

Local variable not cleared

Loop runs forever

Loop runs only once

Loops nested too deeply

Magic decimal number found

Magic hex number found

Magic number found

Magic octal number found

MDIForm event unsupported in VB.NET

Member cannot be default in VB.NET

Member scope exceeds container scope

Microsoft.VisualBasic.Compatibility imported

Module not upgradable to VB.NET

Multi-dimensional array found

Multiple Return statements found

Multiple statements on line

MustInherit class inherits concrete class

MustInherit class missing MustOverride methods

MustOverride overrides concrete procedure

NameCheck

Next statement ends multiple For loops

Non-instantiatable class has instance members

NotInheritable expected

Object read before set

Object read before set (along some path)

Object variable declared As New

Octal number found

Old VB project not upgradable to VB.NET

OLE Automation unavailable in VB.NET

On Error style used

On Local Error statement found

Option Explicit Off

Option Strict missing

Optional parameter in exposed procedure

Optional parameter missing default value

Optional parameter never passed a value

ParamArray is ByVal in VB.NET

Parameter not cleared

Parameter value not used

Parameter with generic type

Parameterless default properties unsupported in VB.NET

Parent class inherited only once

Parent class instantiated

Parent class requires MustInherit

Pass ByRef

Passed value not used

Possibly commented-out code

Possibly orphaned event handler

Possibly twisted tab order

Private constructor expected

Procedure not found in library

Property mixes scopes

Property passed ByRef

Protected constructor expected

Protected found in NotInheritable class

RaiseEvent fails via constructor

ReadOnly variable expected

ReDim without Dim

Rem comment found

Resizable Form missing Form_Resize

Resource file requires work in VB.NET

Return statement found

Return value discarded

Return value not set

Rewrite Sub as Function

ScaleMode must be vbTwips for VB.NET

Scope declaration missing

Seal for less overhead

Setting .Interval does not enable/disable timer in VB.NET

Shadows keyword found

Shared constructor decreases performance

Shared expected

Shared-only class instantiated

Short name

Single-line If..Then statement found

Slow ^ operator found

Stop statement found

String byte functions unavailable in VB.NET

Sub Main not executed in VB.NET

Sub Main: VB.NET program exits at End Sub

SuppressFinalize missing

Switch function found

Text comparison used

Timer event missing

Timer interval below 55 ms

Too many parameters

Too many uncommented lines

Trailing comment found

TTF/OTF fonts required by VB.NET

Type field not read, writers all dead

Type field not written, readers all dead

Type field read, not written

Type field readers all dead

Type field users all dead

Type field writers all dead

Type field written, not read

Type inference used

Type unsupported by VB.NET

Type users all dead

Unavailable in VB.NET

Uncommented procedure

Undefined compiler constant

Underscore _names not hidden in VB.NET

Unicode function is faster

Unreachable code found

Unused file

Use Binary instead of Random file access

Use compound operator

Variable clearing violation

Variable clearing violation

Variable declared in code

Variable missing type declaration

Variable not read, writers all dead

Variable not written, readers all dead

Variable read before written

Variable read before written (along some path)

Variable read, not written

Variable readers all dead

Variable users all dead

Variable with generic type

Variable writers all dead

Variable written, not read

Variable/parameter/constant with type character

VB5 project may not upgrade to VB.NET

Verify accuracy

WebClasses upgrade to ASP.NET

While loop found

WithEvents adds overhead

Write-only property found

2. Complete reference list

Dead code

ByVal parameter not read
A procedure parameter is not read by the procedure. It is written to, however. Since it is a ByVal parameter, it is essentially a dead parameter being used as a local variable. This is bad programming style. If the procedure is expected to use the parameter value, there is a bug. On the other hand, someone may just have forgotten to remove the superfluous parameter. To fix your code, Dim a local variable with the same name. To optimize the program and make it more understandable, remove the extra parameter if you can. Removal should be done carefully, though, because it can affect existing callers. At times, removal is not possible when you need to keep the interface unchanged. Project Analyzer ignores obvious cases, such as event handlers and Overrides, that must conform to a pre-defined parameter list.
'$PROBHIDE DEAD_PARAM, PARAM_NOT_READ, NOT_READ
Class not inherited
A class is defined MustInherit but it is not inherited by any child class. Because it is an abstract class, you cannot instantiate it and it is thus of no use at run-time. However, the class is in compile-time use as a data type, so you cannot just remove it. Verify how it is being used to decide whether you should add a child class, remove the MustInherit keyword or remove the class together with the users.
'$PROBHIDE NOT_INHERITED
Class not instantiated
A class is not instantiated even if it should be. Because no instances exist, you cannot access the instance procedures and variables. Thus, the class is not in use at run-time. However, the class is in compile-time use as a data type, or definitions such as Enums declared within the class are in use, so you cannot just remove it. Verify how it is being used to decide whether you should instantiate it via the New operator or remove it together with the users. This problem does not apply to abstract classes, classes with Shared members, classes that prevent instantiation or classic VB interface .cls files.
'$PROBHIDE NOT_INSTANTIATED
Constant users all dead
The value of a Const or an Enum constant is not used at run-time. Even though the constant name is referenced in the code, the respective procedures are dead. The constant value is effectively dead too, because it is not used for anything. If the constant value SHOULD be used, the program contains a flaw. Alternatively, this is a leftover from removed or disabled functionality. In that case consider deleting the constant along with the user procedure(s). Note, however, that deleting a constant from an Enum might render the Enum incomplete or change other values in the same Enum. To avoid breaking existing code, you may want to keep useless constants in the Enum.
'$PROBHIDE DEAD_USERS
Control not enabled
A control's Enabled property is set to False and it is not set to True by code. Most user interface controls are not very useful if they are never enabled. You should consider removing disabled controls as they may unnecessarily consume some resources. Events related to the control are possibly not executed. Code that reads or sets the control's properties and calls its methods is potentially unnecessary for the operation of the program. There are some cases where a disabled control can be useful, so you have to be careful about removing the control and related code. This rule does not work with control arrays. Rule applies to VB 3-6.
'$PROBHIDE CTRLDIS
Control not visible
A control's Visible property is set to False and it is not set to True by code. Most user interface controls are not very useful if they are not visible. The control was possibly set invisible by a developer who thought it was not required any more but was uncertain about removing it. You should consider removing invisible controls as they may unnecessarily consume some resources. Events related to the control are possibly not executed. Code that reads or sets the control's properties and calls its methods is potentially unnecessary for the operation of the program. There are some cases where an invisible control can be useful, so you have to be careful about removing the control and related code. This rule does not work with control arrays. It does not detect all kinds of invisibility, as controls may be hidden behind other controls or set invisible by code. Rule applies to VB 3-6.
'$PROBHIDE CTRLINV
Control outside visible area
A control is located outside of the visible area of the form it is on. The control is not moved by code and the form does not seem to resize to reveal the control. Most user interface controls are not very useful if they are not visible. The control was possibly moved outside the form borders by a developer who thought it was not required any more but was uncertain about removing it. You should consider removing invisible controls as they may unnecessarily consume some resources. Events related to the control are possibly not executed. Code that reads or sets the control's properties and calls its methods is potentially unnecessary for the operation of the program. There are some cases where an invisible control can be useful, so you have to be careful about removing the control and related code. This rule does not work with control arrays or controls that are placed within other controls. Rule applies to VB 3-6.
'$PROBHIDE CTRLOUT
Dead class
A class is not used. You may remove this class in its entirety provided that you are sure you won't need it later.
'$PROBHIDE DEAD_CLASS
Dead compiler constant
A compiler constant is defined, but it is not used for conditional compilation. You may have forgotten to use it or it may have fallen out of use due to modifications made to the code. You may remove the definition without affecting the code under analysis. If it's a #Const, removal will have no effect on the code. If the constant is defined in project settings, removal could theoretically have an effect. This would only happen if a file referencing the constant were later added to the project.
'$PROBHIDE COMPCONST, DEAD_COMPCONST
Dead constant
The value of a constant is not used. You may have forgotten to use it, or it is useless in this application. You should verify which case it is. If it's useless, you may remove it if you are sure you won't need it later. The removal doesn't affect the functionality of your program. You may consider preserving the constant for the sake of completeness or later use, though. The best way to achieve this is to comment it out. The commented constant is clearly reserved for future purposes and not being used at the moment. — An extra string constant bloats the executable size while an extra numeric constant simply bloats the source code and makes it harder to understand. A dead constant may also have an obsolete value, which is not apparent before the constant is brought back to use again. These are the reasons why dead constants should be cleaned out even though they don't affect the functionality of the program.
'$PROBHIDE DEAD_CONST
Dead enum
An Enum is not used as a data type. The constants defined by the Enum are not used either. You may remove this Enum if you are sure you won't need it later. — Even though a dead Enum does not affect the functionality of the program, its member constants may become obsolete or incomplete in time. These problems are not apparent before the Enum is brought back to use again. It is better to comment the Enum out or delete it to avoid these problems.
'$PROBHIDE DEAD_ENUM
Dead enum constant
An enumeration constant is not used. You may have forgotten to use it, or it is useless in this application. You should verify which case it is. If it is useless, you may remove it if you are sure you won't need it later. The removal doesn't affect the functionality of your program. You may consider keeping this constant available for the sake of completeness or later use, though. Note that removing a constant from an Enum may change the values of the constants that come after it, causing side effects. When removing an Enum constant it is safest to explicitly define a value for the next constant to prevent breaking existing code. The code may rely on the specific numeric values of the enum constants.
'$PROBHIDE DEAD_ENUM_CONST
Dead interface
An Interface definition is not implemented or not used. You can remove it if you are sure you won't need it later.
'$PROBHIDE DEAD_INTERFACE
Dead line label or number
An unused line label or label number was found. It is not used as a jump target or for error handling. You may remove it without changing the program flow. Line labels and line numbers are an outdated syntax feature. Line labels are typically used for error handling with On Error GoTo. A dead line label could indicate the code has been restructured; the label is what remains of previous logic. A dead label could also reveal an unexecuted error handling block. The code below the dead label may be unreachable. To detect all unreachable blocks, use the Logic rule Unreachable code found.
'$PROBHIDE DEAD_LABEL, DEAD_LINENUM
Dead module
A .NET Module is not used. You can remove the module in its entirety if you are sure you won't need it later. For VB Classic modules, see the problem Unused file for a similar rule.
'$PROBHIDE DEAD_MODULE
Dead parameter
A procedure parameter is not used by the procedure. Does this indicate missing implementation or someone just forgot to remove the parameter? Passing superfluous parameters adds unnecessary overhead. In addition, a developer may misinterpret what the procedure does by looking at its parameters, which may introduce new bugs in the code later. Remove extra parameters when you can. Removal should be done carefully, though, because it can affect existing callers. At times, removal is not possible when you need to keep the interface unchanged. Project Analyzer ignores obvious cases, such as event handlers and Overrides, that must conform to a pre-defined parameter list.
'$PROBHIDE DEAD_PARAM
Dead procedure/declaration/event
A procedure, a DLL declaration or an Event declaration is not used by the project. It is not called by the code nor executed by any other means. You may remove it if you are sure you won't need it later. The removal doesn't affect the functionality of your program. - Event declarations are reported dead only if they are not raised nor handled. See the problem Event not raised for events that would be handled but that are not fired.
'$PROBHIDE DEAD_PROC
Dead procedure/declaration/event (callers all dead)
A procedure is not executed and it is effectively dead. Calls to the procedure exist, but the callers don't execute. You should remove this procedure along with its callers, provided that you are sure you won't need any of the callers later.
'$PROBHIDE DEAD_PROC
Dead return value
A function's return value is not used by any of its callers. This indicates a possible bug in the callers or a useless return value. Review the function and the callers to determine whether the return value should be used or whether the function should be rewritten as a Sub. This problem does not apply to VB3 where return values must be used at all times. See also the style issue Return value discarded.
'$PROBHIDE DEAD_RETVAL, RETVAL
Dead Structure
A user-defined data type is not used. You may remove this if you are sure you won't need it later. The removal will not change the functionality of your code. This problem rule applies to VB Classic Types and VB.NET Structures.
'$PROBHIDE DEAD_STRUCTURE
Dead type field
A field in a user-defined type is not used by your code. You may have forgotten to use the field. It may also be useless or unused on purpose. Carefully consider the reason before removing the field. You need to review the use of the entire user-defined type. If it is being used in random file access or external DLL calls, changing the type may break the file structure or the calls. - This problem rule applies to VB 3-6 only. Fields of VB.NET Structures are handled via the rule Dead variable.
'$PROBHIDE DEAD_FIELD
Dead variable
A variable is not used. You may remove it if you are sure you won't need it later. The removal doesn't affect the functionality of your program. Before removal, you might want to determine why the variable actually is superfluous and whether it represents missing functionality or the remains of some deleted functionality. — A dead variable consumes memory and makes the program harder to understand. That is why dead variables should be removed even though they don't affect the functionality of the program.
'$PROBHIDE DEAD_VAR
Enum constant users all dead
The value of a Const or an Enum constant is not used at run-time. Even though the constant name is referenced in the code, the respective procedures are dead. The constant value is effectively dead too, because it is not used for anything. If the constant value SHOULD be used, the program contains a flaw. Alternatively, this is a leftover from removed or disabled functionality. In that case consider deleting the constant along with the user procedure(s). Note, however, that deleting a constant from an Enum might render the Enum incomplete or change other values in the same Enum. To avoid breaking existing code, you may want to keep useless constants in the Enum.
'$PROBHIDE DEAD_USERS
Enum users all dead
An Enum is used as a data type, but the users are all dead. The values in the Enum never appear at run-time. If the values SHOULD be used, the program contains a flaw. Alternatively, this is a leftover from removed or disabled functionality. Consider deleting the Enum along with the user procedure(s).
'$PROBHIDE DEAD_USERS
Event not raised
An event does not fire. The class does not call RaiseEvent to raise the event. All existing event handlers are not executed.
'$PROBHIDE NOT_RAISED
Implemented interface not used
An interface is implemented by one or more classes or structures. However, the interface is not used anywhere outside of the implementors. The interface is possibly unnecessary. This problem type is available for VB.NET Interfaces. It is also available for VB Classic classes that are used as interface definitions.
'$PROBHIDE DEAD_INTERFACE
Interface not implemented
An Interface is defined and used but it is not implemented by any class or structure. The Interface has no effect at run-time. You should either remove it or add one or more implementations. This problem type is available for VB.NET Interfaces. It is also available for VB Classic classes that have no code in them except for a public interface definition. These classes are candidates for either implementation or removal. You can implement a class by either adding code in its procedures or by implementing it via the Implements statement.
'$PROBHIDE NOT_IMPLEMENTED
Optional parameter never passed a value
An Optional parameter is never passed as a call argument. The passed value is always the default value of the parameter. Determine if it is a superfluous parameter that could be removed, and the parameter be replaced by a local constant. Alternatively, it is possible that callers have omitted the value in error. Review each calling line to see if the parameter should actually be passed some value. You can do this by right-clicking the procedure name and selecting References.
'$PROBHIDE OPTIONAL_NOVAL
Return value discarded
The return value is ignored at a call to a function. Although it is not necessary to actually use a function's return value, simply ignoring it could indicate a problem in the caller's logic. Review the call to determine if the return value can be ignored safely. This rule also verifies Declare Sub statements that could be rewritten as Declare Function if DLL analysis is enabled. This problem does not apply to VB3 where return values must be used at all times. See also the optimization issue Dead return value.
'$PROBHIDE RETVAL_DISCARDED, RETVAL
Return value not set
A function does not set its return value, which can be an error. The function always returns zero, empty or Nothing, depending on the data type. Based on the documentation or purpose of the function, determine which value it should return. You can also visit the callers of the function to see which value(s) they expect to get. If there is no meaningful value to return, rewrite the function as a Sub.
'$PROBHIDE RETVAL_NOT_SET, RETVAL
Type field not read, writers all dead
A variable is practically unused and useless. It is never read. Write statements do exist, but they never execute because the writer procedures are all dead. The variable looks like a leftover from previous functionality. There is no point writing values to the variable any more, since there are no reads from it. Consider deleting the dead writers along with the variable. Removing useless parts helps maintenance.
'$PROBHIDE FIELD_NOT_READ, NOT_READ
Type field not written, readers all dead
A variable is practically unused and useless. It is never assigned a value. Read statements do exist, but they never execute because the reader procedures are all dead. The variable looks like a leftover from previous functionality. The dead readers may contain a hidden bug (dead bug, so to say). The readers may perform in an unexpected way since the variable never gets any useful value other than zero, empty or Nothing. Taking the readers back to use can bring the bug to life. Consider deleting the readers along with the variable. Removing questionable, useless parts helps maintenance.
'$PROBHIDE FIELD_NOT_WRITTEN, NOT_WRITTEN
Type field read, not written
A field in a user-defined type is never written to, even though its value is read by the program. The value is always zero, empty or Nothing, depending on the data type. Review the code to see if the missing write is a flaw in the program or if it is intentional. The field may also be useless or unused on purpose. Carefully consider the reason before removing the field. You need to review the use of the entire user-defined type. If it is being used in random file access or external DLL calls, changing the type may break the file structure or the calls. - This problem rule applies to VB 3-6 only. Fields of VB.NET Structures are handled via the rule Dead variable.
'$PROBHIDE FIELD_NOT_WRITTEN, NOT_WRITTEN
Type field readers all dead
A variable is being read and written. The reads never execute because the reader procedures are all dead. One or more writes do execute, but it is to no benefit. This is either a problem in your program or a good place for optimization. Check to see if not reading the variable indicates a logical fault. It could indicate missing or removed functionality. You may need to bring the dead readers back to life by calling them, or add new read statements in the live part of your code. If there does not seem to be a fault, consider dropping the writes. Your code possibly does some unnecessary work in getting the right value to the variable. Remove the unnecessary parts to optimize your code.
'$PROBHIDE DEAD_READERS
Type field users all dead
A variable seems to be in use, but it is not. The user procedures never execute because they are all dead. As a result, the variable is completely unused and useless at run-time. If you remove all the user procedures, this variable will stay as a leftover unless you delete it. Use this rule to hunt for related pieces of dead code that you can remove at the same time. Right-click the variable name and select References to see the dead users. If the variable seems useful, some features may be missing from your program. Consider bringing the variable back to life by calling the dead users.
'$PROBHIDE DEAD_USERS
Type field writers all dead
A variable is being read and written. The writes never execute because the writer procedures are all dead. One or more reads do execute, though, indicating a flaw in the program. The value read is always zero, empty or Nothing, depending on the data type. Review the code to see if this is causes an error at run-time. Determine whether one of the dead writer procedures should be called to bring the variable back to full life, or whether you should add a new write statement to give the variable a real value. – This type of flawed dead code is really hard to catch without Project Analyzer. The problem is especially nasty for object variables, because the object will always be Nothing. This can cause an 'Object variable not set' error when the variable is referenced.
'$PROBHIDE DEAD_WRITERS
Type field written, not read
A field in a user-defined type is written but not read by your code. This may indicate a useless field or incomplete functionality. Carefully consider removing the field. Before removal you need to review how the type is being used. If it is being used in random file access or external DLL calls, changing the type may break the file structure or the calls. - This problem rule applies to VB 3-6 only. Fields of VB.NET Structures are handled via the rule Variable written, not read.
'$PROBHIDE FIELD_NOT_READ, NOT_READ
Type users all dead
A user-defined type is used as a data type, but the users are all dead. It is effectively dead. Consider deleting the Type along with the user procedure(s). This rule applies to the Type block in classic VB.
'$PROBHIDE DEAD_USERS
Unused file
A file is not used. Drop the file from the project. You can always add it back later.
'$PROBHIDE UNUSED_FILE
Variable not read, writers all dead
A variable is practically unused and useless. It is never read. Write statements do exist, but they never execute because the writer procedures are all dead. The variable looks like a leftover from previous functionality. There is no point writing values to the variable any more, since there are no reads from it. Consider deleting the dead writers along with the variable. Removing useless parts helps maintenance.
'$PROBHIDE VAR_NOT_READ, NOT_READ
Variable not written, readers all dead
A variable is practically unused and useless. It is never assigned a value. Read statements do exist, but they never execute because the reader procedures are all dead. The variable looks like a leftover from previous functionality. The dead readers may contain a hidden bug (dead bug, so to say). The readers may perform in an unexpected way since the variable never gets any useful value other than zero, empty or Nothing. Taking the readers back to use can bring the bug to life. Consider deleting the readers along with the variable. Removing questionable, useless parts helps maintenance.
'$PROBHIDE VAR_NOT_WRITTEN, NOT_WRITTEN
Variable read, not written
A variable is never written to, even though its value is read by the program. The value is always zero, empty or Nothing, depending on the data type. Review the code to see if the missing write is a flaw in the program or if it is intentional. The write statement(s) may have been deleted by accident or the developer forgot to add them in the first place. In this case one or more writes should be added. On the other hand, the write(s) may have been removed on purpose, in which case the variable now works as a constant. Consider removing the variable altogether or declaring it as a constant. The use of a constant prevents unexpected changes later in the life-cycle of the program. You can also save a little memory as constants don't require run-time data storage. — This review rule is especially important for object variables, because the variable will always contain the value Nothing. This can cause an 'Object variable not set' error at the location the object is referenced. A special case is denoted as 'No real value given, cleared/allocated only'. For an object variable this means the variable is set to Nothing but it never contains a live object. Alternatively, an array is allocated but nothing is stored in it. The array is consuming memory for no purpose.
'$PROBHIDE VAR_NOT_WRITTEN, NOT_WRITTEN
Variable readers all dead
A variable is being read and written. The reads never execute because the reader procedures are all dead. One or more writes do execute, but it is to no benefit. This is either a problem in your program or a good place for optimization. Check to see if not reading the variable indicates a logical fault. It could indicate missing or removed functionality. You may need to bring the dead readers back to life by calling them, or add new read statements in the live part of your code. If there does not seem to be a fault, consider dropping the writes. Your code possibly does some unnecessary work in getting the right value to the variable. Remove the unnecessary parts to optimize your code.
'$PROBHIDE DEAD_READERS
Variable users all dead
A variable seems to be in use, but it is not. The user procedures never execute because they are all dead. As a result, the variable is completely unused and useless at run-time. If you remove all the user procedures, this variable will stay as a leftover unless you delete it. Use this rule to hunt for related pieces of dead code that you can remove at the same time. Right-click the variable name and select References to see the dead users. If the variable seems useful, some features may be missing from your program. Consider bringing the variable back to life by calling the dead users.
'$PROBHIDE DEAD_USERS
Variable writers all dead
A variable is being read and written. The writes never execute because the writer procedures are all dead. One or more reads do execute, though, indicating a flaw in the program. The value read is always zero, empty or Nothing, depending on the data type. Review the code to see if this is causes an error at run-time. Determine whether one of the dead writer procedures should be called to bring the variable back to full life, or whether you should add a new write statement to give the variable a real value. – This type of flawed dead code is really hard to catch without Project Analyzer. The problem is especially nasty for object variables, because the object will always be Nothing. This can cause an 'Object variable not set' error when the variable is referenced.
'$PROBHIDE DEAD_WRITERS
Variable written, not read
A variable is given a value but the value is never read by the program. The variable is either useless or there is a flaw in the program. Review the write locations. Check the code to determine if it's a flaw or if the variable is simply a leftover from an earlier version. Remove the variable and the write statements if you are sure the variable is useless. Before removal, determine if the write statements contain any procedure calls that must execute. Removing these calls could make the program behave erroneously.
'$PROBHIDE VAR_NOT_READ, NOT_READ

Functionality

Assignment to self
An assignment statement seems to set the value of a variable or property to itself without modification. Example: x = x. This is most probably an error. The assignment is either unnecessary or it is incorrect and should be fixed.
'$PROBHIDE ASSIGNMENT_TO_SELF
Cancel button missing
A dialog box has CommandButtons but none of them is marked Cancel. When the user hits Esc, none of the buttons handle it as a Click event. Rule applies to VB 3-6.
'$PROBHIDE BUTTONS
Click event missing
A CommandButton or Menu does not do anything when clicked. Rule applies to VB 3-6.
'$PROBHIDE NO_CLICK
Declare contains ordinal number
Declare a Function or Sub with its name, not its number. If the numbering is later changed in the DLL, your program will fail. Only when the function has no name can you use the ordinal number. This problem is triggered when a Declare statement refers to function such as “#1”. The problem is ignored if DLL analysis is on and the target DLL procedure has no name.
'$PROBHIDE ORDINAL
Default button missing
A dialog box has CommandButtons but none of them is marked Default. When the user hits Enter, none of the buttons handle it as a Click event. Rule applies to VB 3-6.
'$PROBHIDE BUTTONS
Delayed error handling
A procedure uses delayed error handling (On Error Resume Next, Try without Catch). Run-time errors are handled in the procedure(s) that call this one. This may be completely as you planned, or you may have forgotten to add an error handler (On Error Goto, or Catch in a Try..End Try block). You can ignore this problem in procedures with less than or equal to x lines of code. Write x in the "Ignore when" textbox in Problem Options. Sub and End Sub lines are counted as code, making an empty procedure or property block have 2 lines. Leave the box empty for no limit.
'$PROBHIDE DELAYED_ERROR_HANDLING, NO_ERROR_HANDLER
End statement found
Your program ends here. Check to see if you really want to end your program like this. It may be completely as you planned, though, and if you think everything is OK, leave it as is.
'$PROBHIDE END
Error event missing
Every Data control should have the Error event implemented. If you don't do it, Visual Basic only displays a simple error message. It is also important to use an error handler inside the Error event, because if a new error occurs, the Error event fires again. Rule applies to VB 3-6.
'$PROBHIDE NO_ERROR
Error handler missing
A procedure has no error handler. Your program may crash if a run-time error occurs in this procedure. You can ignore this problem in procedures with less than or equal to x lines of code. Write x in the "Ignore when" textbox in Problem Options. Sub/Function and End Sub/Function lines are counted as code, making an empty procedure or property block have 2 lines. Leave the box empty if you don't wish to have a limit.
'$PROBHIDE NO_ERROR_HANDLER
Events not handled
An object variable is declared WithEvents. However, none of the events are handled.
'$PROBHIDE NO_EVENTS
Form missing HelpContextID
Your program uses context-sensitive help (F1), but a Form was found that has no HelpContextID set. Rule applies to VB 3-6.
'$PROBHIDE NO_HELPCONTEXTID
Form missing Icon
A Form doesn't have an icon that is required. A default icon, generated by VB, will be shown. Rule applies to VB 3-6.
'$PROBHIDE NO_ICON
Hard-coded path found
A string that looks like a hard-coded path name exists in your program. File access through hard-coded paths will fail if the directory structure changes. This rule catches strings starting with “A:\” to “Z:\”. It also reports relative paths in declaring a DLL procedure. In addition, the rule reports relative path names found with the following classic VB file access statements: Open, Name, Kill, Shell, ChDir, MkDir and RmDir. These statements may indicate the assumed directory structure at run-time. It is more flexible to operate with path names relative to the installation directory, for example. Where hard-coded paths are really desired, it is best to define the necessary paths with global constants or in a resource file to allow for easier maintenance.
'$PROBHIDE PATH
Hotkey conflict
Two or more controls or menu items share a hotkey. For example, there are options &Save and &Search in the same menu. Rule applies to VB 3-6.
'$PROBHIDE HOTKEYS, HOTKEY_CONFLICT
Hotkey missing
A control or menu item is missing a &hotkey. Checked controls: CommandButton, CheckBox, OptionButton, Frame, Menu. Rule applies to VB 3-6.
'$PROBHIDE HOTKEYS, NO_HOTKEY
Possibly twisted tab order
The tab order of some controls on a form looks questionable. Take a look at the TabIndex properties of the mentioned controls. The best way to do this is to open the form in VB, select the first control and press the Tab key repeatedly. Generally, the focus should move either right or down. Labels with an access key (& in the caption) should precede the control next to them. A container control should precede any child controls placed within it. A back jump is allowed to move the focus from the bottom of the form to the top-left corner. If the form's RightToLeft property is True, Project Analyzer uses a mirrored rule to require moves either left or down. The twisted tab order detection rules are not foolproof. In some cases, a twisted-looking tab order might be all right. Forms that hide, show or move their controls at run-time are exceptional in that their design-time layout is different from the run-time layout. In that case, this rule may produce a false warning and you should ignore it. Rule applies to VB 3-6.
'$PROBHIDE TABORDER
Procedure not found in library
A procedure is declared, the library exists on your system, but there is no such a procedure in the file. You have declared a non-existing procedure or the library file you have is not the required version. If you execute this procedure call on this machine, you will most probably get a run-time error. However, the code may still work on another computer with the correct library version available.
'$PROBHIDE NOT_IN_LIB
RaiseEvent fails via constructor
Event handlers cannot catch an Event that fires during object construction. That is, RaiseEvent has no effect in Sub New or one of the procedures called by Sub New. As an exception, you can raise a Shared Event from a Sub New. A Shared Event is not tied to a specific instance, and raising it through an instance constructor works. As an exception to the exception, Shared Sub New cannot raise a Shared Event. Tip: Handling a Shared Event is not possible with the WithEvents keyword. Use the AddHandler statement.
'$PROBHIDE RAISEEVENT_CTOR
Resizable Form missing Form_Resize
The Form_Resize event is missing from a Form that users can resize at run-time. Your application may look odd if you don't respond to Resize events. Rule applies to VB 3-6.
'$PROBHIDE NO_RESIZE
Stop statement found
Your program ends here. Check to see if you really want to end your program like this. It may be completely as you planned, though, and if you think everything is OK, leave it as is.
'$PROBHIDE STOP
Timer event missing
A Timer does not fire an event at defined intervals. Rule applies to VB 3-6.
'$PROBHIDE NO_TIMER
Timer interval below 55 ms
The interrupt interval of a Timer control is below 55 ms. Shorter intervals are not supported by VB. Rule applies to VB 3-6.
'$PROBHIDE TIMER_INTERVAL
Verify accuracy
A floating point constant may be imprecise. If the value suggested by Project Analyzer is for the same purpose as the value in the code, determine which version is more appropriate. This rule searches the code for decimal numbers that look like common constants, such as pi or e. The rule verifies the accuracy of such constants. The rule gets triggered where fewer than all available digits are used. Use of imprecise constants may produce incorrect results or subtle errors in calculations. Carefully consider the given accurate value. Keep in mind that changing the number may change the results as well, so you must verify your code actually works correctly with the new value. Sometimes there are several alternative values for a constant. Care must be taken to choose the correct alternative for the application in question. This rule may produce false alarms when two different constants have close values. Make sure you only change your code when you are sure the new value is correct. This feature is good for verifying scientific programs. It supports hundreds of mathematical, physical and chemical constants. Constants include ones used in physics, such as parsec, Avogadro constant, electron mass, and conversion factors such as kilometres per mile and grams per pound. The rule works with floating point values from 5 to 15 significant digits. It assumes the Double datatype. To customize the list of constants see file constant.txt in your Project Analyzer directory.
'$PROBHIDE ACCURACY

Logic

Assigned object not used
A local variable is assigned a value that is not actually used after the assignment. It is either overwritten or not used at all. Review the code to see if it is a programming error or if you can optimize by deleting the write statement. Make sure you are not removing any required function calls at this point, that is calls that have useful side effects. — Note: This rule only considers reachable code. If a read instruction exists in an unreachable statement, such as an impossible branch, it is not taken as a read. Before deleting any code, look for all use locations of the variable to determine whether the value could actually be required under some other circumstances, such as if you later change some condition. — Details: Arrays are excluded from this rule as well as parameters.
'$PROBHIDE VALUE_UNUSED
Assigned value not used
A local variable is assigned a value that is not actually used after the assignment. It is either overwritten or not used at all. Review the code to see if it is a programming error or if you can optimize by deleting the write statement. Make sure you are not removing any required function calls at this point, that is calls that have useful side effects. — Note: This rule only considers reachable code. If a read instruction exists in an unreachable statement, such as an impossible branch, it is not taken as a read. Before deleting any code, look for all use locations of the variable to determine whether the value could actually be required under some other circumstances, such as if you later change some condition. — Details: Arrays are excluded from this rule as well as parameters.
'$PROBHIDE VALUE_UNUSED
Case branch(es) missing for Enum
A Select Case statement branches off an Enum value, but it does not contain a Case for every Enum constant. This may indicate missing logic, possibly due to an Enum constant added later. Check to see whether this causes problems when an unhandled Enum value is passed. This rule requires every Enum constant name to be listed in a Case, even if the constants have the same value. Use of the underlying numeric values is not acceptable. Ranges such as Case X To Z are not acceptable either. Listing each individual constant helps prevent breaking existing Select Case blocks if the Enum is later changed or rearranged. To accept Case Else as a default branch, check Ignore when Case Else exists.
'$PROBHIDE CASE_MISSING
Case Else missing
A Select Case block is missing its Case Else branch. An unexpected input value can go unhandled. This rule lets you prevent bugs from causing havoc beforehand. You can require each Select Case to have a Case Else just in case an unexpected value comes up. As an exception, Case Else is not required by this rule if existing Case branches cover all theoretically possible input values. Tip: To detect unexpected values while debugging and run the final executable without interruption, add the Debug.Assert False statement in each Case Else that may execute due to an unexpected input value.
'$PROBHIDE CASE_ELSE
Case overlap
A Case condition overlaps an earlier condition. Since previous conditions have priority, this condition will not match all the given values. As an example, Case 1 To 5 and Case 3 To 7 overlap in values 3 to 5. To make the Cases more understandable, rewrite this condition so that overlapping does not occur. Note that a Case statement can have multiple conditions separated by commas. This rule reviews each condition separately, so there may be overlapping and non-overlapping conditions in the same Case statement. See also: Case useless.
'$PROBHIDE CASE_OVERLAP
Case useless
A Case condition will not match any input values. The condition is already covered by an earlier condition or conditions (duplicated Case or totally overlapping range). This warning is also triggered for a never-matching Case x To y, where y is less than x. Note that a Case statement can have multiple conditions separated by commas. This rule reviews each condition separately, so there may be both useful and useless conditions in the same Case statement. See also: Case overlap.
'$PROBHIDE CASE_USELESS
Condition always True or False
A conditional statement always evaluates the same way. This is an unconditional statement, really. It may be a flaw in the code. The rule checks the condition of the following keywords: If, ElseIf, Select, While and Until. Tips: To exclude useless code, use #If False rather than If False. This prevents compilation of dead lines into the executable. To loop eternally, use Do..Loop without either Until or While. Special case: Select Case True is allowed by this rule. In this syntax the real conditions appears after each Case condition as in Select Case True: Case A=B, Case C=D and so on.
'$PROBHIDE COND
Condition always True or False at run-time
Due to run-time conditions, such as the actual value of a variable or parameter, a conditional statement always evaluates the same way. This is an unconditional statement, really. It may be a flaw in the code. Be careful in removing or changing the condition as the condition may turn out essential when the code is later changed.
'$PROBHIDE COND
Conditional block excluded
A conditional compilation block (#If..#ElseIf..#Else..#End) is excluded due to a False condition. This is OK where conditional compilation is used to produce several versions of the program. In some cases it may indicate remnants of code that should have been removed. This rule is there to help you detect all False branches, should you wish to get rid of them. — A special consideration affects VB6 code that is planned to be migrated to VB.NET. The VB.NET upgrade wizard doesn't migrate code inside a False branch. It copies the code 'as is'. If the False branch is large, it is recommended that you temporarily set the condition it to True before migration. Otherwise you will have to migrate it manually.
'$PROBHIDE EXCLUDED
Cyclic recursion found
Cyclic recursion happens when A calls B, which calls C, which eventually calls A again. Recursion through two or more procedures is difficult to understand and get to work correctly. There is also a risk of endless recursion. Cyclic recursion is also called indirect recursion, as opposed to direct recursion, where a procedure calls itself repeatedly. Direct recursion is not as problematic as cyclic recursion. Consider replacing cyclic recursion with either a non-recursive technique or direct recursion. Restricting recursion to a single procedure is easier to manage. To prevent endless recursion, you can add a safety counter that breaks the execution if it goes too deep. To fully understand a large recursive cycle, get the Recursion diagram in Enterprise Diagrams. Note: This rule triggers based on static analysis. Due to run-time conditions and checks, the actual execution path might not be recursive.
'$PROBHIDE RECURSION
Empty block
An empty block was found. Empty blocks may indicate unfinished functionality or functionality that has been deleted or commented out. As an example, an empty If block does not execute anything based on the decision. An empty Else block is totally useless and can be removed. Where an empty If block is followed by an Else block, the logic should be reversed and the Else block removed to make the code more readable. An empty Try block is useless. An empty Catch block does not process the exception it caught. When removing empty blocks be careful that the functionality will not change. Before removing an empty If..Then, make sure that the condition does not execute any important calls. Before removing an empty Case, make sure it does not affect any Case that comes after it. Before removing an empty loop, make sure it indeed does not perform anything useful. — You can optionally allow empty blocks containing a comment. In this programming style, a non-empty comment indicates the block is intentionally empty. — Empty Case Else blocks are not considered to be a problem. Empty Case Else is common practice to indicate that there is no processing for other values in a Select block.
'$PROBHIDE EMPTY_BLOCK
Empty procedure/module
This rule detects empty modules, classes, interfaces and the like. In addition, it detects procedures having no executable statements in them. Since declarative statements do not count, a procedure with just a Dim or a Const line can also be reported as an empty procedure. Procedures that need to be empty, such as interface methods, are not reported by this rule. A special case is when an empty Overrides procedure deletes the functionality of an ancestor class method. Overriding should not be used to delete class functionality. The class hierarchy should be redesigned to avoid the need for empty Overrides. Project Analyzer supports an option to ignore the Empty procedure/module warning if there is a comment in the procedure or module. A comment makes it explicit why the procedure or module is empty. The comment also allows you to tell unintentionally blank procedures from intentionally blank ones.
'$PROBHIDE EMPTY
For conditions illogical
The start, end and/or step values of a For statement appear incorrect. This rule checks for For..Next loops that won't start, loops that may iterate just once and loops that may iterate forever (Step 0). To appear logical, For..Next should be able to iterate at least twice.
'$PROBHIDE FORCOND
Loop runs forever
An eternal loop was found. Once the loop is entered, there is no exit or all exits are unreachable. The program could jam here.
'$PROBHIDE LOOP_FOREVER
Loop runs only once
A loop starts but it doesn’t execute another round. Is it a flaw? Should it run several times or can you just remove this useless loop? — Related rule: A loop that runs zero times is reported as Unreachable code.
'$PROBHIDE LOOP_ONCE
Object read before set
A local object variable is being accessed, but its value is always Nothing at this point. A run-time error is likely (null pointer reference, object variable not set). This warning appears where an object variable cannot be set by a preceding instruction. This is a severe version of rule “Object read before set (along some path)”, since this rule reports cases where the object is believed to be Nothing at all times regardless of previous execution. See also: “Variable read before written”. Tip: To improve the accuracy of this rule, enable analysis of library files (Enterprise Edition required).
'$PROBHIDE READBW
Object read before set (along some path)
A local object variable is being accessed, but its value may be Nothing. A run-time error may occur at this point (null pointer reference, object variable not set). This warning appears when some path may have left an object variable unset. To avoid a run-time error verify that the variable will actually contain an object at this point. This rule is related to “Variable read before written (along some path)”, see that for details. Tip: To improve the accuracy of this rule, enable analysis of library files (Enterprise Edition required).
'$PROBHIDE READBW
Parameter value not used
The value passed to a procedure parameter is not actually used. The value is overwritten or execution never flows into a read instruction. Review the code to see if it is an error. — This rule is related to the “Dead parameter” rule. A Dead parameter is one that is not used at all. “Parameter value not used” means the parameter name is indeed in use, but not the value passed to it.
'$PROBHIDE VALUE_UNUSED
Passed value not used
A parameter is being passed in a procedure call, but the receiving procedure does not actually use the value. Is the logic still all right? It may be possible to optimize by leaving out the parameter or by passing a dummy constant instead of a calculated value. This rule excludes “out” parameters, which are used to return a value.
'$PROBHIDE VALUE_UNUSED
Unreachable code found
A block of code is dead because it is not reachable. It will never execute. Unreachable code means impossible branches, loops that don’t run, unused error handlers (On Error style) and labeled blocks that are not being jumped into. Code that immediately follows an unconditional jump (such as a Return or Exit statement) can also be unreachable. Unreachable code cannot run at all. It is a programming error: bad logic or the remains of old code that should have been deleted. Determine whether you should remove the unreachable block or if it should rather be brought back to life. Unreachable code should not be exist. If it is necessary to leave it for later use, consider commenting it out or putting it in an #If..#End If block to exclude it from compilation and to make it explicit it may be required later. — This rule is good for detecting On Error style error handlers that are not in use. It can also detect broken loops that don't loop (last statement never reached). It can even detect code that was removed by writing Exit Sub above it.
'$PROBHIDE REACH
Variable read before written
A local variable is being read before a write instruction ever executes. At this point the variable will always contain its default value (zero or empty string). This is most probably a mistake. The preceding write instruction may have been deleted or the execution flow wrongly modified. It could also indicate a superfluous variable or the use of an incorrect variable. This rule ignores error handlers, as the run-time triggering of an error handler is difficult to determine by code analysis. This rule finds variable read before *any* write has occurred, whereas the rule “Variable read before written (along some path)” triggers when that is even a remote possibility. Tip: To improve the accuracy of this rule, enable analysis of library files (Enterprise Edition required).
'$PROBHIDE READBW
Variable read before written (along some path)
A local variable is being read before a write instruction is guaranteed to have executed. Thus, when the variable is read, its may have a proper value, but it could also contain its default value – potentially due to a mistake. Depending on the case this may be problematic or not. This warning appears when some path up to a read instruction executes a write instruction while some other path does not. Typically a Then branch writes while Else does not (or vice versa). Another case is when a loop writes to a variable that is read after the loop; if the loop executes zero times, the variable is undefined. You must determine case by case if this is an actual mistake or if it is rather by design. In may cases, 1) use of the variable’s default value may be OK or 2) all executing paths will write to the variable. In a summary, this is a “check this out” type of a rule rather than a “must fix” warning. Tip: To improve the accuracy of this rule, enable analysis of library files (Enterprise Edition required).
'$PROBHIDE READBW

Metrics

Conditionals nested too deeply
Conditional statements nested too deeply. Try simplifying or splitting up the procedure. You can set the limit by yourself.
'$PROBHIDE DCOND
Cyclomatic complexity exceeds limit
Too high cyclomatic complexity. Try simplifying or splitting up the procedure. You can set the limit by yourself. Different recommendations exist, but common threshold values are 11 and 21.
'$PROBHIDE CC, CYCL_COMPLEXITY
Informat'l complexity exceeds limit
Too high informational complexity. Try simplifying or splitting up the procedure. You can set the limit by yourself.
'$PROBHIDE IC1, INF_COMPLEXITY
Informat'l fan-in x fan-out exceeds limit
Too high informational fan-in x fan-out value. You can set the limit by yourself.
'$PROBHIDE IFIO, INF_FANINOUT
Lines of code exceed file limit
Too many lines of code in a file. You can set the limit by yourself.
'$PROBHIDE LOC
Lines of code exceed proc. limit
Too many lines of code in a procedure. You can set the limit by yourself.
'$PROBHIDE LOC
Loops nested too deeply
Loops nested too deeply. Try simplifying or splitting up the procedure. You can set the limit by yourself.
'$PROBHIDE DLOOP

Optimization

Base address unoptimal
A library project's base address is set to the default value in project options. When loading the library, the operating system tries to load it at this address. If not possible, it relocates the library. Changing this address to another value will help to reduce the likelihood of relocation, thus making the library load faster. The base address affects ActiveX OCX, ActiveX DLL and .NET Class Library/Web Control Library projects. Notice that in .NET projects, different configurations (Debug/Release) can have different base address values. The rule works on the currently selected configuration.
'$PROBHIDE BASEADDR
Compilation unoptimized
The compilation settings for a project are set for unoptimized compilation. In VB 5-6, this is due to p-code or unoptimized compilation. Open the Project Options dialog and choose Compile to Native Code and either Optimize for Fast Code or Small Code in the Compile tab. In .NET this problem indicates that compile-time optimizations are disabled. Right-click the project in VS.NET, open the property pages and choose Enable optimizations. You can also enable some advanced optimization techniques using the settings found in these dialog boxes. Notice that in .NET projects, different configurations (Debug/Release) can have different optimization settings. The rule works on the currently analyzed configuration. There are no optimization settings for projects written with VB 3-4.
Consider short-circuited logic
In the expressions (x And y), (x Or y), both operands (x, y) are evaluated. Short-circuiting means rewriting this so that when x=False in (x And y), y is not evaluated. The same goes for x=True in (x Or y). This saves CPU cycles, especially if y is a complex expression. In VB.NET, consider replacing And with AndAlso, and Or with OrElse. In VB Classic, consider splitting an If ..And.. condition as two nested Ifs. Short-circuiting If ..Or.. yields more complex code, usable case by case. Risks: Short-circuiting changes the logic. If the second operand calls a function, this call may not execute. Read VB help for differences between And/AndAlso and Or/OrElse.
'$PROBHIDE SHORTCIRC
Consider using Image control
A PictureBox uses significantly more memory and system resources than an Image control. While PictureBox has more features, this PictureBox is a potential candidate to be replaced by an Image control. Rule applies to VB 3-6.
'$PROBHIDE PICTUREBOX
Constant available
A constant is available in place of a function call. Use a string constant instead of Chr/ChrW. The available string constants and their ASCII values are: vbNullChar (0), vbBack (8), vbTab (9), vbLf (10), vbVerticalTab (11), vbFormFeed (12), vbCr (13), vbCrLf or vbNewline (13 & 10). vbNewline is faster than vbCrLf. Successive Chr(13) & Chr(10) should be replaced by vbNewline, not vbCr & vbLf. - Instead of a call such as Asc("A"), use a numeric constant such as Const ascA = 65. - These rules apply to VB 4-6. In VB.NET the compiler takes care of optimizing the use of these functions.
'$PROBHIDE ASC, CHR
CType slower than DirectCast
Use the DirectCast keyword instead of the CType keyword when you're just casting an object variable to a variable of a different type in .NET. DirectCast can deliver better performance because it never calls methods in the Microsoft.VisualBasic DLL. You should notice the risk of using DirectCast, though. DirectCast can raise a run-time error if the run-time types don't match. In this case, CType may perform type coercion, while DirectCast raises an error.
'$PROBHIDE CTYPE
CVDate found, use CDate
The CVDate function has been replaced by CDate since VB4. CVDate returns a Variant, while CDate returns a Date data type. As to their use, CVDate and CDate are identical except for the handling of Null. CVDate(Null) returns Null, while CDate raises an error. This is a possible caveat when replacing CVDate with CDate.
'$PROBHIDE CVDATE
Dollar would increase performance
Adding $ at the end of a function would increase the speed of execution. Certain functions, like Left, Mid and Right return a Variant that contains a String. The corresponding functions Left$, Mid$ and Right$ return a String. Using the String version makes your program run faster. Rule applies to VB 3-6.
'$PROBHIDE NO_DOLLAR
Len/LenB is faster than = "" or <> ""
To check if a string is empty or not, it's quickest to use the Len function. To test for an empty string, use Len(str)=0. To test for a non-empty string, use Len(str)<>0. In VB 4-6, use the LenB function instead of Len for the same purpose with extra performance. In VB3 and VB.NET, use the Len function.
'$PROBHIDE NULLSTR
Literal "" found
The string literal "" is present in your code. If the statement is an assignment, use vbNullString instead of "". vbNullString is a special constant, available in VB4 and later, that speeds up the assignment and subsequent processing of the value. In classic VB, vbNullString is a null pointer (zero integer), the use of which saves some bytes in the executable file. In VB.NET the case is a bit more complex because vbNullString is the equivalent of Nothing. Replacing "" by vbNullString may introduce errors if you use the string variable in an object-oriented way by calling its methods or properties such as s.Length. In this case, stick to "". Note: In comparison statements use Len/LenB(x)=0 rather than x="".
'$PROBHIDE NULLSTR
Multi-dimensional array found
In VB.NET, jagged arrays (arrays of arrays) are faster to access than multi-dimensional arrays. The .NET compiler optimizes jagged arrays more efficiently. For example, replace Dim myArray(9,8) As Integer with Dim myArray(9)() As Integer. If your array is large or if you access it often, this optimization technique can give you a moderate performance boost.
'$PROBHIDE MULTIDIM
Object variable declared As New
In classic VB, declaring an object variable As New creates an auto-instantiating variable. Each time you read the contents of the variable, VB first checks if the variable contains an object, and creates one if not. This adds overhead, thus slowing your program down. To achieve better performance, remove the word New from the declaration, and instantiate your variable (Set x = New Class) before it is used. It makes sense to test with 'If x Is Nothing Then' before accessing the variable, to avoid the run-time error 'Object variable not set'. In addition, VB.NET has different semantics for As New. Rule applies to VB 3-6.
'$PROBHIDE ASNEW
Seal for less overhead
Seal your .NET classes and methods when possible. Overridable (= virtual) methods are slower to call. Overridable methods are polymorphic resulting in calling overhead, which is significant if you need to run millions of calls. Remove any unnecessary Overridable keywords from method definitions. If your method has the Overrides keyword, add NotOverridable to seal the method. Note that it's not necessary to seal the Finalize destructor. If you don't intend to inherit from a class, seal the whole class with the NotInheritable keyword. Attribute classes should also be sealed with NotInheritable.
'$PROBHIDE SEAL
Slow ^ operator found
Raising to a power with the ^ operator is slow when executed in a loop. Replace ^ by one or more multiplications to achieve better performance: i^2 = i*i, i^3 = i*i*i and so on. For a negative exponent, use division: i^(-1) = 1/i, i^(-2) = 1/i/i and so forth. Note that exponents 0 and 1 make no sense since i^1 = i and i^0 = 1. This rule reports integer exponents from -9 to 9.
'$PROBHIDE POW
Text comparison used
Text comparison is much slower than binary comparison. For more speed, use Option Compare Binary, vbBinaryCompare (VB 5-6) and CompareMethod.Binary (VB.NET).
'$PROBHIDE TEXTCOMP
Unicode function is faster
The wide functions AscW and ChrW/ChrW$ are faster than the Asc/Chr/Chr$ alternatives. VB works internally in Unicode, so the unicode versions run faster. They are not the same functions though. If you're handling ASCII characters from 0 to 127, you're safe to replace Asc with AscW and Chr with ChrW/ChrW$. Rule applies to VB4 and later.
'$PROBHIDE ASC, CHR
Use Binary instead of Random file access
Random file access is significantly slower than Binary access, making file read/write unnecessarily slow. Replace Random with Binary. There is a catch, however. Handling of file position values is different. For random access, it's the record number. For binary access, it's the byte in the file. Thus, check all Get and Put (VB 3-6) or FileGet/FileGetObject/FilePut/FilePutObject (VB.NET) statements.
'$PROBHIDE RANDOM
Use compound operator
The compound operators +=, -=, ^=, *=, /=, \=, &=, <<= and >>= run faster than their regular counterparts in VB.NET. This is mainly true if the leftmost operand includes a property or function call.
'$PROBHIDE COMPOUND
WithEvents adds overhead
The WithEvents keyword adds overhead to variable access, as .NET implements these variables as properties. Consider removing WithEvents and handling the events via the AddHandler mechanism. The WithEvents syntax may be easier to read, but it slows down your program.
'$PROBHIDE WITHEVENTS

Style

ByRef parameter read only, consider ByVal
A ByRef parameter is not changed by the procedure. Consider passing the parameter by value (ByVal) instead of by reference (ByRef). This will prevent errors later. A future modification could accidentally change the value of the ByRef parameter, which could cause problems when the changed value is passed back to the callers. ByVal protects the callers from these unexpected changes. ByRef may sometimes be necessary for speed optimization, though. You can use this review rule to find ByRef parameters that could safely be made ByVal without changing the current logic.
'$PROBHIDE BYREF_READONLY
ByRef parameter returns a value
A procedure returns a value in a ByRef parameter. It is undesirable to return values via 'out' parameters. Callers of the procedure may not expect changes to the arguments. An unexpected change may result in an error that is hard to detect. Values should only be returned as function return values. Consider changing the parameter to ByVal and possibly returning the value in the function return value. If you need to return several values, consider a user-defined type as the return data type. If you really need to use an 'out' parameter, name it clearly to make it obvious. Out parameters in Functions and Properties are especially undesirable as they cause unexpected side effects. They are a bit less problematic for Subs, which do not have any other return value. For this reason, Project Analyzer offers the option 'Ignore for Subs'. Specifics: The value change does not necessarily happen in the procedure indicated. The parameter may be passed ByRef further to another procedure that does the writing. For an interface parameter the change may occur in the procedure(s) that implement the interface. If it's an Overridable procedure, writing may occur in Overrides methods in descendant classes. See also: ByVal parameter written to.
'$PROBHIDE BYREF_RETVAL
ByVal parameter written to
Procedure changes the value of a ByVal parameter. Procedures should not assign values to their formal parameters directly. Instead, procedures should declare a local variable for this purpose. Changing the value of a parameter may lead to errors that are hard to catch. When writing modifications to the procedure later, a developer may assume that the parameter retains its original value, even when it has changed. On the other hand, if a ByVal parameter is later changed to ByRef (due to optimization, for example), changes written to the parameter will propagate to the callers causing unexpected results. — Alternative use: Enable this rule to detect ByVal parameters that might be intended as 'out' parameters and should be changed to ByRef. See also: ByRef parameter returns a value.
'$PROBHIDE BYVAL_WRITTEN
ByVal/ByRef missing
A parameter has no ByVal or ByRef declaration. The default in VB 3-6 is ByRef. In VB.NET, the default is ByVal. Use of ByRef should be limited to where it is clearly required. ByVal is safer because it prevents values of passed parameters from being changed accidentally. Since bugs can easily occur with implicit ByRef, add either ByVal or ByRef to all parameters. Exception: explicit ByRef is unavailable in VB3. — If you migrate VB 3-6 code to VB.NET, there is yet another catch. The VB.NET upgrade wizard adds ByRef automatically. Add ByVal/ByRef manually to prevent this.
'$PROBHIDE NO_BYVAL
Call statement found
The Call statement is no longer needed. You may remove it.
'$PROBHIDE CALL
Child reuses ancestor member name
A child class member has the same name as a private member of its ancestor class. Even though a child class is allowed to have any member names, it should not reuse the names of private members of its ancestors. The use of similar names increases the probability of programming errors. First, it may not be clear to a developer that there are two different things with the same name. Second, if the ancestor member scope is later changed, it will result in name shadowing. This rule is related to the Shadows keyword but technically speaking, it is not actual name shadowing because a private ancestor member is not visible to the child.
'$PROBHIDE REUSES_NAME
Choose function found
The Choose function is considered bad programming style because of functionality, optimization and readability issues. All expressions in Choose are always executed, resulting in longer execution time and possible unwanted side-effects. May return unwanted Null. Use Select Case instead.
'$PROBHIDE CHOOSE
Class looks like Interface
An abstract .NET class looks like an Interface in that it defines actions but does not implement them. Could you rewrite the class as an Interface to make this explicit? If the only purpose of the class is to define a set of procedures for descendants to implement, redefining it as an Interface might be more appropriate. It is a matter of programming style which way you prefer. This rule finds abstract MustInherit classes that define one or more empty procedures. In addition, they must not define any implementation, that is, variables, Private procedures or any procedures with code in them. If the class inherits another class (other than System.Object), the parent must also look like Interface (except that it does not necessarily have to define any procedures).
'$PROBHIDE LIKE_INTERFACE
Class/Structure nested inside Interface
Interfaces should not define inner classes or structures. This is bad programming. An interface is an abstraction of a concept, a Class or Structure is an implementation. Don’t mix these, but leave the implementation details out of interfaces. Nesting an Interface within an Interface is odd as well, but since it may have special uses, this rule does not trigger a warning about them.
'$PROBHIDE IN_INTERFACE
Constant declared in code
A Const statement is found among procedure code. You can require that all constants be declared in their own block at the start of a procedure. The benefit of this style is that all declarations can be found quickly in one place.
'$PROBHIDE CONST_DECL_IN_CODE, DECL_IN_CODE
Constant missing type declaration
A constant has no defined data type. VB will pick an appropriate data type for it. The chosen type may not be optimal where the constant value is actually used. You can use this rule to require explicit typing of constants.
'$PROBHIDE NO_TYPE
Constructor missing
A concrete .NET class should define at least one constructor for instantiating objects of the class. The scope of the constructor should be used to define who can instantiate the objects. A Shared constructor is not enough for a concrete class. This rule skips abstract MustInherit classes and classes that have only Shared members. These special class types are subject to the rules Protected constructor expected and Private constructor expected, respectively.
'$PROBHIDE CTOR
CreateObject found
CreateObject is a late-bound call. Generally speaking, you should use early binding to achieve better performance and also to avoid programming errors. To replace CreateObject with an early-bound call, simply use the syntax As New Classname. If this is not successful, add a reference from your project to the underlying COM library. This rule allows the use of CreateObject when creating objects on a remote server.
'$PROBHIDE CREATEOBJECT
Data-only class found
A class consists only of data. There is no behavior. Is this a class, really? Consider whether the class would work better as a user-defined Type or Structure. You may also want to put the variables as member variables of another class or classes. As exceptional cases, this rule allows data-only interfaces (classic VB .cls interfaces) and data-only base classes with at least 2 children. The latter case is a common data class with different implementation classes that act on the same data.
'$PROBHIDE DATAONLY
Dataless class found
This class contains procedures, but no class-level variables. Check to see if this is the right way to obtain abstraction. The procedures might work better in a module or as a part of another class. There is no point in instantiating dataless classes, really. If you want to keep the dataless class, consider making it a static class with Shared methods and a Private Sub New to prevent instantiation. This rule explicitly allows dataless Shared-only classes.
'$PROBHIDE DATALESS
Default name
A project, module or control has not been named with a descriptive name. VB has generated a default name instead, like Project1, Module1, Text1, List2 etc. This rule is available for VB 3-6 controls and VB 3-6 and VBA project and module names.
'$PROBHIDE DEFAULT_NAME
DefType statement found
DefType statements force data types on declarations starting with the given letters. Relying on DefType may cause confusion because the datatype is not visible on each declaration. Use the 'As Datatype' syntax for more readable declarations that are also easier to maintain. The rule catches the following statements: DefBool, DefByte, DefInt, DefLng, DefLngLng, DefLngPtr, DefCur, DefSng, DefDbl, DefDate, DefStr, DefObj, DefVar. This problem is available for VB 3-6.
'$PROBHIDE DEFTYPE
Encapsulate non-private variable as property
Variables that aren't Private should be avoided in classes. Read/Write access to a class's member variables should only be allowed via properties. Make the variable Private and add a property to read/write the contents. — Warning 'Passed ByRef. Encapsulated Property will not receive changes back from ByRef.' In classic VB, passing a variable ByRef may change the value of the variable. Passing a Property ByRef will not change the value, however. This can lead to errors that are hard to debug. When you encapsulate a variable as a property, make sure the logic still functions with ByRef calls. Project Analyzer detects ByRef passing and shows the warning text for the problem. This is not an issue with VB.NET because VB.NET uses copy-in/copy-out semantics for Properties passed ByRef, so variables and encapsulated properties work the same.
'$PROBHIDE PUBVAR
Enum constant expected
An enumeration constant is expected on this line. An Enum datatype is assigned a value not belonging to that Enum. One should only store Enum values, not integers or other datatypes. Otherwise you easily end up with a value outside to the Enum. An Enum should fully define and document the datatype’s acceptable values. Using an undefined value is undocumented programming, really, or even an indication of erroneous logic. A programming style that uses ’magic’ integers interchangeably with Enum constants is prone to maintenance errors. If the Enum values are later changed, the respective ’magic’ integers are easily left unchanged, which leads to new errors. This rule checks assignment statements and the default value of an Optional parameter. In addition, it checks Enum-type Consts. The warnings triggered by this rule are for your information, not necessary an indication of a real problem. At times, you may choose to ignore this warning when the code is clear or when it is not possible to rewrite it.
'$PROBHIDE ENUM_CONST_EXPECTED
Enum has implicit member value(s)
One or more members of an Enum do not have an explicitly declared value. The values might change if new members are added. This potentially affects code where the old values are used instead of the enum member names.
'$PROBHIDE IMPLICIT_ENUM
Enum missing zero value
An Enum should define a constant with the value of zero. The default value of an uninitialized Enum variable is zero. Explicitly defining a zero Enum constant makes the uninitialized value valid. You can name the zero constant with a descriptive name such as None or Empty or Error.
'$PROBHIDE ENUM_ZERO
Enum with duplicate value
Two or more constants in an Enum define the same value. Check to see if this is by accident. Declaring the same value several times may be intended. On the other hand, an error may have caused the duplicate definition. Check to see if you can join the multiple constants into one to prevent problems understanding the Enum later.
'$PROBHIDE ENUM_DUPLICATE
Event handler called directly
Event handlers should not be explicitly called by other procedures. They should only execute as a response to an event. Calling handlers directly may lead to less manageable code. In addition, you may need to pass useless or fake arguments to the event handler. Create a new procedure, give it a meaningful name and move the called functionality to it. Should you later need to change the event handler, the changes will not accidentally affect the calling procedure. Tip: This problem may rarely be incorrectly shown for regular procedures that look like event handlers (say Pic1_Clack). In that case re-analyze the system including all COM files in the analysis. This will make event handler detection more accurate. Tip works with VB 4-6 and requires Project Analyzer Enterprise Edition.
'$PROBHIDE CALLED_DIRECTLY
Event handler should be Private
Event handlers should be marked Private to prevent other modules from calling them directly. If it is necessary that the functionality be called from outside, the event handler should call the functionality in a separate procedure. In VB.NET, Private is also necessary to prevent child classes from overriding an event handler. Otherwise a less secure procedure could override a secure event handler, opening a potential security vulnerability.
'$PROBHIDE HANDLER_PRIVATE
Excess scope
A part of your program has a wider scope than necessary. It is a good practice to use as tight a scope as possible to prevent other parts of the program calling and modifying parts that they shouldn't have anything to do with. You can define a more limited scope without affecting the current use of this code. Before limiting the scope, see if there is a reason why the wide scope might be necessary later. Rule works with VB 3-6.
'$PROBHIDE EXCESS_SCOPE, SCOPE
Exit statement found
Use of the Exit statement indicates unstructured program flow, much the same way as the Goto statement. An Exit statement causes an immediate jump out of a programming structure such as a loop. In purely structured programming style Exit statements should not be used. Well-placed Exit statements are not considered harmful by many programmers, though.
'$PROBHIDE EXIT
Exit Sub|Function|Property found
An Exit Sub|Function|Property statement causes an immediate jump out of a procedure. It potentially makes the procedure have several exit points. Procedures should have only one exit point at the end. — There is a case where VB requires a premature Exit. This is when you need to quit a procedure immediately before an On Error Goto xxx type error hander. Project Analyzer allows this use.
'$PROBHIDE EXIT
File with several classes or modules
Each file should contain just one class or one module. This makes it easier to keep track of the project structure. It’s OK to put related Structures or Interfaces in the same file with a class or module. It’s also OK to nest classes when necessary. This rule applies to VB.NET only.
'$PROBHIDE MANYMOD
Finalize found
A .NET class defines a Finalize destructor. Finalization is generally not required if the class uses only .NET managed resources. The existence of a Finalize destructor will slow down the garbage collection process, which has a negative performance impact if a large number of instances of a class are created and destroyed. For maximum speed, finalization should be left to classes that allocate unmanaged resources.
'$PROBHIDE NO_FINALIZE
Finalize missing
A .NET class defines no Finalize destructor. Proper finalization is required if the class uses unmanaged resources. Finalization is generally not required if the class uses only .NET managed resources. The compulsory use of a Finalize method is a matter of programming style.
'$PROBHIDE NO_FINALIZE
Finalize missing MyBase.Finalize
A Finalize destructor of a .NET class should call MyBase.Finalize to free up any resources allocated by the base class. If the class derives directly from System.Object, this call is not necessary.
'$PROBHIDE NO_MYBASE_FINALIZE
Fixed file number found
Using fixed file numbers (hard-coded integers) in file handling is a potential cause of run-time errors. It is better to use a variable and initiate it with the FreeFile function like this: FileNum = FreeFile.
'$PROBHIDE FIXED_FILENUM
Fixed-length string used
The fixed-length string data type should be reserved for uses where it is required. In many cases, the variable-length string provides more efficient memory usage and better performance. Use of variable-length strings is also preferred if you plan to convert to VB.NET later as VB.NET provides only limited support for fixed-length strings. Rule applies to VB 3-6.
'$PROBHIDE FIXEDLEN
For index variable not local
A For or For Each loop should use a local index variable. This index variable is defined outside the procedure. Alternatively, it is a ByRef parameter. The loop updates the variable’s value, which may be an unexpected side effect in this procedure. Fix the problem by declaring a local variable of the same name. In VB2003 and later, use the syntax For j As Datatype to create a local loop variable. In VB2008 and later, this problem can accidentally occur with Option Infer On.
'$PROBHIDE FORVAR
For with Step 1 found
Specifying Step 1 in a For statement is redundant because one is the default value. You may omit the Step 1 clause.
'$PROBHIDE STEP1
Function missing type declaration
A function does not have a defined return data type. By default, the type is Variant in classic VB and Object in VB.NET. These generic types need more memory than other data types. Decide what type you need and write it to the declaration. As an additional bonus, upgrading to VB.NET will be easier if you use explicit data types. In VB.NET, you can set Option Strict On to require explicit data types.
'$PROBHIDE NO_TYPE
Function/Property with type character
A Function or a Property is declared with one of the old-style $#%!&@^ type characters. Instead of MyFunction$( ), use MyFunction( ) As String, etc.
'$PROBHIDE TYPE_CHAR
Global found, use Public
Use of the Global keyword is outdated. Simply replace Global with Public. VB3 supports only Global. VB 4-6 support Global but favor Public. VB.NET no longer supports Global but requires Public.
'$PROBHIDE GLOBAL, SCOPE
Global variable found
Global variables (Public and Friend variables declared inside standard modules) are convenient for programmers working under pressure. It's usually easier and faster to define globals rather than pass parameters. Unfortunately, as the global variable is fully accessible from all parts of the project, it's difficult to determine the source of error should the global variable be found to have an incorrect value. This has an effect on debugging time.
'$PROBHIDE PUBVAR
GoSub statement found
A GoSub or On..GoSub statement exists in code. Use of GoSub is bad programming practice, leads to low execution performance and should be avoided when possible. In addition, VB.NET doesn't support GoSub. Rule applies to VB 3-6.
'$PROBHIDE GOSUB
GoTo statement found
A GoTo or On..GoTo statement exists in code. Use of GoTo is bad programming practice and should be avoided when possible. Jumping around with GoTo easily leads to unstructured control flow structure and spaghetti code.
'$PROBHIDE GOTO
IDisposable not implemented
A .NET class defines a Finalize destructor but does not implement the IDisposable interface. An object that allocates some resources should implement IDisposable.Dispose to free the resources when the object is no more required. Users can call Dispose to free the resources as soon as possible. Relying on the Finalize destructor to release resources will lead to resources staying allocated for a longer time than what is necessary. This happens because the garbage collection process will execute Finalize asynchronously at a later time. Read .NET help for 'Implementing a Dispose method' for information on how to implement finalization with IDisposable. See also the rule SuppressFinalize missing.
'$PROBHIDE NO_IDISPOSABLE
IIf function found
The IIf function is considered bad programming style because of functionality, optimization and readability issues. Both cases of IIf are always executed resulting in longer execution time and possible unwanted side-effects. Use If..Then..Else..End If instead.
'$PROBHIDE IIF
Implementation called directly
A procedure that implements an interface should not be explicitly called by other procedures. It should execute as a response to the interface it implements. A direct call may lead to less manageable code. Create a new procedure, give it a meaningful name and move the called functionality to it. Should you later need to change the interface, or the implementation, the changes will not accidentally affect the calling procedure.
'$PROBHIDE CALLED_DIRECTLY
Implementation should be Private
Procedures that implement an interface should be marked Private to prevent other modules from calling them directly. If it is necessary that the functionality be called from outside, the implementation and the functionality should be in separate procedures. In VB.NET, Private is also necessary to prevent child classes from overriding the implementation of an interface. Otherwise a less secure procedure could override a secure implementation, opening a potential security vulnerability.
'$PROBHIDE IMPL_PRIVATE
Implicit variable
This statement creates a new local variable without any explicit declaration. This can happen with the For and For Each statements with Option Infer On (introduced in VB2008). While this causes no immediate problem, there is a risk of maintenance errors. If a variable with the same name is later Dim’d, the statement will start changing that variable, which is most probably not wanted. Fix the problem by explicitly adding a datatype declaration with syntax For [Each] j As datatype. You can switch Option Infer Off to prevent this problem from reoccurring.
'$PROBHIDE IMPLICIT_VAR
Inheritance limited
All methods and properties of a class are sealed but the class is not. The class can be derived but none of the derived methods or properties can be overridden by subclasses. Subclasses can thus add new functionality but they cannot modify existing behavior. This restriction can be considered a form of limited inheritance, indicating a possible design flaw. You have two choices to clear things up. If the class is not designed to be derived from, prohibit inheritance by adding a NotInheritable keyword to the class and removing any NotOverridable keywords from the methods. This way you explicitly seal the class to disallow limited inheritance. Alternatively, go from limited inheritance to more versatile inheritance by defining some appropriate methods Overridable. You can also choose to overlook this problem if limited inheritance is what you want to achieve.
'$PROBHIDE INHERITANCE_LIMITED
Initializer missing for local variable
A local variable declaration does not contain an initializer. The default value for the variable will be zero or Nothing. A value of Nothing can lead to a run-time error when used. You can initialize a variable by either of the following syntaxes: 'Dim x = y' or 'Dim x As New ...'. This rule allows you to require explicit variable initialization in VB.NET.
'$PROBHIDE NO_INITIALIZER
Initializer missing for variable
A variable declaration does not contain an initializer. The default value for the variable will be zero or Nothing. A value of Nothing can lead to a run-time error when used. You can initialize a variable by either of the following syntaxes: 'Dim x = y' or 'Dim x As New ...'. The latter option is better as it fixes the data type of the variable as well, whereas the previous option does not necessarily do so (depending on VB version and project options). This rule allows you to require explicit variable initialization in VB.NET. Since instance fields of a Structure cannot have initializers, the rule ignores them. As an exception, initializers are required for Shared fields of a Structure.
'$PROBHIDE NO_INITIALIZER
Interface ambiguous
An Interface defines the same name twice. This happens when an Interface inherits two base Interfaces having methods or properties with the same name. Calling the duplicated member is cumbersome. To avoid an ambiguous call, type casting is required. Consider renaming one of the members. Alternatively, rewrite the interface hierarchy. This rule does not apply to method overloading, which is a non-ambiguous way to reuse a name.
'$PROBHIDE INTERFACE_AMBIGUOUS
Interface class contains code
A VB5/VB6 .cls file defines an interface and also contains executable code. The class's interface is being implemented by another class, yet there is code in the class's procedures. It is a mix of interface definition and concrete code. Keeping interface classes and concrete classes separate will help in clarifying the program's structure. An interface class should be pure in that it contains no executable code and that it is not instantiated. See also the rule Interface class instantiated.
'$PROBHIDE INTERFACE_WITH_CODE
Interface class instantiated
A VB5/VB6 .cls file defines an interface that is being implemented by another class, yet the class is also instantiated. Keeping interface classes and concrete classes separate will help in clarifying the program's structure. An interface class should be pure in that it contains no executable code and that it is not instantiated. See also the rule Interface class contains code.
'$PROBHIDE INTERFACE_INST
Interface duplicated
There is a superfluous interface. An Interface inherits the same base Interface twice. Alternatively, a Class or a Structure implements the same base Interface twice. While it causes no real harm, consider clarifying the interface hierarchy so that duplication is not necessary.
'$PROBHIDE INTERFACE_DUPLICATED
Interface members missing
A class, interface or a VB.NET Structure does not define any members to access from other parts of the code. There is no way to execute methods or pass data. This could indicate a design flaw: some code is possibly missing. This rule warns about marker interfaces and interfaces that only define constants. The following definitions count as interface members: Sub, Function, Property, Operator and variable (other than Private). A class may also use the Implements keyword to allow access via an external interface. Inherited members do not count as interface members, nor do DLL procedure declarations. This rule works for both VB.NET and classic VB classes.
'$PROBHIDE NO_INTERFACE
Let statement found
The Let statement is obsolete. Instead of Let x = 1, you can simply write x = 1.
'$PROBHIDE LET
Line too long
A line of code is longer than allowed. A typical limit is 80 characters per line, but you can also use higher limits such as 90 or 100. Long lines are hard to read and understand. Overly long lines don’t fit in the view of your development environment and you need to scroll. What fits in view depends on the monitor and font. On a 1280x1024 screen you can reasonably allow about 80-90 characters in a 10pt Courier New font and maybe 100 characters in an 8pt font. Long lines won’t fit on paper either, and need to be wrapped. While the Print feature of Project Analyzer wraps neatly in a syntax-aware fashion, other programs might not. As an additional bonus, enforcing short lines discourages too deep nesting. How to shorten the lines? Split complex expressions into two or more statements with temporary variables. This will make your code more self-explanatory. Splitting a line with the line continuation character (_) is only a partial answer. It’s like manual word wrapping. A long statement is not any easier to understand even if it covers several lines.
'$PROBHIDE LONG_LINE
Local variable not cleared
A variable or parameter violates the clearing rules currently in effect. This problem indicates that a clearing statement is either missing, not found in the correct location, or that there are too few of them. You can require explicit clearing of object variables, deallocation of dynamic arrays and releasing of Win API resource handles. See the help file for instructions on how to define the rules.
'$PROBHIDE CLEAR
Magic decimal number found
A number with a decimal fraction is not defined as a constant. See Magic number found for a full description.
'$PROBHIDE MAGIC, MAGICDEC
Magic hex number found
A hexadecimal number is not defined as a constant. See Magic number found for a full description. Exception: &H0 is not considered magic.
'$PROBHIDE MAGIC, MAGICHEX
Magic number found
A magic number is a hard-coded numeric literal that is not defined as a constant. Unnamed magic numbers in code are obscure as they do not reveal the meaning of the number. They increase opportunities for subtle errors and make it more difficult to extend or modify the program in the future. Replacing magic numbers with named constants makes programs easier to read, understand and maintain. The same value is often duplicated in different places of the program. Changing such a value is error-prone as each location must be considered separately. In addition, if two distinct magic numbers have the same value, they may be accidentally edited together, even though only one of them should have been changed. The following decimal integers are not considered magic: -1, 0, 1, 2. These numbers are frequently used as initial values, For loop control values and in common mathematical expressions. A hexadecimal or octal zero is not considered magic either.
'$PROBHIDE MAGIC
Magic octal number found
An octal number is not defined as a constant. See Magic number found for a full description. Exception: &O0 is not considered magic.
'$PROBHIDE MAGIC, MAGICOCT
Member scope exceeds container scope
The scope of a member is wider than the scope of the class, module or structure that it belongs to. A member cannot have higher visibility than its container. Although this causes no immediate faults, it may make the code harder to understand and more prone to errors. If the scope of the container is changed later, the members may accidentally have higher visibility than desired. Notice that the scope of the container may be set automatically by VB (if no scope is defined) or it may be further limited by the container of the container. This problem is shown if the member explicitly defines too wide a scope. It is not shown if the member has implicit scope declaration, that is, no scope keyword. As an exception, if a procedure is declared with the Overrides keyword, its scope cannot be defined freely and is thus not subject to this rule. Member scope checking is available for VB.NET only. In VB Classic, scope choices are limited and not likely to cause confusion.
'$PROBHIDE SCOPE, MEMBER_SCOPE
Microsoft.VisualBasic.Compatibility imported
Use objects and methods in the .NET Framework and stay clear of those defined in the Microsoft.VisualBasic.Compatibility namespace. The Microsoft.VisualBasic.Compatibility namespace is used by the tools that upgrade Visual Basic 6.0 code to Visual Basic .NET. It is a bridge to support Visual Basic 6 features that are not directly supported by the .NET implementation of Visual Basic. Microsoft.VisualBasic.Compatibility adds a layer of complexity to your application and introduces some minimal performance costs. The native .NET methods are often faster and offer more options.
'$PROBHIDE COMPATIMPORT
Multiple Return statements found
A procedure contains multiple Return statements. There should be exactly one exit point in a procedure. Multiple exits make the procedure harder to understand. The requirement for multiple exits may indicate too complex a procedure, in which case it should be split. Rewrite the procedure to contain a maximum of one Return statement. This rule applies to VB.NET. Note that this rule does not count Exit Function statements. The rule 'Exit Sub|Function|Property statement found' detects them.
'$PROBHIDE MULTIRETURN
Multiple statements on line
More than one statement was found on one line of code. The code may be difficult to understand. Write only one statement on one line to reach optimal understandability.
'$PROBHIDE MULTISTATEMENT
MustInherit class inherits concrete class
An abstract class (MustInherit) is derived from a concrete class other than System.Object. Abstract classes should be on top of the class hierarchy. The hierarchy should not be unnecessarily deep either.
'$PROBHIDE MUSTINHERIT_CONCRETE
MustInherit class missing MustOverride methods
An abstract class (MustInherit) does not define any abstract methods or properties (MustOverride). Why is the class abstract then, really? An abstract class defines an incomplete implementation. Child classes complete it by implementing the abstract methods. Reconsider the design of this class hierarchy.
'$PROBHIDE NO_MUSTOVERRIDE
MustOverride overrides concrete procedure
A MustOverride abstract procedure overrides a concrete procedure. The class deletes inherited functionality, but does not provide any replacement. Is this correct?
'$PROBHIDE MUSTOVERRIDE_CONCRETE
NameCheck
A name fails Project NameCheck. Fix the name or select another naming standard. For more information about Project NameCheck, see the Pro menu and the help file.
'$PROBHIDE NAMECHECK
Next statement ends multiple For loops
A Next statement with two or more variables was found. The statement ends more than one For loop. For clarity, terminate each For block with its own Next statement. This way the For and Next statements will appear in pairs and make the code easier to understand.
'$PROBHIDE MULTINEXT
Non-instantiatable class has instance members
A class cannot be instantiated, because it has only Private constructors. Only the Shared members of the class can be accessed. The instance members are inaccessible and will remain unused. Reconsider the design of this odd class. One of the constructors could be made accessible, or the instance members could be removed or moved to another class. Alternatively, the class could be instantiated from an inner Class or Structure.
'$PROBHIDE NONINST
NotInheritable expected
A class has only Shared members. It was probably not designed for use as a base class for Inherits. Mark it NotInheritable to make it explicit and to prevent accidental inheritance later. This rule ignores classes that have already been inherited from.
'$PROBHIDE NO_NOTINHERITABLE
Octal number found
An octal number has been found. Octal numbers are expressed in digits 0-7. Since octal numbers are relatively rare, they can cause problems reading the code. To avoid confusion, express numeric values in either decimal or hexadecimal format, which are more widely understood.
'$PROBHIDE OCT
On Error style used
A procedure utilizes On Error statements for error handling. On Error is old syntax in VB.NET. It is better to use the Try..Catch block for error handling. On Error Resume Next also deteriorates the performance of .NET execution. Use Try..End Try without the Catch block to achieve a similar effect without the performance hit.
'$PROBHIDE ONERROR
On Local Error statement found
The 'On Local Error' statement can be rewritten as 'On Error'. The Local keyword is redundant. All error handlers are local to the procedure regardless of the keyword.
'$PROBHIDE ONLOCALERROR
Option Explicit Off
Option Explicit is not set for a file, or it is deliberately set Off. You should always use Option Explicit. It makes VB require explicit variable declaration. This way you avoid using unnecessary implicit Variants (classic VB) or Objects (VB.NET). Even better, you get rid of some nasty errors caused by typing errors and variables with similar names. — The use of Option Explicit will also help in upgrading code to VB.NET. By forcing explicit variable declaration you prevent accidental use of late binding, which is harder to upgrade.
'$PROBHIDE MISSING_EXPLICIT, EXPLICIT_OFF
Option Strict missing
Option Strict is Off for a VB.NET file. There is no Option Strict statement in the file and Option Strict is Off in project settings. Use this rule to require Option Strict On. In VB.NET, Option Strict On enforces type-safe code by allowing only widening data type conversions. It also disables late binding. You can set it On either by writing Option Strict On in the file or changing the Option Strict setting in project options. This rule allows an explicit Option Strict Off statement. Use it as an exception in those files that require it.
'$PROBHIDE MISSING_STRICT
Optional parameter in exposed procedure
The Optional keyword presents a cross-language interoperability problem in VB.NET. Even though Optional parameters are a powerful and useful feature, they are not compatible with all .NET languages. The default value will be ignored and callers are required to pass all parameters. Therefore, Optional parameters should not be used with exposed procedures. For best interoperability, consider replacing Optional parameters with Overloads or several versions of the same procedure. You may also consider a ParamArray, even though this is not always the best choice.
'$PROBHIDE OPTIONAL_EXPOSED
Optional parameter missing default value
Optional parameters should declare an explicit default value so that users will know what to expect when omitting the parameter. If you upgrade to VB.NET, the migration wizard will add a default value. The default for Variant parameters will be Nothing, not Missing, which can make your code behave differently.
'$PROBHIDE NO_DEFAULT
Parameter not cleared
A variable or parameter violates the clearing rules currently in effect. This problem indicates that a clearing statement is either missing, not found in the correct location, or that there are too few of them. You can require explicit clearing of object variables, deallocation of dynamic arrays and releasing of Win API resource handles. See the help file for instructions on how to define the rules.
'$PROBHIDE CLEAR
Parameter with generic type
A parameter is declared as a generic type. While this is completely legal, it may lead to slow and error-prone code. VB may have to use late binding because it doesn't know what kind of object to expect. In late binding, calls to the object's members are slower and may result in a run-time error if the member doesn't exist. If you know what kind of an object the variable will contain, declare it as that type. This is especially important if you plan to migrate existing VB 3-6 code to VB.NET. The .NET upgrade wizard cannot successfully convert all late-bound calls, resulting in manual work and errors.
'$PROBHIDE GENERIC
Parent class inherited only once
A parent class has only one immediate child class. The inheritance hierarchy seems unnecessarily deep. In general, a parent class should be used to derive two or more child classes, while not creating instantiations of the parent. Since this parentclass has just one child, it’s like an extra layer of inheritance. The hierarchy is not as simple as it could be. Consider joining the parent with the child. Determine if the parent class was designed to prepare for future expansion of the class tree. If so, add the missing child class. This rule applies to VB.NET classes only and it ignores Interfaces.
'$PROBHIDE INHERIT_ONCE
Parent class instantiated
An instance of a .NET parent (base) class is created. Keeping parent classes abstract and instantiating only leaf classes will make your class inheritance tree more clear. See also the rule Parent class requires MustInherit.
'$PROBHIDE PARENT_INST
Parent class requires MustInherit
Add MustInherit to all your .NET parent (base) classes to prevent accidental instantiation. Keeping parent classes abstract and instantiating only leaf classes will make your class inheritance tree more clear. See also the rule Parent class instantiated.
'$PROBHIDE NO_MUSTINHERIT
Pass ByRef
This rule is intended for manual review and does not necessarily indicate a problem. A parameter is being passed by reference in a procedure call. The value of the parameter may change during the call. Verify that a change is really expected by the caller. If the change is unexpected, it may cause an error in the caller or later in the program. — Use of this rule: Detect potentially unexpected changes to data. Review all call locations to find potential problems. This rule only reports ByRef passing where the value may change; if the value cannot change, this rule doesn't fire.
'$PROBHIDE PASS_BYREF
Possibly commented-out code
The line(s) may contain commented-out code. Removed code that has been left as a comment may be considered junk. It may distract developers and cause confusion about its significance. It's possibly a bad or otherwise outdated piece of code. Consider removing commented-out code to clean up your project. Project Analyzer uses heuristic rules to search for comments that resemble the actual code in the project. The rules are not foolproof, though, and a certain deal of false alarms are to be expected. In order to mark a line as being commented out on purpose, you can prefix it with a dollar: '$If fail Then End. The dollar will make the line look like non-code to Project Analyzer, thus excluding it from the check.
'$PROBHIDE COMMENTOUT
Possibly orphaned event handler
A confusing Sub has been found. It looks like it may have originally been an event handler. It no longer handles any events, though. Check to see if the Sub should trigger as a response to some existing event or if it is obsolete. If it is a useful Sub, consider renaming it to show it is not an event handler. This review rule is heuristic and cannot tell for sure if a Sub actually was an event handler. In classic VB, this rule compares each Sub’s name against a list of well-known event names. In addition, it considers all Event signatures currently analyzed, including those found in COM files, to determine if a Sub looks like an event handler. In VB.NET this rule looks for Subs with event parameters (ByVal sender As System.Object, ByVal e As System.EventArgs).
'$PROBHIDE ORPHAN
Private constructor expected
A .NET class that has only Shared members should define a Private Sub New() to prevent instantiation. There is no value in creating an instance of a class that contains only Shared members. To prevent such extraneous instantiation, ensure that the class has a single, no-argument, private constructor and no other constructors. This rule applies to .NET classes having only Shared procedures and variables. Sub New and Finalize are not taken as procedures.
'$PROBHIDE CTOR
Protected constructor expected
Constructors of an abstract MustInherit class in .NET can only be called from an instantiating subclass. Marking all constructors Protected helps indicate this. Having no constructors in an abstract class is also a viable alternative. This rule ignores Shared constructors.
'$PROBHIDE CTOR
Protected found in NotInheritable class
The use of a Protected or Protected Friend scope for a member of a NotInheritable class makes no sense as there cannot be any subclasses. Rewrite Protected as Private and Protected Friend as Friend. As an exception, Protected and Protected Friend may be required in an Overrides declaration.
'$PROBHIDE PROTECTED
ReadOnly variable expected
A variable is assigned a value in its initializer or a constructor, but nowhere else. Declare the variable as ReadOnly to make it explicit that the value does not change. This prevents accidental writes to the variable. Note that ReadOnly does not provide 100% security in terms of preventing malicious programs from changing the value. ReadOnly can be added to non-local variables in VB.NET.
'$PROBHIDE NO_READONLY
ReDim without Dim
A ReDim statement allocates a local array without a prior Dim declaration. It is equivalent to using undeclared local variables without Option Explicit. An exceptional statement in classic VB, ReDim is not controlled by Option Explicit. There is a risk of maintenance errors. If an array with the same name is later Dim’d outside this procedure, the ReDim will erase and reallocate that array, which is most probably not wanted. Fix the problem by adding a local declaration with syntax Dim() arrayname As datatype above the ReDim line. This will protect you from an accidental change to a non-local array. Pay attention to declaring the correct datatype to preserve memory. This rule applies to classic VB only.
'$PROBHIDE REDIM
Rem comment found
The Rem comment syntax is obsolete. In modern code, comments are marked with the single quote character (').
'$PROBHIDE REM
Return statement found
A Return statement causes an immediate jump out of a procedure in VB.NET. It potentially makes the procedure have several exit points. Procedures should have only one exit point at the end. — There is a case where VB requires a premature Return. This is when you need to quit a procedure immediately before an On Error Goto xxx type error hander. Another case where Return must be used is in an Operator (VB 2005 and later). Project Analyzer allows these uses. This rule is available for VB.NET.
'$PROBHIDE RETURN
Rewrite Sub as Function
A Sub returns a value in an 'out' parameter. You should rewrite it as a Function for clarity. — A Sub with an 'out' parameter may be useful as an optimization. ByRef may avoid an expensive copy of the argument, whereas a function return value is always a copy. This optimization is related to String parameters and .NET Structures.
'$PROBHIDE SUB2FUNC
Scope declaration missing
A part of your program does not have a defined scope. Instead, it is using a default scope as given by VB. VB's default rules are somewhat complicated and may lead to a scope that is too wide or too narrow. With a narrow scope, you can encapsulate functionality and data. With a large scope, you give access to this part of your program from other parts. Determine which scope is appropriate and declare it explicitly. The current default scope is given. This problem is not reported for VB 3.0, which has a limited scope declaration syntax.
'$PROBHIDE NO_SCOPE, SCOPE
Shadows keyword found
The Shadows keyword in VB.NET allows a child class to hide members of its ancestor classes. Shadowing is not recommended as it makes programs harder to understand. It may not be clear to a developer that there are two different things with the same name. See also the rule Child reuses ancestor member name.
'$PROBHIDE SHADOWS
Shared constructor decreases performance
Having a Shared Sub New makes the program run slower. Even though the shared constructor executes only once, its execution is checked every time a Shared member is accessed or when an instance of the type is created. There is also the problem that you have no control over when the shared constructor really runs. It is better to declare Shared variables with an initializer such as Shared myvar = 7. This guarantees the variable will have the value without overhead, whatever happens in your program. Note that a Sub New in a Module also counts as a shared constructor.
'$PROBHIDE SHARED_CTOR
Shared expected
A Sub, Function or Property does not access any instance variables or procedures. It can be declared as Shared. In addition to determining missing Shared keywords, this rule helps you spot procedures that do not access instance variables even when they should. After adding the Shared keyword to some procedures, re-analyze the program to see if any callers of the new Shared procedures should also be Shared.
'$PROBHIDE NO_SHARED
Shared-only class instantiated
A class with only Shared members is being instantiated. There is no need to create an instance of this class. You can access the Shared members through the class name as a qualifier. Ideally, you should declare a Private Sub New constructor for the Shared-only class to prevent accidental instantiation.
'$PROBHIDE SHARED_INST
Short name
A name is too short and not likely to be descriptive. The name can belong to a control, procedure, variable, constant, Type or Enum—just about anything. Names should be descriptive to keep the code easier to understand. You can the limit the length by yourself. Project Analyzer reports names that are equal to or shorter than your limit. You can optionally allow single-character local variables (i, j, k...) used as For index variables. This rule allows numeric x and y as parameters and local variables, as these names are frequently used for coordinates, but only when they exist as a pair, declared next to each other. This rule allows the following names in VB.NET: e As EventArgs and Catch ex [As Exception].
'$PROBHIDE SHORT_NAME
Single-line If..Then statement found
An If..Then[..Else] structure was found in its single-line form. The code may be difficult to understand. Use the If..Then, [Else] and End If statements on separate lines to make the code more readable.
'$PROBHIDE SINGLE_LINE_IF
SuppressFinalize missing
A method implementing IDispose.Dispose should call GC.SuppressFinalize(Me). The Dispose method should make this call to prevent the Finalize destructor from getting executed by the garbage collection process. If the Dispose method frees all allocated resources, it is unnecessary for the GC to call Finalize to free them again. By calling GC.SuppressFinalize(Me) you make the garbage collection run more efficiently. This rule applies to .NET classes implementing the IDispose interface and having a Finalize destructor.
'$PROBHIDE NO_SUPPRESSFINALIZE
Switch function found
The Switch function is considered bad programming style because of functionality, optimization and readability issues. All expressions in Switch are always executed, resulting in longer execution time and possible unwanted side-effects. May return unwanted Null. Use Select Case or If..End If instead.
'$PROBHIDE SWITCH
Too many parameters
A procedure has a lot of parameters. The more parameters you have, the more difficult the procedure is to use. Consider dividing the procedure. Target at a maximum of 5 parameters.
'$PROBHIDE PARAMS
Too many uncommented lines
Several code lines were found without any comments in them. Add enough comments to make the code easier to understand. This rule finds consequtive uncommented lines. You can set the 'too many' limit to your taste. The rule counts the lines between comments. Empty lines are skipped. Lines continued with the line continuation syntax ' _' count as one line. The lines are counted for each procedure individually so that small uncommented procedures will not trigger an error even if they exceed the limit together. This rule is useful for finding long uncommented blocks inside procedures that have some comments, but not enough. It differs from the 'Uncommented code' rule in that this one reports any consequtive lines without comments, while the 'Uncommented code' rule targets entire procedures with zero comments.
'$PROBHIDE NO_COMMENT
Trailing comment found
An endline comment has been found after code. Comments should be written as the only thing on a line (full-line comments). As the space to the right of a line is limited, endline comments tend to be cryptic. There simply isn’t enough space to write a good comment. It’s better to write a descriptive full-line comment, on one or more lines, before the appropriate block of code. Trying to shortly comment each line as you go does not necessarily tell what the code is really intended to do. In addition, endline comments should look aligned and not wavy. Aligning them takes time, especially when the code is later changed. One should spend more time writing new comments, not adjusting old ones.
'$PROBHIDE TRAILING_COMMENT
Type inference used
A local variable has no explicit datatype definition. The compiler infers its datatype from the variable’s initialization value. A feature introduced in VB2008, this happens with the setting Option Infer On. Since a variable may be intended to contain datatypes other than its initial value, each variable should preferably be declared with an explicit datatype. There is also a maintenance issue to consider. The inferred datatype may depend on a function call or a reference to other data. If the datatype of that reference is later changed, the change is propagated to this variable too. While this may be desirable, it may also introduce a hidden bug where the variable is then used. In other words, the variable’s datatype may be subject to an unintentional change. Adding an As datatype clause makes the datatype explicit and prevents unwanted changes.
'$PROBHIDE INFER
Uncommented procedure
A procedure is not commented. It may be hard to understand what the procedure does, what parameters it takes and what the return value is. The internal functioning of the procedure isn't commented either. Use this rule to require at least one comment in each procedure. — You can ignore short uncommented procedures with a maximum of x lines of code. Write x in the 'Ignore when' textbox in Problem Options. Lines Sub/Function and End Sub/Function are counted as code, making an empty procedure have 2 lines. Leave the box empty if you don't want to have a limit.
'$PROBHIDE NO_COMMENT
Undefined compiler constant
A compiler constant was found, but no definition for it. While this is perfectly legal, it could also indicate a problem, such as a mistyped condition or accidental removal of the definition.
'$PROBHIDE COMPCONST, UNDEF_COMPCONST
Variable clearing violation
A variable or parameter violates the clearing rules currently in effect. This problem indicates that a clearing statement is either missing, not found in the correct location, or that there are too few of them. You can require explicit clearing of object variables, deallocation of dynamic arrays and releasing of Win API resource handles. See the help file for instructions on how to define the rules.
'$PROBHIDE CLEAR
Variable declared in code
A Dim or Static statement is found among procedure code. You can require that all local variables be declared in their own block at the start of a procedure. The benefit of this style is that all declarations can be found quickly in one place. Note that the use of this rule disallows block-scope variables in VB.NET.
'$PROBHIDE VAR_DECL_IN_CODE, DECL_IN_CODE
Variable missing type declaration
A variable does not have a defined data type. By default, the type is Variant in classic VB and Object in VB.NET. These generic types need more memory than other data types. Decide what type you need and write it to the declaration. As an additional bonus, upgrading to VB.NET will be easier if you use explicit data types. In VB.NET, you can set Option Strict On to require explicit data types.
'$PROBHIDE NO_TYPE
Variable with generic type
A variable is declared as a generic type. While this is completely legal, it may lead to slow and error-prone code. VB may have to use late binding because it doesn't know what kind of object to expect. In late binding, calls to the object's members are slower and may result in a run-time error if the member doesn't exist. If you know what kind of an object the variable will contain, declare it as that type. This is especially important if you plan to migrate existing VB 3-6 code to VB.NET. The .NET upgrade wizard cannot successfully convert all late-bound calls, resulting in manual work and errors.
'$PROBHIDE GENERIC
Variable/parameter/constant with type character
A variable, procedure parameter or constant is declared with one of the old-style $#%!&@^ type characters. Instead of Year%, use Year As Integer, etc. Note: The VB.NET Nullable character ? is not considered to be problematic.
'$PROBHIDE TYPE_CHAR
While loop found
The While loop is outdated. Do...Loop provides a more structured and flexible way to perform looping. In VB 3-6, the syntax to avoid is While..Wend. In VB.NET, it is While..End While.
'$PROBHIDE WHILE_WEND
Write-only property found
A property is either missing a Get accessor or it is explicitly declared WriteOnly. Alternatively, the property is partially write-only in that the Get accessor has a smaller scope than the corresponding Set or Let. In the latter case the write-only and read/write status depends on scope. A write-only property is not logical. There is no security in letting one write a value but not read it back. Where write-only access is desired, it’s better to use a method such as SetValue. This makes the design explicit.
'$PROBHIDE WRITEONLY

VB.NET Compatibility

Add-in model changed in VB.NET
This is a VB add-in project. The add-in programming model has changed in VB.NET, requiring major migration work.
ADO required for data binding in VB.NET
Data controls can be bound only to ADO, not to RDO or DAO. Upgrade the RDO and DAO data binding to ADO before upgrading your project to VB.NET. See vb6 help or MSDN for topic 'RDO to ADO' or 'DAO to ADO'.
Array must start at 0 in VB.NET
VB.NET requires arrays be declared with a lower bound of zero. Non-zero-based arrays will be upgraded to be zero-based. A replacement format is available, allowing non-zero lower bounds, but it is slower than native arrays, and limited when passing arrays as parameter to functions. Use of zero-based arrays is recommended. Arrays with negative bounds are especially problematic, as all .NET arrays are in the range 0..ubound. Arrays with a negative upper bound are not upgraded at all.
As Any not allowed in VB.NET
As Any will not be allowed in API declarations. Get prepared by adding a separate API declaration for all parameter types you may need.
As New doesn't auto-instantiate if object released in VB.NET
VB.NET does not automatically re-instatiate an object that has been explicitly released. This problem affects you only if you set this variable to Nothing and try to use it later without instantiating a new object first.
As New unsupported for arrays in VB.NET
Arrays cannot be declared with 'As New'. You will need to remove the New keyword and initialize the array before use.
ByRef property params unsupported by VB.NET
VB.NET does not support ByRef property parameters, because they can lead to unexpected behavior. All declarations of parameterized properties must specify ByVal for the parameters. The .NET upgrade wizard turns all ByRef parameters into ByVal without warning.
ByVal/ByRef not allowed in API calls in VB.NET
ByVal or ByRef will not be available for calling the API. Review your API declaration to find out if you can replace it by a better declaration where ByVal/ByRef is not needed to call.
Class Instancing changes in VB.NET
There is no direct equivalent for the following Instancing property values: 3=SingleUse, 4=GlobalSingleUse, 6=GlobalMultiUse. The upgrade wizard sets the access level to Public. You can control the way that an object can be created by setting the access level of the constructor (Sub New). The unavailability of the Instancing value may require changes in the way the class is being used.
COM method not callable from VB.NET
VB.NET projects can call COM class methods but not COM module methods. You may be able use the .NET framework classes to achieve the same functionality or you may need to keep your code in VB6. This problem detection rule requires that the corresponding COM file has been analyzed.
COM+/MTS not upgradable to VB.NET
The project refers COMSVCS.DLL (COM+ Services Type Library). Existing code will need to be upgraded to use .NET transaction processing.
Control unsupported by VB.NET
A control type is not available in VB.NET. Image is auto-replaced by PictureBox. OLE Containers can be manually replaced by a browser control. MSComCtl2.UpDown won't upgrade but can be manually replaced by DomainUpDown or NumericUpDown controls.
DDE unsupported by VB.NET
DDE is not available in VB.NET. You will have to use other kind of inter-process communication.
Diagonal line unsupported by VB.NET
VB.NET does not support diagonal Line controls. After migration, you will have to override the OnPaint event to draw the line. It won't pay off to do it before migration, because the drawing statements change too.
DoEvents() returns no value in VB.NET
DoEvents() does not return the number of open forms, or any other value. There will be no replacement function. The DoEvents statement will remain.
Drag-and-drop requires rewrite for VB.NET
VB.NET supports drag-and-drop functionality, but the object model is quite different. Drag-and-drop code must be rewritten.
Event behavior changes in VB.NET
The behavior of this event will change somewhat in VB.NET. You will have to review and test the event code after migration. Affected events: ComboBox_Change, ComboBox_Scroll, ListBox_Scroll, Form_Activate, Form_DeActivate, Form_Terminate, Form_Unload, Class_Terminate. This problem is not reported for empty event handlers.
Event log model differs in VB.NET
The event log model is different in VB.NET and manual work is needed. Affected code: LogMode, LogPath, StartLogging, StartMode.
Initialized arrays in UDTs unsupported by VB.NET
Fields in user-defined types cannot be initialized arrays in VB.NET. Only arrays declared without dimension - MyArray() - are allowed. You must add code to ReDim array fields before use.
MDIForm event unsupported in VB.NET
The following events are unavailable: MDIForm_Click, MDIForm_MouseDown, MDIForm_MouseMove, MDIForm_MouseUp. There is no replacement. This problem is not reported for empty event handlers.
Member cannot be default in VB.NET
Variables, Subs and Functions are not allowed as default members of objects in VB.NET. The VB.NET upgrade wizard adds the member name automatically if you have typed your object variables and thus used early binding. If you use late binding (As Object, As Variant), you will have to add the name manually. You may prepare for migration by marking this member as non-default and fixing all references by hand.
Module not upgradable to VB.NET
This module type is not available in VB.NET. DHTML pages: stay in VB6. DataReports: unable to migrate. If your application depends heavily on property pages, it should be left in Visual Basic 6.0. ActiveX documents should either be rewritten as UserControls or left in VB6.
Old VB project not upgradable to VB.NET
This project was made in VB version 3 or 4. VB.NET will not load it. You will need to upgrade to VB6 first.
OLE Automation unavailable in VB.NET
The OLE Automation features are unavailable in VB.NET. You will need to use another kind of inter-process communication. Affected code: OleRequestPendingMsgText, OleRequestPendingMsgTitle, OleRequestPendingTimeout, OleServerBusyMsgText, OleServerBusyMsgTitle, OleServerBusyRaiseError, OleServerBusyTimeout.
ParamArray is ByVal in VB.NET
ParamArrays are ByRef in classic VB, but they will be converted to ByVal for VB.NET. Your code seems to use ParamArray as an 'out' parameter to return values to callers. This is not possible in VB.NET. You should return 'out' values in the function return value (recommended) or in a regular ByRef array parameter (worse alternative). This problem rule does not fire for ParamArrays that do not return an 'out' value.
Parameterless default properties unsupported in VB.NET
A property with no parameters can't be the default member of an object in VB.NET. This means that you can no longer omit the property name to access the property. VB.NET upgrade wizard adds the property name automatically if you have typed your object variables and thus used early binding. If you use late binding (As Object, As Variant), you will have to add the name manually. You may prepare for migration by marking this property as non-default and fixing all references by hand.
Property mixes scopes
Property accessors have different levels of accessibility. This causes a problem when upgrading to VB.NET, because the upgrade wizard will convert all accessors to the widest scope, exposing previously hidden code. VB 2002 and 2003 require property accessors to have the same scope. VB 2005 and VB 2008 support different scopes for Get and Set, but the upgrade wizards in VB 2005 and VB 2008 do not: they still upgrade to the widest scope.
Property passed ByRef
A property is being passed to a ByRef parameter in a procedure call. In VB6, the changes to the parameter are not updated to the property. Thus, only Property Get executes. In VB.NET, updates are copied to the property when the call exits (copy in/copy out semantics). Thus, both Property Get and Set execute. This may lead to an unexpected change in the property value and a bug that is hard to detect. You should enclose the property in parentheses, which enforces pass ByVal instead of ByRef. Alternatively you can change the formal parameter to ByVal (if that preserves the logic during other calls to the same procedure).
Resource file requires work in VB.NET
The .NET resource file format is .resX. Code that loads resources (LoadResString, LoadResData, LoadResPicture) is converted automatically by the upgrade wizard, but the resource file itself is not.
ScaleMode must be vbTwips for VB.NET
To make sure your forms upgrade correctly, always use ScaleMode=vbTwips. VB.NET transforms your forms coordinates from twips to pixels. If ScaleMode is non-twips, you'll have sizing issues.
Setting .Interval does not enable/disable timer in VB.NET
Setting Timer.Interval=0 does not disable the Timer (in fact, the interval will become 1 msec). You will have to use Timer.Enabled=False. Setting Timer.Interval>0 does not enable it either, you will need to call Timer.Enabled=True.
String byte functions unavailable in VB.NET
The byte versions of string handling functions are not available in VB.NET. Encoding and decoding functions in the System.Text namespace replace this functionality. The upgrade wizard does not automatically convert the byte functions. You may want to consider replacing them with the Unicode (wide) functions before upgrading. Affected functions: AscB, LenB, InStrB, ChrB, LeftB, MidB, RightB, InputB.
Sub Main not executed in VB.NET
The startup object is Sub Main. In VB.NET, Sub Main is not executed at all in this kind of a project.
Sub Main: VB.NET program exits at End Sub
The startup object is Sub Main. Currently, the program exits when all objects are destroyed. In VB.NET, the program exits at end of Sub Main. Fix: Set a form to be the startup object. Call Sub Main from Form_Load event.
TTF/OTF fonts required by VB.NET
If your application uses other fonts than TTF or OTF, these fonts will be changed to the system's default font, and all formatting (size, bold, italic, underline) will be lost. This applies to the default VB6 font MS Sans Serif. You might want to change all fonts before migration.
Type unsupported by VB.NET
Fixed-length string and Currency are not available as data types in VB.NET. VB.NET will auto-convert Currency to Decimal, which has more precision. VB.NET has a replacement for fixed-length strings, but it is slow and limited. Arrays of fixed length string are not allowed at all. It is recommended to change all fixed-length strings to variable-length strings.
Unavailable in VB.NET
The function or constant, or a direct replacement, is not available in VB.NET. Affected code: CVErr, GoSub, Return, vbDataObject, vbUnicode, vbFromUnicode, vbDefaultButton4, vbDatabaseCompare, VarPtr, StrPtr, ObjPtr, VarPtrArray, VarPtrStringArray. In addition, LSet will have a replacement for strings, but not for UDTs. IsEmpty will be upgraded to IsNothing, which can cause a subtle bug because IsEmpty(vbNullString)=False will be upgraded to IsNothing(Nothing)=True.
Underscore _names not hidden in VB.NET
Underscore as the leftmost character does not mean 'hidden'. There is a new syntax for marking items as hidden in VB.NET IDE.
VB5 project may not upgrade to VB.NET
This project was made in VB5. You may be able to load it in VB.NET, but expect trouble. You might wish to upgrade it to VB6 first.
WebClasses upgrade to ASP.NET
You can upgrade Visual Basic 6.0 WebClass projects to ASP.NET Web Applications.

3. Comment directives

ACCURACY
Verify accuracy
ASC
Constant available
Unicode function is faster
ASNEW
Object variable declared As New
ASSIGNMENT_TO_SELF
Assignment to self
BASEADDR
Base address unoptimal
BUTTONS
Cancel button missing
Default button missing
BYREF_READONLY
ByRef parameter read only, consider ByVal
BYREF_RETVAL
ByRef parameter returns a value
BYVAL_WRITTEN
ByVal parameter written to
CALL
Call statement found
CALLED_DIRECTLY
Event handler called directly
Implementation called directly
CASE_ELSE
Case Else missing
CASE_MISSING
Case branch(es) missing for Enum
CASE_OVERLAP
Case overlap
CASE_USELESS
Case useless
CC
Cyclomatic complexity exceeds limit
CHOOSE
Choose function found
CHR
Constant available
Unicode function is faster
CLEAR
Local variable not cleared
Parameter not cleared
Variable clearing violation
COMMENTOUT
Possibly commented-out code
COMPATIMPORT
Microsoft.VisualBasic.Compatibility imported
COMPCONST
Dead compiler constant
Undefined compiler constant
COMPOUND
Use compound operator
COND
Condition always True or False
Condition always True or False at run-time
CONST_DECL_IN_CODE
Constant declared in code
CREATEOBJECT
CreateObject found
CTOR
Constructor missing
Private constructor expected
Protected constructor expected
CTRLDIS
Control not enabled
CTRLINV
Control not visible
CTRLOUT
Control outside visible area
CTYPE
CType slower than DirectCast
CVDATE
CVDate found, use CDate
CYCL_COMPLEXITY
Cyclomatic complexity exceeds limit
DATALESS
Dataless class found
DATAONLY
Data-only class found
DCOND
Conditionals nested too deeply
DEAD_CLASS
Dead class
DEAD_COMPCONST
Dead compiler constant
DEAD_CONST
Dead constant
DEAD_ENUM
Dead enum
DEAD_ENUM_CONST
Dead enum constant
DEAD_FIELD
Dead type field
DEAD_INTERFACE
Dead interface
Implemented interface not used
DEAD_LABEL
Dead line label or number
DEAD_LINENUM
Dead line label or number
DEAD_MODULE
Dead module
DEAD_PARAM
ByVal parameter not read
Dead parameter
DEAD_PROC
Dead procedure/declaration/event
Dead procedure/declaration/event (callers all dead)
DEAD_READERS
Type field readers all dead
Variable readers all dead
DEAD_RETVAL
Dead return value
DEAD_STRUCTURE
Dead Structure
DEAD_USERS
Constant users all dead
Enum constant users all dead
Enum users all dead
Type field users all dead
Type users all dead
Variable users all dead
DEAD_VAR
Dead variable
DEAD_WRITERS
Type field writers all dead
Variable writers all dead
DECL_IN_CODE
Constant declared in code
Variable declared in code
DEFAULT_NAME
Default name
DEFTYPE
DefType statement found
DELAYED_ERROR_HANDLING
Delayed error handling
DLOOP
Loops nested too deeply
EMPTY
Empty procedure/module
EMPTY_BLOCK
Empty block
END
End statement found
ENUM_CONST_EXPECTED
Enum constant expected
ENUM_DUPLICATE
Enum with duplicate value
ENUM_ZERO
Enum missing zero value
EXCESS_SCOPE
Excess scope
EXCLUDED
Conditional block excluded
EXIT
Exit statement found
Exit Sub|Function|Property found
EXPLICIT_OFF
Option Explicit Off
FIELD_NOT_READ
Type field not read, writers all dead
Type field written, not read
FIELD_NOT_WRITTEN
Type field not written, readers all dead
Type field read, not written
FIXED_FILENUM
Fixed file number found
FIXEDLEN
Fixed-length string used
FORCOND
For conditions illogical
FORVAR
For index variable not local
GENERIC
Parameter with generic type
Variable with generic type
GLOBAL
Global found, use Public
GOSUB
GoSub statement found
GOTO
GoTo statement found
HANDLER_PRIVATE
Event handler should be Private
HOTKEY_CONFLICT
Hotkey conflict
HOTKEYS
Hotkey conflict
Hotkey missing
IC1
Informat'l complexity exceeds limit
IFIO
Informat'l fan-in x fan-out exceeds limit
IIF
IIf function found
IMPL_PRIVATE
Implementation should be Private
IMPLICIT_ENUM
Enum has implicit member value(s)
IMPLICIT_VAR
Implicit variable
IN_INTERFACE
Class/Structure nested inside Interface
INF_COMPLEXITY
Informat'l complexity exceeds limit
INF_FANINOUT
Informat'l fan-in x fan-out exceeds limit
INFER
Type inference used
INHERIT_ONCE
Parent class inherited only once
INHERITANCE_LIMITED
Inheritance limited
INTERFACE_AMBIGUOUS
Interface ambiguous
INTERFACE_DUPLICATED
Interface duplicated
INTERFACE_INST
Interface class instantiated
INTERFACE_WITH_CODE
Interface class contains code
LET
Let statement found
LIKE_INTERFACE
Class looks like Interface
LOC
Lines of code exceed file limit
Lines of code exceed proc. limit
LONG_LINE
Line too long
LOOP_FOREVER
Loop runs forever
LOOP_ONCE
Loop runs only once
MAGIC
Magic decimal number found
Magic hex number found
Magic number found
Magic octal number found
MAGICDEC
Magic decimal number found
MAGICHEX
Magic hex number found
MAGICOCT
Magic octal number found
MANYMOD
File with several classes or modules
MEMBER_SCOPE
Member scope exceeds container scope
MISSING_EXPLICIT
Option Explicit Off
MISSING_STRICT
Option Strict missing
MULTIDIM
Multi-dimensional array found
MULTINEXT
Next statement ends multiple For loops
MULTIRETURN
Multiple Return statements found
MULTISTATEMENT
Multiple statements on line
MUSTINHERIT_CONCRETE
MustInherit class inherits concrete class
MUSTOVERRIDE_CONCRETE
MustOverride overrides concrete procedure
NAMECHECK
NameCheck
NO_BYVAL
ByVal/ByRef missing
NO_CLICK
Click event missing
NO_COMMENT
Too many uncommented lines
Uncommented procedure
NO_DEFAULT
Optional parameter missing default value
NO_DOLLAR
Dollar would increase performance
NO_ERROR
Error event missing
NO_ERROR_HANDLER
Delayed error handling
Error handler missing
NO_EVENTS
Events not handled
NO_FINALIZE
Finalize found
Finalize missing
NO_HELPCONTEXTID
Form missing HelpContextID
NO_HOTKEY
Hotkey missing
NO_ICON
Form missing Icon
NO_IDISPOSABLE
IDisposable not implemented
NO_INITIALIZER
Initializer missing for local variable
Initializer missing for variable
NO_INTERFACE
Interface members missing
NO_MUSTINHERIT
Parent class requires MustInherit
NO_MUSTOVERRIDE
MustInherit class missing MustOverride methods
NO_MYBASE_FINALIZE
Finalize missing MyBase.Finalize
NO_NOTINHERITABLE
NotInheritable expected
NO_READONLY
ReadOnly variable expected
NO_RESIZE
Resizable Form missing Form_Resize
NO_SCOPE
Scope declaration missing
NO_SHARED
Shared expected
NO_SUPPRESSFINALIZE
SuppressFinalize missing
NO_TIMER
Timer event missing
NO_TYPE
Constant missing type declaration
Function missing type declaration
Variable missing type declaration
NONINST
Non-instantiatable class has instance members
NOT_IMPLEMENTED
Interface not implemented
NOT_IN_LIB
Procedure not found in library
NOT_INHERITED
Class not inherited
NOT_INSTANTIATED
Class not instantiated
NOT_RAISED
Event not raised
NOT_READ
ByVal parameter not read
Type field not read, writers all dead
Type field written, not read
Variable not read, writers all dead
Variable written, not read
NOT_WRITTEN
Type field not written, readers all dead
Type field read, not written
Variable not written, readers all dead
Variable read, not written
NULLSTR
Len/LenB is faster than = "" or <> ""
Literal "" found
OCT
Octal number found
ONERROR
On Error style used
ONLOCALERROR
On Local Error statement found
OPTIONAL_EXPOSED
Optional parameter in exposed procedure
OPTIONAL_NOVAL
Optional parameter never passed a value
ORDINAL
Declare contains ordinal number
ORPHAN
Possibly orphaned event handler
PARAM_NOT_READ
ByVal parameter not read
PARAMS
Too many parameters
PARENT_INST
Parent class instantiated
PASS_BYREF
Pass ByRef
PATH
Hard-coded path found
PICTUREBOX
Consider using Image control
POW
Slow ^ operator found
PROTECTED
Protected found in NotInheritable class
PUBVAR
Encapsulate non-private variable as property
Global variable found
RAISEEVENT_CTOR
RaiseEvent fails via constructor
RANDOM
Use Binary instead of Random file access
REACH
Unreachable code found
READBW
Object read before set
Object read before set (along some path)
Variable read before written
Variable read before written (along some path)
RECURSION
Cyclic recursion found
REDIM
ReDim without Dim
REM
Rem comment found
RETURN
Return statement found
RETVAL
Dead return value
Return value discarded
Return value not set
RETVAL_DISCARDED
Return value discarded
RETVAL_NOT_SET
Return value not set
REUSES_NAME
Child reuses ancestor member name
SCOPE
Excess scope
Global found, use Public
Member scope exceeds container scope
Scope declaration missing
SEAL
Seal for less overhead
SHADOWS
Shadows keyword found
SHARED_CTOR
Shared constructor decreases performance
SHARED_INST
Shared-only class instantiated
SHORT_NAME
Short name
SHORTCIRC
Consider short-circuited logic
SINGLE_LINE_IF
Single-line If..Then statement found
STEP1
For with Step 1 found
STOP
Stop statement found
SUB2FUNC
Rewrite Sub as Function
SWITCH
Switch function found
TABORDER
Possibly twisted tab order
TEXTCOMP
Text comparison used
TIMER_INTERVAL
Timer interval below 55 ms
TRAILING_COMMENT
Trailing comment found
TYPE_CHAR
Function/Property with type character
Variable/parameter/constant with type character
UNDEF_COMPCONST
Undefined compiler constant
UNUSED_FILE
Unused file
VALUE_UNUSED
Assigned object not used
Assigned value not used
Parameter value not used
Passed value not used
VAR_DECL_IN_CODE
Variable declared in code
VAR_NOT_READ
Variable not read, writers all dead
Variable written, not read
VAR_NOT_WRITTEN
Variable not written, readers all dead
Variable read, not written
WHILE_WEND
While loop found
WITHEVENTS
WithEvents adds overhead
WRITEONLY
Write-only property found

4. Comment directives, combination types

ALL
All problems
DEAD
Dead code problems
FUNC, FUNCTIONALITY
Functionality problems
LOGIC
Logic flaws
METRICS
Metrics related problems
OPT, OPTIMIZATION
Optimization issues (also includes DEAD)
STYLE
Style problems (also includes METRICS)
VB.NET
VB.NET compatibility rules
CRITICAL
Severity level: Critical
WARN, WARNING
Severity level: Warning
INFO, INFORMATION
Severity level: Information

PROBHIDE

'$PROBHIDE at the end of a problem description indicates which comment directives can be used to hide one or more instances of a particular problem.

See also

Code review rules
Comment directives

© Project Analyzer Help