rubberduck-vba / Rubberduck

Every programmer needs a rubberduck. COM add-in for the VBA & VB6 IDE (VBE).
https://rubberduckvba.com
GNU General Public License v3.0
1.92k stars 302 forks source link

"Implicite default member acces" not recognised #5549

Closed Tanarri closed 4 years ago

Tanarri commented 4 years ago

Rubberduck version information Version 2.5.0.5522 OS: Microsoft Windows NT 10.0.18363.0, x64 Host Product: Microsoft Office 2013 x86 Host Version: 15.0.5233.1000 Host Executable: MSACCESS.EXE

Description A implicite default member access to ACEDAO.DLL;DAO.Field.Value is not recognised, when it should be SVNID = Nz(rsWork.Fields.Item("ID"), vbNullString)

To Reproduce Add a new module in Access 2013

Option Compare Database
Option Explicit

Public Sub test()
    Dim SVNID As Long
    Dim rsWork As DAO.Recordset
    Set rsWork = CurrentDb.OpenRecordset("select * from msysobjects", dbOpenDynaset, dbSeeChanges)
        SVNID = rsWork.Fields.Item("ID")
        SVNID = Nz(rsWork.Fields.Item("ID"), vbNullString)
    rsWork.Close
End Sub

Expected behavior On both lines, which read from rsWork should be suggested, that there is a implicit default member access. But only the following line is mentioned SVNID = rsWork.Fields.Item("ID")

Following code line with the "Nz()" is not mentionted, that there is a default member access - but it should. SVNID = Nz(rsWork.Fields.Item("ID"), vbNullString)

Screenshots grafik

MDoerner commented 4 years ago

How is the function Nz defined? More specifically, what is the type of its first parameter? Without that information it is hard to say what is going on.

retailcoder commented 4 years ago

@MDoerner Nz would be loaded from the Access type library, works a bit like ISNULL in T-SQL; per docs it takes a variant first parameter and an optional (unless used in a query) value_if_null argument can be supplied.

MDoerner commented 4 years ago

Ok, based on that information, there is no implicit default member access in Nz(rsWork.Fields.Item("ID"), vbNullString). Since the parameter type is Variant. The function NZ gets the Field object passed as first argument. The access of the default member will then happens inside that function, if at all, which is an implementation detail of that built-in function. So, the inspection works as expected.

retailcoder commented 4 years ago

In other words rs.Work.Fields.Item("ID") returns a Field object, but because the Nz parameter type is Variant, the function happily receives a Variant/Field object reference, and the let-coercion if it happens, happens inside the Nz function and not at the call site when the argument is evaluated.

So while it's perfectly reasonable to presume Nz leverages the late binding afforded by the Variant type of its first parameter, flagging it as an implicit default member access would require baking-in assumptions about non-user code, because it's the Field object that is being passed as an argument, not the value of its default member.