basic/source/runtime/runtime.cxx                  |   10 ++++++-
 sc/qa/extras/testdocuments/ForEachInSelection.ods |binary
 sc/qa/extras/vba-macro-test.cxx                   |   30 ++++++++++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

New commits:
commit fd6a0cf1eb8441acb23f22e9e9fafc477bf4e57e
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Feb 19 13:26:48 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Feb 19 13:37:42 2023 +0000

    tdf#153724: make sure to retrieve the variable value before checking the 
type
    
    Commit 5760c94b8847164f9a7a181f031c7c86643944af tried to avoid all cases
    which could set an error in SbiRuntime::PushForEach. To do that, it checked
    the type of xObjVar before trying to get an object from it, which otherwise
    could set an error.
    
    But the type of the contained value can be not known until it is retrieved
    (which can happen inside SbxValue::Get in a call to SbxValue::Broadcast with
    SfxHintId::BasicDataWanted). This happens e.g. when the container passed to
    'for each' is a call to some special function, like VBA's 'Selection'. Then
    SbxValue::GetFullType would return SbxEMPTY prior to SbxValue::Get.
    
    Let's make sure to call SbxValue::Get first (asking for a Variant, to avoid
    errors on type mismatch), and only then, check the actual result data type.
    
    Change-Id: Iaa697f38285505e50504ae09f9307fbd29e09a53
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147273
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx
index b521e3e8b458..e6f4f7b68a6b 100644
--- a/basic/source/runtime/runtime.cxx
+++ b/basic/source/runtime/runtime.cxx
@@ -1146,7 +1146,15 @@ void SbiRuntime::PushForEach()
     pForStk = p;
 
     SbxVariableRef xObjVar = PopVar();
-    SbxBase* pObj = xObjVar && xObjVar->GetFullType() == SbxOBJECT ? 
xObjVar->GetObject() : nullptr;
+    SbxBase* pObj(nullptr);
+    if (xObjVar)
+    {
+        SbxValues v(SbxVARIANT);
+        // Here it may retrieve the value, and change the type from SbxEMPTY 
to SbxOBJECT
+        xObjVar->Get(v);
+        if (v.eType == SbxOBJECT)
+            pObj = v.pObj;
+    }
 
     if (SbxDimArray* pArray = dynamic_cast<SbxDimArray*>(pObj))
     {
diff --git a/sc/qa/extras/testdocuments/ForEachInSelection.ods 
b/sc/qa/extras/testdocuments/ForEachInSelection.ods
new file mode 100644
index 000000000000..7996c86eb953
Binary files /dev/null and b/sc/qa/extras/testdocuments/ForEachInSelection.ods 
differ
diff --git a/sc/qa/extras/vba-macro-test.cxx b/sc/qa/extras/vba-macro-test.cxx
index 29fdf213f8e7..04e4efece2cf 100644
--- a/sc/qa/extras/vba-macro-test.cxx
+++ b/sc/qa/extras/vba-macro-test.cxx
@@ -68,6 +68,7 @@ public:
     void testTdf118247();
     void testTdf126457();
     void testVbaPDFExport();
+    void testForEachInSelection();
 
     CPPUNIT_TEST_SUITE(VBAMacroTest);
     CPPUNIT_TEST(testSimpleCopyAndPaste);
@@ -92,6 +93,7 @@ public:
     CPPUNIT_TEST(testTdf118247);
     CPPUNIT_TEST(testTdf126457);
     CPPUNIT_TEST(testVbaPDFExport);
+    CPPUNIT_TEST(testForEachInSelection);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -870,6 +872,34 @@ void VBAMacroTest::testVbaPDFExport()
     SvFileStream aStream(aTempPdfFile.GetURL(), StreamMode::READ);
     CPPUNIT_ASSERT_MESSAGE("Failed to get the pdf document", 
aDocument.Read(aStream));
 }
+
+void VBAMacroTest::testForEachInSelection()
+{
+    loadFromURL(u"ForEachInSelection.ods");
+    SfxObjectShell* pFoundShell = 
SfxObjectShell::GetShellFromComponent(mxComponent);
+
+    CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell);
+    ScDocShell* pDocSh = static_cast<ScDocShell*>(pFoundShell);
+    ScDocument& rDoc = pDocSh->GetDocument();
+
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), rDoc.GetString(ScAddress(0, 0, 0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("bar"), rDoc.GetString(ScAddress(0, 1, 0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("baz"), rDoc.GetString(ScAddress(0, 2, 0)));
+
+    // tdf#153724: without the fix, this would fail with
+    // assertion failed
+    // - Expression: false
+    // - Unexpected dialog:  Error: BASIC runtime error.
+    // '13'
+    // Data type mismatch.
+    executeMacro("vnd.sun.Star.script:Standard.Module1.TestForEachInSelection?"
+                 "language=Basic&location=document");
+
+    CPPUNIT_ASSERT_EQUAL(OUString("oof"), rDoc.GetString(ScAddress(0, 0, 0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("rab"), rDoc.GetString(ScAddress(0, 1, 0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("zab"), rDoc.GetString(ScAddress(0, 2, 0)));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(VBAMacroTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();

Reply via email to