Files
loongoffice/basic/qa/basic_coverage/test_With.bas
Mike Kaganski ff3791f67a tdf#163219: only create local With variable for function results
The problem is, that having a local variable referring the same value
as the original expression 'foo' is not the same as referencing 'foo'
itself. After 'foo' is re-assigned, the local variable still refers
to the original value, not the new one.

It seems impossible to implement the reference using existing codegen
primitives, to imitate the true reference to 'foo', not to its value.
If we implement it by changing the runtime, the bytecode won't work
identically in older versions; if we introduce a new bytecode, that
would be an incompatible change.

As a workaround, only create the local With variable, when the block
variable is created using some function (as much as known by parser).
I think that there would be cases when this would still not work as
intended: an example is a property implemented using getter function;
the parser would likely treat the property as a variable, and avoid
creation of the local variable; and the getter would be called every
time a dot access will happen (which was the essence of tdf#132064).
However, this seems a better alternative to the bug fixed here.

Change-Id: I50bf679762fd2e73f215a000fa0ab60fd6ae7453
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174564
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
2024-10-07 09:38:38 +02:00

104 lines
3.2 KiB
QBasic

'
' This file is part of the LibreOffice project.
'
' This Source Code Form is subject to the terms of the Mozilla Public
' License, v. 2.0. If a copy of the MPL was not distributed with this
' file, You can obtain one at http://mozilla.org/MPL/2.0/.
'
Option Explicit
Function doUnitTest as String
TestUtil.TestInit
test_with
doUnitTest = TestUtil.GetResult()
End Function
Sub DEV_TST : MsgBox doUnitTesT : End Sub
Type foo
n As Integer
s As String
End Type
Dim get_foo_count As Integer
Function get_foo As foo
get_foo_count = get_foo_count + 1
get_foo = New foo
End Function
Sub with_in_another_procedure
On Local Error GoTo errorHandler
' tdf#162962 "End With" clears the internal variable; it used to fail,
' when several module's procedures used With blocks, using Option Explicit
Dim foo_var As New foo
With foo_var
.n = 6
TestUtil.AssertEqual(.n, 6, ".n")
End With ' Here (or in similar places in other tests) a "Variable Not Defined" error was generated
Exit Sub
errorHandler:
TestUtil.ReportErrorHandler("with_in_another_procedure", Err, Error$, Erl)
End Sub
Sub test_with
On Local Error GoTo errorHandler
Dim fields As String
With get_foo()
.n = 5
.s = "bar"
fields = "n = " & .n & " s = " & .s
End With
' get_foo must be called only once; before the fix, it failed with
' Number of calls to get_foo returned 4, expected 1
TestUtil.AssertEqual(get_foo_count, 1, "Number of calls to get_foo")
' Before the fix, each use of . resulted in creation of a new 'foo' object,
' and previous assignments didn't reflect in the result; it failed with
' Field values returned n = 0 s = , expected n = 5 s = bar
TestUtil.AssertEqual(fields, "n = 5 s = bar", "Field values")
' Make sure that With works with the original object, modifies it, and does not destroy
Dim foo_var As New foo
With foo_var
.n = 6
.s = "baz"
End With
fields = "n = " & foo_var.n & " s = " & foo_var.s
TestUtil.AssertEqual(fields, "n = 6 s = baz", "Field values of foo_var")
' tdf#163219: make sure that assigning the variable in the block works
Set foo_var = Nothing
TestUtil.Assert(foo_var Is Nothing, "foo_var Is Nothing")
With foo_var
foo_var = New foo
.n = 7
.s = "something"
End With
TestUtil.AssertEqual(foo_var.n, 7, "foo_var.n")
TestUtil.AssertEqual(foo_var.s, "something", "foo_var.s")
' tdf#162935: Test an UNO struct - it used to copy into the With variable, not used by ref
Dim uno_struct As New com.sun.star.table.CellRangeAddress
With uno_struct
.Sheet = 1
.StartColumn = 2
.StartRow = 3
.EndColumn = 4
.EndRow = 5
End With
TestUtil.AssertEqual(uno_struct.Sheet, 1, "uno_struct.Sheet")
TestUtil.AssertEqual(uno_struct.StartColumn, 2, "uno_struct.StartColumn")
TestUtil.AssertEqual(uno_struct.StartRow, 3, "uno_struct.StartRow")
TestUtil.AssertEqual(uno_struct.EndColumn, 4, "uno_struct.EndColumn")
TestUtil.AssertEqual(uno_struct.EndRow, 5, "uno_struct.EndRow")
with_in_another_procedure() ' test tdf#162962
Exit Sub
errorHandler:
TestUtil.ReportErrorHandler("test_with", Err, Error$, Erl)
End Sub