[llvm-branch-commits] [clang] [SSAF] Group virtual method slots into override families (PR #213317)

Ziqing Luo via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Aug 23 19:48:49 PDT 2026


================
@@ -0,0 +1,201 @@
+//===- VirtualMethodFamilyAnalysis.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ScalableStaticAnalysis/Analyses/VirtualMethodFamily/VirtualMethodFamily.h"
+#include "clang/ScalableStaticAnalysis/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysis/Core/WholeProgramAnalysis/AnalysisRegistry.h"
+#include "clang/ScalableStaticAnalysis/Core/WholeProgramAnalysis/SummaryAnalysis.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <map>
+#include <optional>
+#include <utility>
+
+using namespace clang::ssaf;
+
+namespace {
+
+struct MethodFamilyUnionFind {
+  EntityId find(EntityId E);
+  void unionSets(EntityId A, EntityId B);
+
+  void seed(EntityId E, EntityId Owner) { Roots.try_emplace(E, E); }
+  void seed(EntityId Owner, const VirtualMethodSummary &S);
+
+  auto keys() const { return llvm::make_first_range(Roots); }
+
+private:
+  llvm::DenseMap<EntityId, EntityId> Roots;
+};
+
+// Keeps track of what method declared the given parameter or return value.
+struct Owners {
+  void recordOwner(EntityId Owner, const VirtualMethodSummary &S);
+  void recordOwner(EntityId E, EntityId Owner);
+
+  EntityId getOwnerOf(EntityId Id) const {
+    assert(Owners.count(Id));
+    return Owners.at(Id);
+  }
+
+private:
+  llvm::DenseMap<EntityId, EntityId> Owners;
+};
+
+class VirtualMethodFamilyAnalysis final
+    : public SummaryAnalysis<VirtualMethodFamilyAnalysisResult,
+                             VirtualMethodSummary> {
+public:
+  llvm::Error add(EntityId Id, const VirtualMethodSummary &Summary) override {
+    Data[Id] = &Summary;
+    return llvm::Error::success();
+  }
+
+  llvm::Error finalize() override;
+
+private:
+  /// Fill the \c Owners and \c Family maps.
+  void groupParamsAndReturnEntities();
+
+  /// Make the param and return IDs share a family.
+  void unionParamsAndReturnEntitiesInSummaries(const VirtualMethodSummary &LHS,
+                                               const VirtualMethodSummary &RHS);
+
+  Owners Owners;
+  MethodFamilyUnionFind Family;
+  std::map<EntityId, const VirtualMethodSummary *> Data;
+};
+} // namespace
+
+EntityId MethodFamilyUnionFind::find(EntityId E) {
+  auto It = Roots.find(E);
+  if (It == Roots.end()) {
+    Roots.try_emplace(E, E); // Self-rooted singleton.
+    return E;
+  }
+  if (It->second == E)
+    return E;
+  EntityId Root = find(It->second);
+  Roots.insert_or_assign(E, Root); // Path compression.
+  return Root;
+}
+
+void MethodFamilyUnionFind::unionSets(EntityId A, EntityId B) {
+  EntityId RootA = find(A);
+  EntityId RootB = find(B);
+  if (RootA == RootB)
+    return;
+
+  // Prefer the lexicographically-smaller rep for stable output across runs.
+  if (RootB < RootA)
+    std::swap(RootA, RootB);
+
+  Roots.insert_or_assign(RootB, RootA);
+}
+
+void MethodFamilyUnionFind::seed(EntityId Owner,
----------------
ziqingluo-90 wrote:

Why the parameter `Owner` is needed?  The other `seed` function does not use it.

The ownership relation and the belong-to-a-family relation are independent, right? The union-find algorithm computes the latter one.  The algorithm doesn't have to involve `Owner`.

https://github.com/llvm/llvm-project/pull/213317


More information about the llvm-branch-commits mailing list