https://github.com/jkorous-apple updated 
https://github.com/llvm/llvm-project/pull/169131

>From 61f84a4c4dfa70a4c4367c07075ac9a392cf70b4 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Fri, 21 Nov 2025 15:53:11 -0800
Subject: [PATCH 01/10] [clang][ssaf] Introduce entity abstraction for SSAF

Add core abstractions for identifying program entities across compilation
and link unit boundaries in the Scalable Static Analysis Framework (SSAF).

Introduces three key components:
- BuildNamespace: Represents build artifacts (compilation units, link units)
- EntityName: Globally unique entity identifiers across compilation boundaries
- AST mapping: Functions to map Clang AST declarations to EntityNames

Entity identification uses Unified Symbol Resolution (USR) as the underlying
mechanism, with extensions for sub-entities (parameters, return values) via
suffixes. The abstraction allows whole-program analysis by providing stable
identifiers that persist across separately compiled translation units.
---
 .../Analysis/Scalable/ASTEntityMapping.h      |  46 +++
 .../Analysis/Scalable/Model/BuildNamespace.h  |  84 +++++
 .../Analysis/Scalable/Model/EntityName.h      |  47 +++
 clang/lib/Analysis/CMakeLists.txt             |   1 +
 .../Analysis/Scalable/ASTEntityMapping.cpp    |  85 +++++
 clang/lib/Analysis/Scalable/CMakeLists.txt    |  19 +
 .../Scalable/Model/BuildNamespace.cpp         |  72 ++++
 .../Analysis/Scalable/Model/EntityName.cpp    |  44 +++
 clang/unittests/Analysis/CMakeLists.txt       |   1 +
 .../Scalable/ASTEntityMappingTest.cpp         | 343 ++++++++++++++++++
 .../Analysis/Scalable/BuildNamespaceTest.cpp  |  99 +++++
 .../Analysis/Scalable/CMakeLists.txt          |  18 +
 .../Analysis/Scalable/EntityNameTest.cpp      |  62 ++++
 13 files changed, 921 insertions(+)
 create mode 100644 clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
 create mode 100644 clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
 create mode 100644 clang/include/clang/Analysis/Scalable/Model/EntityName.h
 create mode 100644 clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
 create mode 100644 clang/lib/Analysis/Scalable/CMakeLists.txt
 create mode 100644 clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
 create mode 100644 clang/lib/Analysis/Scalable/Model/EntityName.cpp
 create mode 100644 clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
 create mode 100644 clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp
 create mode 100644 clang/unittests/Analysis/Scalable/CMakeLists.txt
 create mode 100644 clang/unittests/Analysis/Scalable/EntityNameTest.cpp

