Dynamic arrays need to be dimensioned before they can be used.
User defined Types (structs) can include dynamic arrays, and can cause crashes if passed to Win32 functions without first being dimensioned.
So... should this inspection only look at DeclarationType.UserDefinedTypeMember declarations that are arrays never used in a ReDim statement?
_Any_ dynamic array will cause a runtime error 9 (subscript out of range) if it's used before it's dimensioned. This is a very useful inspection, that should default to error level (because it catches a _runtime_ error).
This code would trip the inspection:
Sub foo()
Dim a()
a(1) = 42 'boom
End Sub
This code too:
Type T
B() As Variant 'interestingly, not specifying a type here is a compile error
End Type
Private bar As T
Sub foo()
bar.B(2) = 42 'boom
End Sub
Fix for snippet 1:
Sub foo()
Dim a()
ReDim a(_TODO_)
a(1) = 42 'boom
End Sub
Fix for snippet 2:
Type T
B() As Variant 'interestingly, not specifying a type here is a compile error
End Type
Private bar As T
Sub foo()
ReDim bar.B(_TODO_)
bar.B(2) = 42 'boom
End Sub
Note that both quick-fixes generate compile errors - this is by design, and turns a runtime error into a compile-time validation, which is a major improvement. The _TODO_ token is an illegal identifier, so there can't be any clashes with an existing variable - but the Rubberduck parser shouldn't break over it, since the IDENTIFIER lexer token rule has been relaxed lately and won't blow up over an identifier that starts with an underscore.
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Type TDynamic
a As Byte
b() As Byte
c As Byte
End Type
Sub Mysub()
Dim o As TDynamic
Dim iLength As Long
iLength = Len(o) ' = 5
o.a = 1
o.c = 3
'This line will run (as long as o is not expanded in Locals, regardless of whether Locals is visible)
CopyMemory o, "abcde", Len(o)
'Expanding o in the Locals window, Excel goes BOOM
'This works
Debug.Print o.a ' = 164!
'This works
Debug.Print o.c ' = 3
'Don't hover over o.b
Debug.Print o.b 'Excel goes BOOM
'Stopping the code, or exiting the procedure, Excel goes BOOM
End Sub
Actually, the dynamic member of a type, seems to be a pointer, so while it is possible to ReDim the member, the size of the type doesn't change. That makes it unsafe to use with CopyMemory, regardless of whether you Redim the dynamic array.
Private Type TDynamic
a As Byte
b() As Byte
End Type
Sub Test()
Dim td As TDynamic
td.a = 1
Debug.Print Len(td) '5
ReDim td.b(4)
Debug.Print Len(td) '5
ReDim td.b(400000)
Debug.Print Len(td) '5
End Sub
Stumbled across this, and thought I'd throw this out - ReDim isn't the only way to initialize an array. The inspection would also have to check for array returning functions. I use this paradigm _all the time_:
Dim Foo() As String
Foo = Split(vbNullString)
Not to mention to ubiquitous:
Dim cells() As Variant
cells = Range("A1:C3")
Not to mention the Array function...
Sub TesticlePop()
Dim foo() As Variant
foo = Array(1, 2, 3)
End Sub
Most helpful comment
Stumbled across this, and thought I'd throw this out - ReDim isn't the only way to initialize an array. The inspection would also have to check for array returning functions. I use this paradigm _all the time_:
Not to mention to ubiquitous: