Author: Ziqing Luo Date: 2026-08-29T23:47:00-07:00 New Revision: 14c1facce9540128fce14b8c517f5a4528b936e3
URL: https://github.com/llvm/llvm-project/commit/14c1facce9540128fce14b8c517f5a4528b936e3 DIFF: https://github.com/llvm/llvm-project/commit/14c1facce9540128fce14b8c517f5a4528b936e3.diff LOG: [SSAF] Add APIs for resolving bare EntityNames to qualified EntityNames (#219033) Also give Transformation access to SSAFOptions so that it can use link-unit and compilation-unit IDs to resolve bare EntityNames. first step of rdar://185840466 Added: Modified: clang/include/clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h clang/include/clang/ScalableStaticAnalysis/SourceTransformation/Transformation.h clang/include/clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h clang/lib/ScalableStaticAnalysis/Core/ASTEntityMapping.cpp clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp clang/lib/ScalableStaticAnalysis/Core/Model/BuildNamespace.cpp clang/lib/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.cpp clang/lib/ScalableStaticAnalysis/Frontend/SourceTransformationFrontendAction.cpp clang/lib/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.cpp clang/unittests/ScalableStaticAnalysis/ASTEntityMappingTest.cpp clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp clang/unittests/ScalableStaticAnalysis/SourceTransformation/RegistryTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h b/clang/include/clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h index aa8ce469397a0..4b26fb029d77d 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h @@ -10,6 +10,8 @@ #define LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ASTENTITYMAPPING_H #include "clang/AST/Decl.h" +#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h" +#include "clang/ScalableStaticAnalysis/Core/Model/EntityLinkage.h" #include "clang/ScalableStaticAnalysis/Core/Model/EntityName.h" #include "llvm/ADT/StringRef.h" #include <optional> @@ -42,6 +44,30 @@ std::optional<EntityName> getEntityName(const Decl *D); /// \return An EntityName for the function's return entity. std::optional<EntityName> getEntityNameForReturn(const FunctionDecl *FD); +/// Computes the SSAF linkage of a declaration. +/// +/// \param D The declaration to classify. Must not be null. +EntityLinkageType getLinkageForDecl(const Decl *D); + +/// Returns the EntityName qualified with the build namespaces +/// it would carry after linking into \p LUNamespace. +/// +/// \param D The declaration to map. Must not be null. +/// \param TUNamespace The CompilationUnit namespace of a translation unit. +/// \param LUNamespace The LinkUnit namespace the translation unit links into. +/// \return The qualified EntityName if the declaration can be mapped, +/// std::nullopt otherwise. +std::optional<EntityName> +getQualifiedEntityName(const Decl *D, const NestedBuildNamespace &TUNamespace, + const NestedBuildNamespace &LUNamespace); + +/// Similar to `getQualifiedEntityName`, but for entities of function return +/// values. +std::optional<EntityName> +getQualifiedEntityNameForReturn(const FunctionDecl *FD, + const NestedBuildNamespace &TUNamespace, + const NestedBuildNamespace &LUNamespace); + } // namespace clang::ssaf #endif // LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ASTENTITYMAPPING_H diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h index 2df3ad1c9cf3c..4997e439873c8 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h @@ -17,6 +17,7 @@ #define LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_ENTITYLINKER_H #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/Model/EntityLinkage.h" #include "llvm/Support/Error.h" #include "llvm/TargetParser/Triple.h" #include <cstddef> @@ -31,6 +32,14 @@ class MultiArchStaticLibrary; class StaticLibrary; class TUSummaryEncoding; +/// Computes the build namespace an entity should carry after linking, given its +/// linkage. +NestedBuildNamespace +resolveNamespace(const NestedBuildNamespace &LUNamespace, + const NestedBuildNamespace &TUNamespace, + const NestedBuildNamespace &EntityNamespace, + EntityLinkageType Linkage); + class EntityLinker { LUSummaryEncoding Output; diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h b/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h index 4e4368a06ed89..e29af3bfa26f9 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h @@ -105,6 +105,13 @@ class NestedBuildNamespace { static NestedBuildNamespace makeCompilationUnit(llvm::StringRef CompilationId); + /// Creates a NestedBuildNamespace representing a link unit. + /// + /// \param LinkUnitId The unique identifier for the link unit. + /// \returns A NestedBuildNamespace containing a single LinkUnit + /// BuildNamespace. + static NestedBuildNamespace makeLinkUnit(llvm::StringRef LinkUnitId); + /// Creates a new NestedBuildNamespace by appending additional namespace. /// /// \param Namespace The namespace to append. diff --git a/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/Transformation.h b/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/Transformation.h index fae222cda0e84..5416facab0dd4 100644 --- a/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/Transformation.h +++ b/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/Transformation.h @@ -21,14 +21,17 @@ namespace clang::ssaf { +class SSAFOptions; + class Transformation : public clang::ASTConsumer { public: - Transformation(const WPASuite &Suite, SourceEditEmitter &Edits, - TransformationReportEmitter &Report) - : Suite(Suite), Edits(Edits), Report(Report) {} + Transformation(const WPASuite &Suite, const SSAFOptions &Opts, + SourceEditEmitter &Edits, TransformationReportEmitter &Report) + : Suite(Suite), Opts(Opts), Edits(Edits), Report(Report) {} protected: const WPASuite &Suite; + const SSAFOptions &Opts; SourceEditEmitter &Edits; TransformationReportEmitter &Report; }; diff --git a/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h b/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h index eefb841af4fe3..2663d42481338 100644 --- a/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h +++ b/clang/include/clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h @@ -48,7 +48,7 @@ bool isTransformationRegistered(llvm::StringRef Name); /// It's a fatal error if there is no transformation registered with the name. std::unique_ptr<Transformation> makeTransformation(llvm::StringRef Name, const WPASuite &Suite, - SourceEditEmitter &Edits, + const SSAFOptions &Opts, SourceEditEmitter &Edits, TransformationReportEmitter &Report); /// Print the list of available Transformations. @@ -56,8 +56,8 @@ void printAvailableTransformations(llvm::raw_ostream &OS); // Registry for adding new Transformation implementations. using TransformationRegistry = - llvm::Registry<Transformation, const WPASuite &, SourceEditEmitter &, - TransformationReportEmitter &>; + llvm::Registry<Transformation, const WPASuite &, const SSAFOptions &, + SourceEditEmitter &, TransformationReportEmitter &>; } // namespace clang::ssaf diff --git a/clang/lib/ScalableStaticAnalysis/Core/ASTEntityMapping.cpp b/clang/lib/ScalableStaticAnalysis/Core/ASTEntityMapping.cpp index 1f4bf0da274ed..6bbb4ef6f18e0 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/ASTEntityMapping.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/ASTEntityMapping.cpp @@ -12,9 +12,11 @@ #include "clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h" #include "clang/AST/Decl.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.h" #include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h" #include "clang/UnifiedSymbolResolution/USRGeneration.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" namespace clang::ssaf { @@ -80,4 +82,66 @@ std::optional<EntityName> getEntityNameForReturn(const FunctionDecl *FD) { return EntityName(USRBuf.str(), /*Suffix=*/"0", /*Namespace=*/{}); } +EntityLinkageType getLinkageForDecl(const Decl *D) { + const auto *ND = dyn_cast<NamedDecl>(D); + if (!ND) + return EntityLinkageType::None; + + // Parameters have no linkage in C++, but SSAF needs them to inherit + // the external linkage from their parent functions. + // Here is why: + // SSAF treats parameters as entities and may not always associate them back + // to their parent functions. Therefore, it needs to identify parameters of + // functions with external linkage across diff erent TUs. Treating them as + // having no linkage (as in C++) causes the same parameter in diff erent TUs + // to be assigned diff erent EntityIDs. As a result, the behavior of the + // parameter across multiple TUs cannot be correlated. + if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>( + PVD->getParentFunctionOrMethod())) { + return getLinkageForDecl(FD); + } + } + + switch (ND->getFormalLinkage()) { + case Linkage::Invalid: { + llvm_unreachable("Shouldn't be invalid"); + } + case Linkage::None: + return EntityLinkageType::None; + case Linkage::Internal: + return EntityLinkageType::Internal; + case Linkage::UniqueExternal: + return EntityLinkageType::Internal; + case Linkage::VisibleNone: + return EntityLinkageType::Internal; + case Linkage::Module: + return EntityLinkageType::External; + case Linkage::External: + return EntityLinkageType::External; + } + llvm_unreachable("Unhandled clang::Linkage kind"); +} + +std::optional<EntityName> +getQualifiedEntityName(const Decl *D, const NestedBuildNamespace &TUNamespace, + const NestedBuildNamespace &LUNamespace) { + std::optional<EntityName> Name = getEntityName(D); + if (!Name) + return std::nullopt; + return Name->makeQualified(resolveNamespace( + LUNamespace, TUNamespace, /*EntityNamespace=*/{}, getLinkageForDecl(D))); +} + +std::optional<EntityName> +getQualifiedEntityNameForReturn(const FunctionDecl *FD, + const NestedBuildNamespace &TUNamespace, + const NestedBuildNamespace &LUNamespace) { + std::optional<EntityName> Name = getEntityNameForReturn(FD); + if (!Name) + return std::nullopt; + return Name->makeQualified(resolveNamespace( + LUNamespace, TUNamespace, /*EntityNamespace=*/{}, getLinkageForDecl(FD))); +} + } // namespace clang::ssaf diff --git a/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp b/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp index b703efd8324fb..ff171f33310ab 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/EntityLinker/EntityLinker.cpp @@ -60,11 +60,11 @@ static constexpr const char *NoMemberForTargetTriple = } // namespace ErrorMessages -static NestedBuildNamespace -resolveNamespace(const NestedBuildNamespace &LUNamespace, - const NestedBuildNamespace &TUNamespace, - const NestedBuildNamespace &EntityNamespace, - EntityLinkageType Linkage) { +NestedBuildNamespace +clang::ssaf::resolveNamespace(const NestedBuildNamespace &LUNamespace, + const NestedBuildNamespace &TUNamespace, + const NestedBuildNamespace &EntityNamespace, + EntityLinkageType Linkage) { switch (Linkage) { case EntityLinkageType::None: case EntityLinkageType::Internal: diff --git a/clang/lib/ScalableStaticAnalysis/Core/Model/BuildNamespace.cpp b/clang/lib/ScalableStaticAnalysis/Core/Model/BuildNamespace.cpp index 345f375788014..a8fa90e509091 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/Model/BuildNamespace.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/Model/BuildNamespace.cpp @@ -44,6 +44,14 @@ NestedBuildNamespace::makeCompilationUnit(llvm::StringRef CompilationId) { return Result; } +NestedBuildNamespace +NestedBuildNamespace::makeLinkUnit(llvm::StringRef LinkUnitId) { + NestedBuildNamespace Result; + Result.Namespaces.push_back( + BuildNamespace(BuildNamespaceKind::LinkUnit, LinkUnitId)); + return Result; +} + bool NestedBuildNamespace::empty() const { return Namespaces.empty(); } bool NestedBuildNamespace::operator==(const NestedBuildNamespace &Other) const { diff --git a/clang/lib/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.cpp b/clang/lib/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.cpp index 40205b90a4eb6..0bce1a1aebf45 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.cpp @@ -19,47 +19,6 @@ using namespace clang; using namespace ssaf; -static EntityLinkageType getLinkageForDecl(const Decl *D) { - const auto *ND = dyn_cast<NamedDecl>(D); - if (!ND) - return EntityLinkageType::None; - - // Parameters have no linkage in C++, but SSAF needs them to inherit - // the external linkage from their parent functions. - // Here is why: - // SSAF treats parameters as entities and may not always associate them back - // to their parent functions. Therefore, it needs to identify parameters of - // functions with external linkage across diff erent TUs. Treating them as - // having no linkage (as in C++) causes the same parameter in diff erent TUs - // to be assigned diff erent EntityIDs. As a result, the behavior of the - // parameter across multiple TUs cannot be correlated. - if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { - if (const auto *FD = llvm::dyn_cast_or_null<FunctionDecl>( - PVD->getParentFunctionOrMethod())) { - return getLinkageForDecl(FD); - } - } - - switch (ND->getFormalLinkage()) { - case Linkage::Invalid: { - llvm_unreachable("Shouldn't be invalid"); - } - case Linkage::None: - return EntityLinkageType::None; - case Linkage::Internal: - return EntityLinkageType::Internal; - case Linkage::UniqueExternal: - return EntityLinkageType::Internal; - case Linkage::VisibleNone: - return EntityLinkageType::Internal; - case Linkage::Module: - return EntityLinkageType::External; - case Linkage::External: - return EntityLinkageType::External; - } - llvm_unreachable("Unhandled clang::Linkage kind"); -} - std::optional<EntityId> TUSummaryExtractor::addEntity(const NamedDecl *D) { auto Name = getEntityName(D); if (!Name) diff --git a/clang/lib/ScalableStaticAnalysis/Frontend/SourceTransformationFrontendAction.cpp b/clang/lib/ScalableStaticAnalysis/Frontend/SourceTransformationFrontendAction.cpp index 4983d5e241e0f..ed8725b6aea24 100644 --- a/clang/lib/ScalableStaticAnalysis/Frontend/SourceTransformationFrontendAction.cpp +++ b/clang/lib/ScalableStaticAnalysis/Frontend/SourceTransformationFrontendAction.cpp @@ -206,7 +206,7 @@ SourceTransformationRunner::SourceTransformationRunner(WPASuite Suite, // their lifetimes — those references are captured in its base ctor. std::vector<std::unique_ptr<ASTConsumer>> Consumers; Consumers.push_back(makeTransformation(Opts.SourceTransformation, this->Suite, - Edits, Report)); + Opts, Edits, Report)); assert(Consumers.front()); MultiplexConsumer::Consumers = std::move(Consumers); } diff --git a/clang/lib/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.cpp b/clang/lib/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.cpp index 6be42cc75b4d8..b5faa4fb59fa4 100644 --- a/clang/lib/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.cpp +++ b/clang/lib/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.cpp @@ -28,11 +28,11 @@ bool ssaf::isTransformationRegistered(llvm::StringRef Name) { std::unique_ptr<Transformation> ssaf::makeTransformation(llvm::StringRef Name, const WPASuite &Suite, - SourceEditEmitter &Edits, + const SSAFOptions &Opts, SourceEditEmitter &Edits, TransformationReportEmitter &Report) { for (const auto &Entry : TransformationRegistry::entries()) if (Entry.getName() == Name) - return Entry.instantiate(Suite, Edits, Report); + return Entry.instantiate(Suite, Opts, Edits, Report); assert(false && "Unknown Transformation name"); return nullptr; } diff --git a/clang/unittests/ScalableStaticAnalysis/ASTEntityMappingTest.cpp b/clang/unittests/ScalableStaticAnalysis/ASTEntityMappingTest.cpp index c34e92cb9fa5d..b272ab7a51790 100644 --- a/clang/unittests/ScalableStaticAnalysis/ASTEntityMappingTest.cpp +++ b/clang/unittests/ScalableStaticAnalysis/ASTEntityMappingTest.cpp @@ -13,6 +13,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" @@ -337,5 +338,38 @@ TEST(ASTEntityMappingTest, FunctionReturnRedeclaration) { } } +// getQualifiedEntityName / getQualifiedEntityNameForReturn tests + +TEST(ASTEntityMappingTest, QualifiedNameFollowsLinkage) { + auto AST = tooling::buildASTFromCode(R"cpp( + void ext() {} + static void internal() {} + )cpp"); + auto &Ctx = AST->getASTContext(); + + const auto *Ext = findFnByName("ext", Ctx); + const auto *Internal = findFnByName("internal", Ctx); + ASSERT_TRUE(Ext); + ASSERT_TRUE(Internal); + + auto TUNamespace = NestedBuildNamespace::makeCompilationUnit("tu1.cpp"); + auto LUNamespace = NestedBuildNamespace::makeLinkUnit("lu1"); + auto BareExt = getEntityName(Ext); + auto BareInternal = getEntityName(Internal); + auto BareExtReturn = getEntityNameForReturn(Ext); + ASSERT_TRUE(BareExt && BareInternal && BareExtReturn); + + // External linkage is qualified with the LU namespace only, not the TU's. + ASSERT_TRUE(getQualifiedEntityName(Ext, TUNamespace, LUNamespace) == + BareExt->makeQualified(LUNamespace)); + // Internal linkage is qualified with the TU namespace first, then the LU's. + ASSERT_TRUE( + getQualifiedEntityName(Internal, TUNamespace, LUNamespace) == + BareInternal->makeQualified(TUNamespace).makeQualified(LUNamespace)); + // getQualifiedEntityNameForReturn follows the same linkage-based rule. + ASSERT_TRUE(getQualifiedEntityNameForReturn(Ext, TUNamespace, LUNamespace) == + BareExtReturn->makeQualified(LUNamespace)); +} + } // namespace } // namespace clang::ssaf diff --git a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp index a04070c50270a..5f44260612404 100644 --- a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp +++ b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/Basic/Sarif.h" +#include "clang/Frontend/SSAFOptions.h" #include "clang/ScalableStaticAnalysis/Analyses/EntityPointerLevel/EntityPointerLevel.h" #include "clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h" #include "clang/ScalableStaticAnalysis/Core/ASTEntityMapping.h" @@ -120,7 +121,8 @@ class CppBoundedBuffersTest : public TestFixture { RecordingEditEmitter Edits; RecordingReportEmitter Report; - CppBoundedBuffers(Suite, Edits, Report).HandleTranslationUnit(Ctx); + SSAFOptions Opts; + CppBoundedBuffers(Suite, Opts, Edits, Report).HandleTranslationUnit(Ctx); tooling::Replacements Replacements; for (const tooling::Replacement &R : Edits.Replacements) diff --git a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/RegistryTest.cpp b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/RegistryTest.cpp index 3fa24920c20a4..c8b45ca890cea 100644 --- a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/RegistryTest.cpp +++ b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/RegistryTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "TestFixture.h" +#include "clang/Frontend/SSAFOptions.h" #include "clang/ScalableStaticAnalysis/SourceTransformation/Transformation.h" #include "clang/ScalableStaticAnalysis/SourceTransformation/TransformationRegistry.h" #include "llvm/ADT/STLExtras.h" @@ -52,10 +53,11 @@ TEST_F(TransformationRegistryTest, isTransformationRegistered) { TEST_F(TransformationRegistryTest, makeTransformation) { WPASuite Suite = makeWPASuite(); + SSAFOptions Opts; StubEditEmitter Edits; StubReportEmitter Report; std::unique_ptr<Transformation> T = - makeTransformation("stub-transformation", Suite, Edits, Report); + makeTransformation("stub-transformation", Suite, Opts, Edits, Report); EXPECT_NE(T, nullptr); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
