From 1033f3b4249b8b0224ba725b220338e6c9621084 Mon Sep 17 00:00:00 2001
From: Kitsune Ral <Kitsune-Ral@users.sf.net>
Date: Sat, 18 May 2019 21:50:08 +0900
Subject: Connection::onSyncSuccess(): fix using after move()

Also rewrite the account data piece with visit().
---
 lib/connection.cpp | 116 +++++++++++++++++++++++++++--------------------------
 1 file changed, 60 insertions(+), 56 deletions(-)

(limited to 'lib')

diff --git a/lib/connection.cpp b/lib/connection.cpp
index d75d8e56..cd0d96f7 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -411,63 +411,67 @@ void Connection::onSyncSuccess(SyncData &&data, bool fromCache) {
         // Let UI update itself after updating each room
         QCoreApplication::processEvents();
     }
-    for (auto&& accountEvent: data.takeAccountData())
-    {
-        if (is<DirectChatEvent>(*accountEvent))
-        {
-            const auto usersToDCs = ptrCast<DirectChatEvent>(move(accountEvent))
-                                        ->usersToDirectChats();
-            DirectChatsMap removals =
-                erase_if(d->directChats, [&usersToDCs] (auto it) {
-                    return !usersToDCs.contains(it.key()->id(), it.value());
-                });
-            erase_if(d->directChatUsers, [&usersToDCs] (auto it) {
-                return !usersToDCs.contains(it.value()->id(), it.key());
-            });
-            if (MAIN().isDebugEnabled())
-                for (auto it = removals.begin(); it != removals.end(); ++it)
-                    qCDebug(MAIN) << it.value()
-                        << "is no more a direct chat with" << it.key()->id();
-
-            DirectChatsMap additions;
-            for (auto it = usersToDCs.begin(); it != usersToDCs.end(); ++it)
-            {
-                if (auto* u = user(it.key()))
-                {
-                    if (!d->directChats.contains(u, it.value()))
-                    {
-                        Q_ASSERT(!d->directChatUsers.contains(it.value(), u));
-                        additions.insert(u, it.value());
-                        d->directChats.insert(u, it.value());
-                        d->directChatUsers.insert(it.value(), u);
-                        qCDebug(MAIN) << "Marked room" << it.value()
+    // After running this loop, the account data events not saved in
+    // d->accountData (see the end of the loop body) are auto-cleaned away
+    for (auto& eventPtr: data.takeAccountData())
+        visit(*eventPtr,
+              [this](const DirectChatEvent& dce) {
+                  const auto& usersToDCs = dce.usersToDirectChats();
+                  DirectChatsMap removals =
+                          erase_if(d->directChats, [&usersToDCs](auto it) {
+                              return !usersToDCs.contains(it.key()->id(),
+                                                          it.value());
+                          });
+                  erase_if(d->directChatUsers, [&usersToDCs](auto it) {
+                      return !usersToDCs.contains(it.value()->id(), it.key());
+                  });
+                  if (MAIN().isDebugEnabled())
+                      for (auto it = removals.begin(); it != removals.end();
+                               ++it)
+                          qCDebug(MAIN) << it.value()
+                                        << "is no more a direct chat with"
+                                        << it.key()->id();
+
+                  DirectChatsMap additions;
+                  for (auto it = usersToDCs.begin(); it != usersToDCs.end();
+                           ++it) {
+                      if (auto* u = user(it.key())) {
+                          if (!d->directChats.contains(u, it.value())) {
+                              Q_ASSERT(!d->directChatUsers.contains(it.value(),
+                                                                    u));
+                              additions.insert(u, it.value());
+                              d->directChats.insert(u, it.value());
+                              d->directChatUsers.insert(it.value(), u);
+                              qCDebug(MAIN)
+                                      << "Marked room" << it.value()
                                       << "as a direct chat with" << u->id();
-                    }
-                } else
-                    qCWarning(MAIN)
-                            << "Couldn't get a user object for" << it.key();
-            }
-            if (!additions.isEmpty() || !removals.isEmpty())
-                emit directChatsListChanged(additions, removals);
-
-            continue;
-        }
-        if (is<IgnoredUsersEvent>(*accountEvent))
-            qCDebug(MAIN) << "Users ignored by" << d->userId << "updated:"
-                << QStringList::fromSet(ignoredUsers()).join(',');
-
-        auto& currentData = d->accountData[accountEvent->matrixType()];
-        // A polymorphic event-specific comparison might be a bit more
-        // efficient; maaybe do it another day
-        if (!currentData ||
-                currentData->contentJson() != accountEvent->contentJson())
-        {
-            currentData = std::move(accountEvent);
-            qCDebug(MAIN) << "Updated account data of type"
-                          << currentData->matrixType();
-            emit accountDataChanged(currentData->matrixType());
-        }
-    }
+                          }
+                      } else
+                          qCWarning(MAIN) << "Couldn't get a user object for"
+                                          << it.key();
+                  }
+                  if (!additions.isEmpty() || !removals.isEmpty())
+                      emit directChatsListChanged(additions, removals);
+              },
+              // catch-all, passing eventPtr for a possible take-over
+              [this, &eventPtr](const Event& accountEvent) {
+                  if (is<IgnoredUsersEvent>(accountEvent))
+                      qCDebug(MAIN)
+                              << "Users ignored by" << d->userId << "updated:"
+                              << QStringList::fromSet(ignoredUsers()).join(',');
+
+                  auto& currentData = d->accountData[accountEvent.matrixType()];
+                  // A polymorphic event-specific comparison might be a bit more
+                  // efficient; maaybe do it another day
+                  if (!currentData
+                      || currentData->contentJson()
+                              != accountEvent.contentJson()) {
+                      currentData = std::move(eventPtr);
+                      qCDebug(MAIN) << "Updated account data of type"
+                                    << currentData->matrixType();
+                      emit accountDataChanged(currentData->matrixType());
+                  }
+              });
 }
 
 void Connection::stopSync()
-- 
cgit v1.2.3