diff --git a/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h 
b/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
new file mode 100644
index 0000000000000..a137e8b741821
--- /dev/null
+++ b/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
@@ -0,0 +1,46 @@
+//===- ASTMapping.h - AST to SSAF Entity mapping ----------------*- C++ 
-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
+
+#include "clang/Analysis/Scalable/Model/EntityName.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/StringRef.h"
+#include <optional>
+
+namespace clang {
+namespace ssaf {
+
+/// Maps a declaration to an EntityName.
+///
+/// Supported declaration types for entity mapping:
+/// - Functions and methods
+/// - Global Variables
+/// - Function parameters
+/// - Struct/class/union type definitions
+/// - Struct/class/union fields
+///
+/// Implicit declarations and compiler builtins are not mapped.
+///
+/// \param D The declaration to map. Must not be null.
+///
+/// \return An EntityName if the declaration can be mapped, std::nullopt 
otherwise.
+std::optional<EntityName> getLocalEntityNameForDecl(const Decl* D);
+
+/// Maps a function return type to an EntityName.
+///
+/// \param FD The function declaration. Must not be null.
+///
+/// \return An EntityName for the function's return type.
+std::optional<EntityName> getLocalEntityNameForFunctionReturn(const 
FunctionDecl* FD);
+
+} // namespace ssaf
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
new file mode 100644
index 0000000000000..c4bf7146e461f
--- /dev/null
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -0,0 +1,84 @@
+//===- BuildNamespace.h -----------------------------------------*- C++ 
-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
+
+#include "llvm/ADT/StringRef.h"
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace ssaf {
+
+enum class BuildNamespaceKind : unsigned short {
+  CompilationUnit,
+  LinkUnit
+};
+
+std::string toString(BuildNamespaceKind BNK);
+
+std::optional<BuildNamespaceKind> parseBuildNamespaceKind(llvm::StringRef Str);
+
+/// Represents a single step in the build process.
+class BuildNamespace {
+  BuildNamespaceKind Kind;
+  std::string Name;
+public:
+  BuildNamespace(BuildNamespaceKind Kind, llvm::StringRef Name)
+    : Kind(Kind), Name(Name.str()) {}
+
+  static BuildNamespace makeTU(llvm::StringRef CompilationId);
+
+  bool operator==(const BuildNamespace& Other) const;
+  bool operator!=(const BuildNamespace& Other) const;
+  bool operator<(const BuildNamespace& Other) const;
+
+  friend class SerializationFormat;
+};
+
+/// Represents a sequence of steps in the build process.
+class NestedBuildNamespace {
+  friend class SerializationFormat;
+
+  std::vector<BuildNamespace> Namespaces;
+
+public:
+  NestedBuildNamespace() = default;
+
+  explicit NestedBuildNamespace(const std::vector<BuildNamespace>& Namespaces)
+    : Namespaces(Namespaces) {}
+
+  explicit NestedBuildNamespace(const BuildNamespace& N) {
+    Namespaces.push_back(N);
+  }
+
+  static NestedBuildNamespace makeTU(llvm::StringRef CompilationId);
+
+  NestedBuildNamespace makeQualified(NestedBuildNamespace Namespace) {
+    auto Copy = *this;
+    for (const auto& N : Namespace.Namespaces)
+      Copy.Namespaces.push_back(N);
+    return Copy;
+  }
+
+  bool empty() const;
+
+  bool operator==(const NestedBuildNamespace& Other) const;
+  bool operator!=(const NestedBuildNamespace& Other) const;
+  bool operator<(const NestedBuildNamespace& Other) const;
+
+  friend class JSONWriter;
+  friend class LinkUnitResolution;
+};
+
+} // namespace ssaf
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h 
b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
new file mode 100644
index 0000000000000..7f11ef0589bf5
--- /dev/null
+++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
@@ -0,0 +1,47 @@
+//===- EntityName.h ---------------------------------------------*- C++ 
-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
+
+#include "clang/Analysis/Scalable/Model/BuildNamespace.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+namespace ssaf {
+
+/// Uniquely identifies an entity in a program.
+///
+/// EntityName provides a globally unique identifier for program entities that 
remains
+/// stable across compilation boundaries. This enables whole-program analysis 
to track
+/// and relate entities across separately compiled translation units.
+class EntityName {
+  std::string USR;
+  llvm::SmallString<16> Suffix;
+  NestedBuildNamespace Namespace;
+
+public:
+  EntityName(llvm::StringRef USR, llvm::StringRef Suffix,
+             NestedBuildNamespace Namespace);
+
+  bool operator==(const EntityName& Other) const;
+  bool operator!=(const EntityName& Other) const;
+  bool operator<(const EntityName& Other) const;
+
+  EntityName makeQualified(NestedBuildNamespace Namespace);
+
+  friend class LinkUnitResolution;
+  friend class SerializationFormat;
+};
+
+} // namespace ssaf
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
diff --git a/clang/lib/Analysis/CMakeLists.txt 
b/clang/lib/Analysis/CMakeLists.txt
index 1dbd4153d856f..99a2ec684e149 100644
--- a/clang/lib/Analysis/CMakeLists.txt
+++ b/clang/lib/Analysis/CMakeLists.txt
@@ -50,3 +50,4 @@ add_clang_library(clangAnalysis
 add_subdirectory(plugins)
 add_subdirectory(FlowSensitive)
 add_subdirectory(LifetimeSafety)
+add_subdirectory(Scalable)
diff --git a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp 
b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
new file mode 100644
index 0000000000000..87d05e8aa5dc3
--- /dev/null
+++ b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
@@ -0,0 +1,85 @@
+//===- ASTMapping.cpp - AST to SSAF Entity mapping --------------*- C++ 
-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements utilities for mapping AST declarations to SSAF 
entities.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Scalable/ASTEntityMapping.h"
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Scalable/Model/BuildNamespace.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/SmallString.h"
+
+namespace clang {
+namespace ssaf {
+
+std::optional<EntityName> getLocalEntityNameForDecl(const Decl* D) {
+  if (!D)
+    return std::nullopt;
+
+  if (D->isImplicit())
+    return std::nullopt;
+
+  if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->getBuiltinID())
+    return std::nullopt;
+
+  if (!isa<FunctionDecl>(D) && !isa<ParmVarDecl>(D) && !isa<VarDecl>(D) &&
+      !isa<FieldDecl>(D) && !isa<RecordDecl>(D))
+    return std::nullopt;
+
+  llvm::SmallString<16> Suffix;
+  const Decl *USRDecl = D;
+
+  // For parameters, use the parent function's USR with parameter index as 
suffix
+  if (const auto * PVD = dyn_cast<ParmVarDecl>(D)) {
+    const auto *FD = 
dyn_cast_or_null<FunctionDecl>(PVD->getParentFunctionOrMethod());
+    if (!FD)
+      return std::nullopt;
+    USRDecl = FD;
+
+    const auto ParamIdx = PVD->getFunctionScopeIndex();
+    llvm::raw_svector_ostream OS(Suffix);
+    // Parameter uses function's USR with 1-based index as suffix
+    OS << (ParamIdx + 1);
+  }
+
+  llvm::SmallString<128> USRBuf;
+  if (clang::index::generateUSRForDecl(USRDecl, USRBuf)) {
+    return std::nullopt;
+  }
+
+  if (USRBuf.empty())
+    return std::nullopt;
+
+  return EntityName(USRBuf.str(), Suffix, {});
+}
+
+std::optional<EntityName> getLocalEntityNameForFunctionReturn(const 
FunctionDecl* FD) {
+  if (!FD)
+    return std::nullopt;
+
+  if (FD->isImplicit())
+    return std::nullopt;
+
+  if (FD->getBuiltinID())
+    return std::nullopt;
+
+  llvm::SmallString<128> USRBuf;
+  if (clang::index::generateUSRForDecl(FD, USRBuf)) {
+    return std::nullopt;
+  }
+
+  if (USRBuf.empty())
+    return std::nullopt;
+
+  return EntityName(USRBuf.str(), "0", {});
+}
+
+} // namespace ssaf
+} // namespace clang
diff --git a/clang/lib/Analysis/Scalable/CMakeLists.txt 
b/clang/lib/Analysis/Scalable/CMakeLists.txt
new file mode 100644
index 0000000000000..ea4693f102cb2
--- /dev/null
+++ b/clang/lib/Analysis/Scalable/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangAnalysisScalable
+  ASTEntityMapping.cpp
+  Model/BuildNamespace.cpp
+  Model/EntityName.cpp
+
+  LINK_LIBS
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangIndex
+  clangLex
+  clangFrontend
+
+  DEPENDS
+  )
diff --git a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp 
b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
new file mode 100644
index 0000000000000..5284a9a87a33a
--- /dev/null
+++ b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
@@ -0,0 +1,72 @@
+//===- BuildNamespace.cpp ---------------------------------------*- C++ 
-*-===//
+//
+// 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/Analysis/Scalable/Model/BuildNamespace.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace clang {
+namespace ssaf {
+
+std::string toString(BuildNamespaceKind BNK) {
+  switch(BNK) {
+    case BuildNamespaceKind::CompilationUnit: return "compilation_unit";
+    case BuildNamespaceKind::LinkUnit: return "link_unit";
+  }
+  llvm_unreachable("Unknown BuildNamespaceKind");
+}
+
+std::optional<BuildNamespaceKind> parseBuildNamespaceKind(llvm::StringRef Str) 
{
+  if (Str == "compilation_unit")
+    return BuildNamespaceKind::CompilationUnit;
+  if (Str == "link_unit")
+    return BuildNamespaceKind::LinkUnit;
+  return std::nullopt;
+}
+
+BuildNamespace BuildNamespace::makeTU(llvm::StringRef CompilationId) {
+  return BuildNamespace{BuildNamespaceKind::CompilationUnit, 
CompilationId.str()};
+}
+
+bool BuildNamespace::operator==(const BuildNamespace& Other) const {
+  return Kind == Other.Kind && Name == Other.Name;
+}
+
+bool BuildNamespace::operator!=(const BuildNamespace& Other) const {
+  return !(*this == Other);
+}
+
+bool BuildNamespace::operator<(const BuildNamespace& Other) const {
+  if (Kind != Other.Kind)
+    return Kind < Other.Kind;
+  return Name < Other.Name;
+}
+
+NestedBuildNamespace NestedBuildNamespace::makeTU(llvm::StringRef 
CompilationId) {
+  NestedBuildNamespace Result;
+  Result.Namespaces.push_back(BuildNamespace::makeTU(CompilationId));
+  return Result;
+}
+
+bool NestedBuildNamespace::empty() const {
+  return Namespaces.empty();
+}
+
+bool NestedBuildNamespace::operator==(const NestedBuildNamespace& Other) const 
{
+  return Namespaces == Other.Namespaces;
+}
+
+bool NestedBuildNamespace::operator!=(const NestedBuildNamespace& Other) const 
{
+  return !(*this == Other);
+}
+
+bool NestedBuildNamespace::operator<(const NestedBuildNamespace& Other) const {
+  return Namespaces < Other.Namespaces;
+}
+
+} // namespace ssaf
+} // namespace clang
diff --git a/clang/lib/Analysis/Scalable/Model/EntityName.cpp 
b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
new file mode 100644
index 0000000000000..3404ecc58fac2
--- /dev/null
+++ b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
@@ -0,0 +1,44 @@
+//===- EntityName.cpp -------------------------------------------*- C++ 
-*-===//
+//
+// 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/Analysis/Scalable/Model/EntityName.h"
+
+namespace clang {
+namespace ssaf {
+
+EntityName::EntityName(llvm::StringRef USR, llvm::StringRef Suffix,
+                       NestedBuildNamespace Namespace)
+  : USR(USR.str()), Suffix(Suffix), Namespace(std::move(Namespace)) {}
+
+bool EntityName::operator==(const EntityName& Other) const {
+  return USR == Other.USR &&
+         Suffix == Other.Suffix &&
+         Namespace == Other.Namespace;
+}
+
+bool EntityName::operator!=(const EntityName& Other) const {
+  return !(*this == Other);
+}
+
+bool EntityName::operator<(const EntityName& Other) const {
+  if (USR != Other.USR)
+    return USR < Other.USR;
+  if (Suffix != Other.Suffix)
+    return Suffix.str() < Other.Suffix.str();
+  return Namespace < Other.Namespace;
+}
+
+EntityName EntityName::makeQualified(NestedBuildNamespace Namespace) {
+  auto Copy = *this;
+  Copy.Namespace = Copy.Namespace.makeQualified(Namespace);
+
+  return Copy;
+}
+
+} // namespace ssaf
+} // namespace clang
diff --git a/clang/unittests/Analysis/CMakeLists.txt 
b/clang/unittests/Analysis/CMakeLists.txt
index e0acf436b37c7..97e768b11db69 100644
--- a/clang/unittests/Analysis/CMakeLists.txt
+++ b/clang/unittests/Analysis/CMakeLists.txt
@@ -26,3 +26,4 @@ add_clang_unittest(ClangAnalysisTests
   )
 
 add_subdirectory(FlowSensitive)
+add_subdirectory(Scalable)
diff --git a/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp 
b/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
new file mode 100644
index 0000000000000..8de0df246cb65
--- /dev/null
+++ b/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
@@ -0,0 +1,343 @@
+//===- unittests/Analysis/Scalable/ASTEntityMappingTest.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/Analysis/Scalable/ASTEntityMapping.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace ssaf {
+namespace {
+
+// Helper function to find a declaration by name
+template <typename DeclType>
+const DeclType *findDecl(ASTContext &Ctx, StringRef Name) {
+  auto Matcher = namedDecl(hasName(Name)).bind("decl");
+  auto Matches = match(Matcher, Ctx);
+  if (Matches.empty())
+    return nullptr;
+  return Matches[0].getNodeAs<DeclType>("decl");
+}
+
+TEST(ASTEntityMappingTest, FunctionDecl) {
+  auto AST = tooling::buildASTFromCode("void foo() {}");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *FD = findDecl<FunctionDecl>(Ctx, "foo");
+  ASSERT_NE(FD, nullptr);
+
+  auto EntityName = getLocalEntityNameForDecl(FD);
+  EXPECT_TRUE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, VarDecl) {
+  auto AST = tooling::buildASTFromCode("int x = 42;");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *VD = findDecl<VarDecl>(Ctx, "x");
+  ASSERT_NE(VD, nullptr);
+
+  auto EntityName = getLocalEntityNameForDecl(VD);
+  EXPECT_TRUE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, ParmVarDecl) {
+  auto AST = tooling::buildASTFromCode("void foo(int x) {}");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *FD = findDecl<FunctionDecl>(Ctx, "foo");
+  ASSERT_NE(FD, nullptr);
+  ASSERT_GT(FD->param_size(), 0u);
+
+  const auto *PVD = FD->getParamDecl(0);
+  ASSERT_NE(PVD, nullptr);
+
+  auto EntityName = getLocalEntityNameForDecl(PVD);
+  EXPECT_TRUE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, RecordDecl) {
+  auto AST = tooling::buildASTFromCode("struct S {};");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *RD = findDecl<RecordDecl>(Ctx, "S");
+  ASSERT_NE(RD, nullptr);
+
+  auto EntityName = getLocalEntityNameForDecl(RD);
+  EXPECT_TRUE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, FieldDecl) {
+  auto AST = tooling::buildASTFromCode("struct S { int field; };");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *FD = findDecl<FieldDecl>(Ctx, "field");
+  ASSERT_NE(FD, nullptr);
+
+  auto EntityName = getLocalEntityNameForDecl(FD);
+  EXPECT_TRUE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, NullDecl) {
+  auto EntityName = getLocalEntityNameForDecl(nullptr);
+  EXPECT_FALSE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, ImplicitDecl) {
+  auto AST = tooling::buildASTFromCode(R"(
+    struct S {
+      S() = default;
+    };
+  )", "test.cpp", std::make_shared<PCHContainerOperations>());
+  auto &Ctx = AST->getASTContext();
+
+  const auto *RD = findDecl<CXXRecordDecl>(Ctx, "S");
+  ASSERT_NE(RD, nullptr);
+
+  // Find the implicitly-declared copy constructor
+  for (const auto *Ctor : RD->ctors()) {
+    if (Ctor->isCopyConstructor() && Ctor->isImplicit()) {
+      auto EntityName = getLocalEntityNameForDecl(Ctor);
+      EXPECT_FALSE(EntityName.has_value());
+      return;
+    }
+  }
+}
+
+TEST(ASTEntityMappingTest, BuiltinFunction) {
+  auto AST = tooling::buildASTFromCode(R"(
+    void test() {
+      __builtin_memcpy(0, 0, 0);
+    }
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  // Find the builtin call
+  auto Matcher = callExpr().bind("call");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_FALSE(Matches.empty());
+
+  const auto *CE = Matches[0].getNodeAs<CallExpr>("call");
+  ASSERT_NE(CE, nullptr);
+
+  const auto *Callee = CE->getDirectCallee();
+  if (Callee && Callee->getBuiltinID()) {
+    auto EntityName = getLocalEntityNameForDecl(Callee);
+    EXPECT_FALSE(EntityName.has_value());
+  }
+}
+
+TEST(ASTEntityMappingTest, UnsupportedDecl) {
+  auto AST = tooling::buildASTFromCode("namespace N {}");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *ND = findDecl<NamespaceDecl>(Ctx, "N");
+  ASSERT_NE(ND, nullptr);
+
+  auto EntityName = getLocalEntityNameForDecl(ND);
+  EXPECT_FALSE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, FunctionReturn) {
+  auto AST = tooling::buildASTFromCode("int foo() { return 42; }");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *FD = findDecl<FunctionDecl>(Ctx, "foo");
+  ASSERT_NE(FD, nullptr);
+
+  auto EntityName = getLocalEntityNameForFunctionReturn(FD);
+  EXPECT_TRUE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, FunctionReturnNull) {
+  auto EntityName = getLocalEntityNameForFunctionReturn(nullptr);
+  EXPECT_FALSE(EntityName.has_value());
+}
+
+TEST(ASTEntityMappingTest, FunctionReturnBuiltin) {
+  auto AST = tooling::buildASTFromCode(R"(
+    void test() {
+      __builtin_memcpy(0, 0, 0);
+    }
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  // Find the builtin call
+  auto Matcher = callExpr().bind("call");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_FALSE(Matches.empty());
+
+  const auto *CE = Matches[0].getNodeAs<CallExpr>("call");
+  ASSERT_NE(CE, nullptr);
+
+  const auto *Callee = CE->getDirectCallee();
+  if (Callee && Callee->getBuiltinID()) {
+    auto EntityName = getLocalEntityNameForFunctionReturn(Callee);
+    EXPECT_FALSE(EntityName.has_value());
+  }
+}
+
+TEST(ASTEntityMappingTest, DifferentFunctionsDifferentNames) {
+  auto AST = tooling::buildASTFromCode(R"(
+    void foo() {}
+    void bar() {}
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  const auto *Foo = findDecl<FunctionDecl>(Ctx, "foo");
+  const auto *Bar = findDecl<FunctionDecl>(Ctx, "bar");
+  ASSERT_NE(Foo, nullptr);
+  ASSERT_NE(Bar, nullptr);
+
+  auto FooName = getLocalEntityNameForDecl(Foo);
+  auto BarName = getLocalEntityNameForDecl(Bar);
+  ASSERT_TRUE(FooName.has_value());
+  ASSERT_TRUE(BarName.has_value());
+
+  EXPECT_NE(*FooName, *BarName);
+}
+
+// Redeclaration tests
+
+TEST(ASTEntityMappingTest, FunctionRedeclaration) {
+  auto AST = tooling::buildASTFromCode(R"(
+    void foo();
+    void foo() {}
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  auto Matcher = functionDecl(hasName("foo")).bind("decl");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_EQ(Matches.size(), 2u);
+
+  const auto *Decl1 = Matches[0].getNodeAs<FunctionDecl>("decl");
+  const auto *Decl2 = Matches[1].getNodeAs<FunctionDecl>("decl");
+  ASSERT_NE(Decl1, nullptr);
+  ASSERT_NE(Decl2, nullptr);
+
+  auto Name1 = getLocalEntityNameForDecl(Decl1);
+  auto Name2 = getLocalEntityNameForDecl(Decl2);
+  ASSERT_TRUE(Name1.has_value());
+  ASSERT_TRUE(Name2.has_value());
+
+  EXPECT_EQ(*Name1, *Name2);
+}
+
+TEST(ASTEntityMappingTest, VarRedeclaration) {
+  auto AST = tooling::buildASTFromCode(R"(
+    extern int x;
+    int x = 42;
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  auto Matcher = varDecl(hasName("x")).bind("decl");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_EQ(Matches.size(), 2u);
+
+  const auto *Decl1 = Matches[0].getNodeAs<VarDecl>("decl");
+  const auto *Decl2 = Matches[1].getNodeAs<VarDecl>("decl");
+  ASSERT_NE(Decl1, nullptr);
+  ASSERT_NE(Decl2, nullptr);
+
+  auto Name1 = getLocalEntityNameForDecl(Decl1);
+  auto Name2 = getLocalEntityNameForDecl(Decl2);
+  ASSERT_TRUE(Name1.has_value());
+  ASSERT_TRUE(Name2.has_value());
+
+  EXPECT_EQ(*Name1, *Name2);
+}
+
+TEST(ASTEntityMappingTest, RecordRedeclaration) {
+  auto AST = tooling::buildASTFromCode(R"(
+    struct S;
+    struct S {};
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  // Use recordDecl(isStruct()) to avoid matching implicit typedefs
+  auto Matcher = recordDecl(hasName("S"), isStruct()).bind("decl");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_GE(Matches.size(), 2u);
+
+  const auto *Decl1 = Matches[0].getNodeAs<RecordDecl>("decl");
+  const auto *Decl2 = Matches[1].getNodeAs<RecordDecl>("decl");
+  ASSERT_NE(Decl1, nullptr);
+  ASSERT_NE(Decl2, nullptr);
+
+  auto Name1 = getLocalEntityNameForDecl(Decl1);
+  auto Name2 = getLocalEntityNameForDecl(Decl2);
+  ASSERT_TRUE(Name1.has_value());
+  ASSERT_TRUE(Name2.has_value());
+
+  EXPECT_EQ(*Name1, *Name2);
+}
+
+TEST(ASTEntityMappingTest, ParmVarDeclRedeclaration) {
+  auto AST = tooling::buildASTFromCode(R"(
+    void foo(int x);
+    void foo(int x) {}
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  auto Matcher = functionDecl(hasName("foo")).bind("decl");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_EQ(Matches.size(), 2u);
+
+  const auto *Func1 = Matches[0].getNodeAs<FunctionDecl>("decl");
+  const auto *Func2 = Matches[1].getNodeAs<FunctionDecl>("decl");
+  ASSERT_NE(Func1, nullptr);
+  ASSERT_NE(Func2, nullptr);
+  ASSERT_GT(Func1->param_size(), 0u);
+  ASSERT_GT(Func2->param_size(), 0u);
+
+  const auto *Param1 = Func1->getParamDecl(0);
+  const auto *Param2 = Func2->getParamDecl(0);
+  ASSERT_NE(Param1, nullptr);
+  ASSERT_NE(Param2, nullptr);
+
+  auto Name1 = getLocalEntityNameForDecl(Param1);
+  auto Name2 = getLocalEntityNameForDecl(Param2);
+  ASSERT_TRUE(Name1.has_value());
+  ASSERT_TRUE(Name2.has_value());
+
+  EXPECT_EQ(*Name1, *Name2);
+}
+
+TEST(ASTEntityMappingTest, FunctionReturnRedeclaration) {
+  auto AST = tooling::buildASTFromCode(R"(
+    int foo();
+    int foo() { return 42; }
+  )");
+  auto &Ctx = AST->getASTContext();
+
+  auto Matcher = functionDecl(hasName("foo")).bind("decl");
+  auto Matches = match(Matcher, Ctx);
+  ASSERT_EQ(Matches.size(), 2u);
+
+  const auto *Decl1 = Matches[0].getNodeAs<FunctionDecl>("decl");
+  const auto *Decl2 = Matches[1].getNodeAs<FunctionDecl>("decl");
+  ASSERT_NE(Decl1, nullptr);
+  ASSERT_NE(Decl2, nullptr);
+
+  auto Name1 = getLocalEntityNameForFunctionReturn(Decl1);
+  auto Name2 = getLocalEntityNameForFunctionReturn(Decl2);
+  ASSERT_TRUE(Name1.has_value());
+  ASSERT_TRUE(Name2.has_value());
+
+  EXPECT_EQ(*Name1, *Name2);
+}
+
+} // namespace
+} // namespace ssaf
+} // namespace clang
diff --git a/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp 
b/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp
new file mode 100644
index 0000000000000..aa4155faa30f8
--- /dev/null
+++ b/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp
@@ -0,0 +1,99 @@
+//===- unittests/Analysis/Scalable/BuildNamespaceTest.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/Analysis/Scalable/Model/BuildNamespace.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ssaf {
+namespace {
+
+TEST(BuildNamespaceTest, Equality) {
+  auto BN1 = BuildNamespace::makeTU("test.cpp");
+  auto BN2 = BuildNamespace::makeTU("test.cpp");
+  auto BN3 = BuildNamespace::makeTU("other.cpp");
+
+  EXPECT_EQ(BN1, BN2);
+  EXPECT_NE(BN1, BN3);
+}
+
+TEST(BuildNamespaceTest, DifferentKinds) {
+  BuildNamespace CU(BuildNamespaceKind::CompilationUnit, "test");
+  BuildNamespace LU(BuildNamespaceKind::LinkUnit, "test");
+
+  EXPECT_NE(CU, LU);
+}
+
+TEST(BuildNamespaceTest, ToStringRoundtripCompilationUnit) {
+  auto Kind = BuildNamespaceKind::CompilationUnit;
+  auto Str = toString(Kind);
+  auto Parsed = parseBuildNamespaceKind(Str);
+
+  ASSERT_TRUE(Parsed.has_value());
+  EXPECT_EQ(Kind, *Parsed);
+}
+
+TEST(BuildNamespaceTest, ToStringRoundtripLinkUnit) {
+  auto Kind = BuildNamespaceKind::LinkUnit;
+  auto Str = toString(Kind);
+  auto Parsed = parseBuildNamespaceKind(Str);
+
+  ASSERT_TRUE(Parsed.has_value());
+  EXPECT_EQ(Kind, *Parsed);
+}
+
+// NestedBuildNamespace Tests
+
+TEST(NestedBuildNamespaceTest, DefaultConstruction) {
+  NestedBuildNamespace NBN;
+  EXPECT_TRUE(NBN.empty());
+}
+
+TEST(NestedBuildNamespaceTest, SingleNamespaceConstruction) {
+  auto BN = BuildNamespace::makeTU("test.cpp");
+  NestedBuildNamespace NBN(BN);
+
+  EXPECT_FALSE(NBN.empty());
+}
+
+TEST(NestedBuildNamespaceTest, MakeTU) {
+  auto NBN = NestedBuildNamespace::makeTU("test.cpp");
+  EXPECT_FALSE(NBN.empty());
+}
+
+TEST(NestedBuildNamespaceTest, Equality) {
+  auto NBN1 = NestedBuildNamespace::makeTU("test.cpp");
+  auto NBN2 = NestedBuildNamespace::makeTU("test.cpp");
+  auto NBN3 = NestedBuildNamespace::makeTU("other.cpp");
+
+  EXPECT_EQ(NBN1, NBN2);
+  EXPECT_NE(NBN1, NBN3);
+}
+
+TEST(NestedBuildNamespaceTest, MakeQualified) {
+  auto NBN1 = NestedBuildNamespace::makeTU("test.cpp");
+  BuildNamespace LinkNS(BuildNamespaceKind::LinkUnit, "app");
+  NestedBuildNamespace NBN2(LinkNS);
+
+  auto Qualified = NBN1.makeQualified(NBN2);
+
+  EXPECT_NE(Qualified, NBN1);
+  EXPECT_NE(Qualified, NBN2);
+}
+
+TEST(NestedBuildNamespaceTest, EmptyQualified) {
+  NestedBuildNamespace Empty;
+  auto NBN = NestedBuildNamespace::makeTU("test.cpp");
+
+  auto Qualified = Empty.makeQualified(NBN);
+  EXPECT_EQ(Qualified, NBN);
+}
+
+} // namespace
+} // namespace ssaf
+} // namespace clang
diff --git a/clang/unittests/Analysis/Scalable/CMakeLists.txt 
b/clang/unittests/Analysis/Scalable/CMakeLists.txt
new file mode 100644
index 0000000000000..95aaa2aea253c
--- /dev/null
+++ b/clang/unittests/Analysis/Scalable/CMakeLists.txt
@@ -0,0 +1,18 @@
+add_distinct_clang_unittest(ClangScalableAnalysisFrameworkTests
+  BuildNamespaceTest.cpp
+  EntityNameTest.cpp
+  ASTEntityMappingTest.cpp
+
+  CLANG_LIBS
+  clangAnalysisScalable
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangSerialization
+  clangTooling
+  )
+
+add_custom_target(ClangScalableAnalysisTests
+  DEPENDS
+  ClangScalableAnalysisFrameworkTests
+  )
diff --git a/clang/unittests/Analysis/Scalable/EntityNameTest.cpp 
b/clang/unittests/Analysis/Scalable/EntityNameTest.cpp
new file mode 100644
index 0000000000000..f32807f3be1c1
--- /dev/null
+++ b/clang/unittests/Analysis/Scalable/EntityNameTest.cpp
@@ -0,0 +1,62 @@
+//===- unittests/Analysis/Scalable/EntityNameTest.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/Analysis/Scalable/Model/EntityName.h"
+#include "clang/Analysis/Scalable/Model/BuildNamespace.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ssaf {
+namespace {
+
+TEST(EntityNameTest, Equality) {
+  auto NBN1 = NestedBuildNamespace::makeTU("test.cpp");
+  auto NBN2 = NestedBuildNamespace::makeTU("test.cpp");
+
+  EntityName EN1("c:@F@foo", "", NBN1);
+  EntityName EN2("c:@F@foo", "", NBN2);
+  EntityName EN3("c:@F@bar", "", NBN1);
+
+  EXPECT_EQ(EN1, EN2);
+  EXPECT_NE(EN1, EN3);
+}
+
+TEST(EntityNameTest, EqualityWithDifferentSuffix) {
+  auto NBN = NestedBuildNamespace::makeTU("test.cpp");
+
+  EntityName EN1("c:@F@foo", "1", NBN);
+  EntityName EN2("c:@F@foo", "2", NBN);
+
+  EXPECT_NE(EN1, EN2);
+}
+
+TEST(EntityNameTest, EqualityWithDifferentNamespace) {
+  auto NBN1 = NestedBuildNamespace::makeTU("test1.cpp");
+  auto NBN2 = NestedBuildNamespace::makeTU("test2.cpp");
+
+  EntityName EN1("c:@F@foo", "", NBN1);
+  EntityName EN2("c:@F@foo", "", NBN2);
+
+  EXPECT_NE(EN1, EN2);
+}
+
+TEST(EntityNameTest, MakeQualified) {
+  auto NBN1 = NestedBuildNamespace::makeTU("test.cpp");
+  EntityName EN("c:@F@foo", "", NBN1);
+
+  BuildNamespace LinkNS(BuildNamespaceKind::LinkUnit, "app");
+  NestedBuildNamespace NBN2(LinkNS);
+
+  auto Qualified = EN.makeQualified(NBN2);
+
+  EXPECT_NE(Qualified, EN);
+}
+
+} // namespace
+} // namespace ssaf
+} // namespace clang

>From d1f0e7975c34e5346aa62a9072fdad638fbeac90 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Wed, 3 Dec 2025 14:12:13 -0800
Subject: [PATCH 02/10] [clang][ssaf] Use nested namespace definitions

---
 clang/include/clang/Analysis/Scalable/ASTEntityMapping.h    | 6 ++----
 .../include/clang/Analysis/Scalable/Model/BuildNamespace.h  | 6 ++----
 clang/include/clang/Analysis/Scalable/Model/EntityName.h    | 6 ++----
 clang/lib/Analysis/Scalable/ASTEntityMapping.cpp            | 6 ++----
 clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp        | 6 ++----
 clang/lib/Analysis/Scalable/Model/EntityName.cpp            | 6 ++----
 clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp  | 6 ++----
 clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp    | 6 ++----
 clang/unittests/Analysis/Scalable/EntityNameTest.cpp        | 6 ++----
 9 files changed, 18 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h 
b/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
index a137e8b741821..d1a5b3790ef50 100644
--- a/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
+++ b/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
@@ -14,8 +14,7 @@
 #include "llvm/ADT/StringRef.h"
 #include <optional>
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 
 /// Maps a declaration to an EntityName.
 ///
@@ -40,7 +39,6 @@ std::optional<EntityName> getLocalEntityNameForDecl(const 
Decl* D);
 /// \return An EntityName for the function's return type.
 std::optional<EntityName> getLocalEntityNameForFunctionReturn(const 
FunctionDecl* FD);
 
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
 
 #endif // LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
index c4bf7146e461f..f409dac272ea1 100644
--- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -14,8 +14,7 @@
 #include <string>
 #include <vector>
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 
 enum class BuildNamespaceKind : unsigned short {
   CompilationUnit,
@@ -78,7 +77,6 @@ class NestedBuildNamespace {
   friend class LinkUnitResolution;
 };
 
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
 
 #endif // LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h 
b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
index 7f11ef0589bf5..f76ac6f99e15a 100644
--- a/clang/include/clang/Analysis/Scalable/Model/EntityName.h
+++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
@@ -14,8 +14,7 @@
 #include "llvm/ADT/StringRef.h"
 #include <string>
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 
 /// Uniquely identifies an entity in a program.
 ///
@@ -41,7 +40,6 @@ class EntityName {
   friend class SerializationFormat;
 };
 
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
 
 #endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
diff --git a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp 
b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
index 87d05e8aa5dc3..a82369c1c471e 100644
--- a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
+++ b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
@@ -16,8 +16,7 @@
 #include "clang/Index/USRGeneration.h"
 #include "llvm/ADT/SmallString.h"
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 
 std::optional<EntityName> getLocalEntityNameForDecl(const Decl* D) {
   if (!D)
@@ -81,5 +80,4 @@ std::optional<EntityName> 
getLocalEntityNameForFunctionReturn(const FunctionDecl
   return EntityName(USRBuf.str(), "0", {});
 }
 
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
diff --git a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp 
b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
index 5284a9a87a33a..25785cab0236c 100644
--- a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
+++ b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
@@ -9,8 +9,7 @@
 #include "clang/Analysis/Scalable/Model/BuildNamespace.h"
 #include "llvm/Support/ErrorHandling.h"
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 
 std::string toString(BuildNamespaceKind BNK) {
   switch(BNK) {
@@ -68,5 +67,4 @@ bool NestedBuildNamespace::operator<(const 
NestedBuildNamespace& Other) const {
   return Namespaces < Other.Namespaces;
 }
 
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
diff --git a/clang/lib/Analysis/Scalable/Model/EntityName.cpp 
b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
index 3404ecc58fac2..cc157967937ab 100644
--- a/clang/lib/Analysis/Scalable/Model/EntityName.cpp
+++ b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
@@ -8,8 +8,7 @@
 
 #include "clang/Analysis/Scalable/Model/EntityName.h"
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 
 EntityName::EntityName(llvm::StringRef USR, llvm::StringRef Suffix,
                        NestedBuildNamespace Namespace)
@@ -40,5 +39,4 @@ EntityName EntityName::makeQualified(NestedBuildNamespace 
Namespace) {
   return Copy;
 }
 
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
diff --git a/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp 
b/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
index 8de0df246cb65..555b782e09a06 100644
--- a/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
+++ b/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
@@ -16,8 +16,7 @@
 
 using namespace clang::ast_matchers;
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 namespace {
 
 // Helper function to find a declaration by name
@@ -339,5 +338,4 @@ TEST(ASTEntityMappingTest, FunctionReturnRedeclaration) {
 }
 
 } // namespace
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
diff --git a/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp 
b/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp
index aa4155faa30f8..e62e3257d5608 100644
--- a/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp
+++ b/clang/unittests/Analysis/Scalable/BuildNamespaceTest.cpp
@@ -9,8 +9,7 @@
 #include "clang/Analysis/Scalable/Model/BuildNamespace.h"
 #include "gtest/gtest.h"
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 namespace {
 
 TEST(BuildNamespaceTest, Equality) {
@@ -95,5 +94,4 @@ TEST(NestedBuildNamespaceTest, EmptyQualified) {
 }
 
 } // namespace
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf
diff --git a/clang/unittests/Analysis/Scalable/EntityNameTest.cpp 
b/clang/unittests/Analysis/Scalable/EntityNameTest.cpp
index f32807f3be1c1..0c4ef41a8bf60 100644
--- a/clang/unittests/Analysis/Scalable/EntityNameTest.cpp
+++ b/clang/unittests/Analysis/Scalable/EntityNameTest.cpp
@@ -10,8 +10,7 @@
 #include "clang/Analysis/Scalable/Model/BuildNamespace.h"
 #include "gtest/gtest.h"
 
-namespace clang {
-namespace ssaf {
+namespace clang::ssaf {
 namespace {
 
 TEST(EntityNameTest, Equality) {
@@ -58,5 +57,4 @@ TEST(EntityNameTest, MakeQualified) {
 }
 
 } // namespace
-} // namespace ssaf
-} // namespace clang
+} // namespace clang::ssaf

>From 8da5617ac57d620c4b61f26d319facd40c99f4d4 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Wed, 3 Dec 2025 14:32:47 -0800
Subject: [PATCH 03/10] [clang][ssaf] Return StringRef from
 toString(BuildNamespaceKind)

---
 clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h | 2 +-
 clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
index f409dac272ea1..2abedea24cc19 100644
--- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -21,7 +21,7 @@ enum class BuildNamespaceKind : unsigned short {
   LinkUnit
 };
 
-std::string toString(BuildNamespaceKind BNK);
+llvm::StringRef toString(BuildNamespaceKind BNK);
 
 std::optional<BuildNamespaceKind> parseBuildNamespaceKind(llvm::StringRef Str);
 
diff --git a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp 
b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
index 25785cab0236c..2d0b8aeb49c9a 100644
--- a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
+++ b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
@@ -11,7 +11,7 @@
 
 namespace clang::ssaf {
 
-std::string toString(BuildNamespaceKind BNK) {
+llvm::StringRef toString(BuildNamespaceKind BNK) {
   switch(BNK) {
     case BuildNamespaceKind::CompilationUnit: return "compilation_unit";
     case BuildNamespaceKind::LinkUnit: return "link_unit";

>From 0859de93b5fff9231e80725abe80437c9567845f Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Wed, 3 Dec 2025 14:49:14 -0800
Subject: [PATCH 04/10] [clang][ssaf] Fix header guards

---
 clang/include/clang/Analysis/Scalable/ASTEntityMapping.h    | 6 +++---
 .../include/clang/Analysis/Scalable/Model/BuildNamespace.h  | 6 +++---
 clang/include/clang/Analysis/Scalable/Model/EntityName.h    | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h 
b/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
index d1a5b3790ef50..9a2c01573c4ed 100644
--- a/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
+++ b/clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
@@ -6,8 +6,8 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
-#define LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ASTENTITYMAPPING_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_ASTENTITYMAPPING_H
 
 #include "clang/Analysis/Scalable/Model/EntityName.h"
 #include "clang/AST/Decl.h"
@@ -41,4 +41,4 @@ std::optional<EntityName> 
getLocalEntityNameForFunctionReturn(const FunctionDecl
 
 } // namespace clang::ssaf
 
-#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ASTMAPPING_H
+#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ASTENTITYMAPPING_H
diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
index 2abedea24cc19..0f7ee5da709e8 100644
--- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -6,8 +6,8 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
-#define LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_BUILDNAMESPACE_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_BUILDNAMESPACE_H
 
 #include "llvm/ADT/StringRef.h"
 #include <optional>
@@ -79,4 +79,4 @@ class NestedBuildNamespace {
 
 } // namespace clang::ssaf
 
-#endif // LLVM_CLANG_ANALYSIS_SCALABLE_BUILD_NAMESPACE_H
+#endif // LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_BUILDNAMESPACE_H
diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h 
b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
index f76ac6f99e15a..31c1ef1a69f8e 100644
--- a/clang/include/clang/Analysis/Scalable/Model/EntityName.h
+++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
@@ -6,8 +6,8 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
-#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_ENTITYNAME_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_ENTITYNAME_H
 
 #include "clang/Analysis/Scalable/Model/BuildNamespace.h"
 #include "llvm/ADT/SmallString.h"
@@ -42,4 +42,4 @@ class EntityName {
 
 } // namespace clang::ssaf
 
-#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H
+#endif // LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_ENTITYNAME_H

>From 3ad2d3d217f325d250ee4c5ff857cde36118104a Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Wed, 3 Dec 2025 15:22:09 -0800
Subject: [PATCH 05/10] [clang][ssaf] Optimize
 NestedBuildNamespace::makeQualified

---
 clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
index 0f7ee5da709e8..2a2e090c7fddd 100644
--- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_BUILDNAMESPACE_H
 #define LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_BUILDNAMESPACE_H
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include <optional>
 #include <string>
@@ -62,8 +63,8 @@ class NestedBuildNamespace {
 
   NestedBuildNamespace makeQualified(NestedBuildNamespace Namespace) {
     auto Copy = *this;
-    for (const auto& N : Namespace.Namespaces)
-      Copy.Namespaces.push_back(N);
+    Copy.Namespaces.reserve(Copy.Namespaces.size() + 
Namespace.Namespaces.size());
+    llvm::append_range(Copy.Namespaces, Namespace.Namespaces);
     return Copy;
   }
 

>From 6b840ce6b2523b9f87f45790c9198346c51f3953 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Wed, 3 Dec 2025 15:40:35 -0800
Subject: [PATCH 06/10] [clang][ssaf] Add doc comments to makeQualified methods

---
 clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h | 5 ++++-
 clang/include/clang/Analysis/Scalable/Model/EntityName.h     | 5 ++++-
 clang/lib/Analysis/Scalable/Model/EntityName.cpp             | 2 +-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
index 2a2e090c7fddd..42e8269c352b8 100644
--- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -61,7 +61,10 @@ class NestedBuildNamespace {
 
   static NestedBuildNamespace makeTU(llvm::StringRef CompilationId);
 
-  NestedBuildNamespace makeQualified(NestedBuildNamespace Namespace) {
+  /// Creates a new NestedBuildNamespace by appending additional namespace.
+  ///
+  /// \param Namespace The namespace to append.
+  NestedBuildNamespace makeQualified(NestedBuildNamespace Namespace) const {
     auto Copy = *this;
     Copy.Namespaces.reserve(Copy.Namespaces.size() + 
Namespace.Namespaces.size());
     llvm::append_range(Copy.Namespaces, Namespace.Namespaces);
diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h 
b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
index 31c1ef1a69f8e..61d87f8c5c83d 100644
--- a/clang/include/clang/Analysis/Scalable/Model/EntityName.h
+++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
@@ -34,7 +34,10 @@ class EntityName {
   bool operator!=(const EntityName& Other) const;
   bool operator<(const EntityName& Other) const;
 
-  EntityName makeQualified(NestedBuildNamespace Namespace);
+  /// Creates a new EntityName with additional build namespace qualification.
+  ///
+  /// \param Namespace The namespace steps to append to this entity's 
namespace.
+  EntityName makeQualified(NestedBuildNamespace Namespace) const;
 
   friend class LinkUnitResolution;
   friend class SerializationFormat;
diff --git a/clang/lib/Analysis/Scalable/Model/EntityName.cpp 
b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
index cc157967937ab..14e8d2bb85c9d 100644
--- a/clang/lib/Analysis/Scalable/Model/EntityName.cpp
+++ b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
@@ -32,7 +32,7 @@ bool EntityName::operator<(const EntityName& Other) const {
   return Namespace < Other.Namespace;
 }
 
-EntityName EntityName::makeQualified(NestedBuildNamespace Namespace) {
+EntityName EntityName::makeQualified(NestedBuildNamespace Namespace) const {
   auto Copy = *this;
   Copy.Namespace = Copy.Namespace.makeQualified(Namespace);
 

>From 7467cf7d7efd8e146919bb3f1038a192e3837fa4 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Thu, 4 Dec 2025 16:15:25 -0800
Subject: [PATCH 07/10] [clang][ssaf] Add asTuple helper to EntityName and
 BuildNamespace

---
 .../clang/Analysis/Scalable/Model/BuildNamespace.h   |  3 +++
 .../clang/Analysis/Scalable/Model/EntityName.h       |  2 ++
 clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp |  7 +++----
 clang/lib/Analysis/Scalable/Model/EntityName.cpp     | 12 +++---------
 4 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h 
b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
index 42e8269c352b8..6311d46564985 100644
--- a/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
+++ b/clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
@@ -30,6 +30,9 @@ std::optional<BuildNamespaceKind> 
parseBuildNamespaceKind(llvm::StringRef Str);
 class BuildNamespace {
   BuildNamespaceKind Kind;
   std::string Name;
+
+  auto asTuple() const { return std::tie(Kind, Name); }
+
 public:
   BuildNamespace(BuildNamespaceKind Kind, llvm::StringRef Name)
     : Kind(Kind), Name(Name.str()) {}
diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h 
b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
index 61d87f8c5c83d..ea26d09f3e250 100644
--- a/clang/include/clang/Analysis/Scalable/Model/EntityName.h
+++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h
@@ -26,6 +26,8 @@ class EntityName {
   llvm::SmallString<16> Suffix;
   NestedBuildNamespace Namespace;
 
+  auto asTuple() const { return std::tie(USR, Suffix, Namespace); }
+
 public:
   EntityName(llvm::StringRef USR, llvm::StringRef Suffix,
              NestedBuildNamespace Namespace);
diff --git a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp 
b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
index 2d0b8aeb49c9a..7676d56f867e3 100644
--- a/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
+++ b/clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
@@ -8,6 +8,7 @@
 
 #include "clang/Analysis/Scalable/Model/BuildNamespace.h"
 #include "llvm/Support/ErrorHandling.h"
+#include <tuple>
 
 namespace clang::ssaf {
 
@@ -32,7 +33,7 @@ BuildNamespace BuildNamespace::makeTU(llvm::StringRef 
CompilationId) {
 }
 
 bool BuildNamespace::operator==(const BuildNamespace& Other) const {
-  return Kind == Other.Kind && Name == Other.Name;
+  return asTuple() == Other.asTuple();
 }
 
 bool BuildNamespace::operator!=(const BuildNamespace& Other) const {
@@ -40,9 +41,7 @@ bool BuildNamespace::operator!=(const BuildNamespace& Other) 
const {
 }
 
 bool BuildNamespace::operator<(const BuildNamespace& Other) const {
-  if (Kind != Other.Kind)
-    return Kind < Other.Kind;
-  return Name < Other.Name;
+  return asTuple() < Other.asTuple();
 }
 
 NestedBuildNamespace NestedBuildNamespace::makeTU(llvm::StringRef 
CompilationId) {
diff --git a/clang/lib/Analysis/Scalable/Model/EntityName.cpp 
b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
index 14e8d2bb85c9d..b8c1ba8a052ca 100644
--- a/clang/lib/Analysis/Scalable/Model/EntityName.cpp
+++ b/clang/lib/Analysis/Scalable/Model/EntityName.cpp
@@ -15,21 +15,15 @@ EntityName::EntityName(llvm::StringRef USR, llvm::StringRef 
Suffix,
   : USR(USR.str()), Suffix(Suffix), Namespace(std::move(Namespace)) {}
 
 bool EntityName::operator==(const EntityName& Other) const {
-  return USR == Other.USR &&
-         Suffix == Other.Suffix &&
-         Namespace == Other.Namespace;
+  return asTuple() == Other.asTuple();
 }
 
 bool EntityName::operator!=(const EntityName& Other) const {
   return !(*this == Other);
 }
 
-bool EntityName::operator<(const EntityName& Other) const {
-  if (USR != Other.USR)
-    return USR < Other.USR;
-  if (Suffix != Other.Suffix)
-    return Suffix.str() < Other.Suffix.str();
-  return Namespace < Other.Namespace;
+bool EntityName::operator<(const EntityName &Other) const {
+  return asTuple() < Other.asTuple();
 }
 
 EntityName EntityName::makeQualified(NestedBuildNamespace Namespace) const {

>From 5750baf2d68f3dd3d4d2ed244fa43b130d3edc3d Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Thu, 4 Dec 2025 16:19:56 -0800
Subject: [PATCH 08/10] [clang][ssaf] Simplify AST node type check with isa<>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Balázs Benics <[email protected]>
---
 clang/lib/Analysis/Scalable/ASTEntityMapping.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp 
b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
index a82369c1c471e..60d44e06e5e12 100644
--- a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
+++ b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
@@ -28,8 +28,7 @@ std::optional<EntityName> getLocalEntityNameForDecl(const 
Decl* D) {
   if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->getBuiltinID())
     return std::nullopt;
 
-  if (!isa<FunctionDecl>(D) && !isa<ParmVarDecl>(D) && !isa<VarDecl>(D) &&
-      !isa<FieldDecl>(D) && !isa<RecordDecl>(D))
+  if (!isa<FunctionDecl, ParmVarDecl, VarDecl, FieldDecl, RecordDecl>(D))
     return std::nullopt;
 
   llvm::SmallString<16> Suffix;

>From c25b2bf5afb4d5a5c6662d06f88659947537f974 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Thu, 4 Dec 2025 16:24:45 -0800
Subject: [PATCH 09/10] [clang][ssaf] Add default value param names
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Balázs Benics <[email protected]>
---
 clang/lib/Analysis/Scalable/ASTEntityMapping.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp 
b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
index 60d44e06e5e12..35ff8fa167d58 100644
--- a/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
+++ b/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
@@ -76,7 +76,7 @@ std::optional<EntityName> 
getLocalEntityNameForFunctionReturn(const FunctionDecl
   if (USRBuf.empty())
     return std::nullopt;
 
-  return EntityName(USRBuf.str(), "0", {});
+  return EntityName(USRBuf.str(), /*Suffix=*/"0", /*Namespace=*/{});
 }
 
 } // namespace clang::ssaf

>From 325f74d3737ebb2b25a9346dac715e3f09fc9fc5 Mon Sep 17 00:00:00 2001
From: Jan Korous <[email protected]>
Date: Thu, 4 Dec 2025 16:46:15 -0800
Subject: [PATCH 10/10] [clang][ssaf][NFC] Make test helper to return canonical
 decl

---
 clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp 
b/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
index 555b782e09a06..47226f385597f 100644
--- a/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
+++ b/clang/unittests/Analysis/Scalable/ASTEntityMappingTest.cpp
@@ -26,7 +26,9 @@ const DeclType *findDecl(ASTContext &Ctx, StringRef Name) {
   auto Matches = match(Matcher, Ctx);
   if (Matches.empty())
     return nullptr;
-  return Matches[0].getNodeAs<DeclType>("decl");
+  if (auto Result = Matches[0].getNodeAs<DeclType>("decl"))
+    return dyn_cast<DeclType>(Result->getCanonicalDecl());
+  return nullptr;
 }
 
 TEST(ASTEntityMappingTest, FunctionDecl) {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to