llvm-project/clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
Jan Korous 4c6aa8fd8a
[clang][ssaf] Introduce entity abstraction for SSAF (#169131)
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.
2025-12-10 09:34:40 -08:00

84 lines
2.3 KiB
C++

//===- 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::ssaf {
std::optional<EntityName> getEntityName(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, ParmVarDecl, VarDecl, FieldDecl, 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> getEntityNameForReturn(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(), /*Suffix=*/"0", /*Namespace=*/{});
}
} // namespace clang::ssaf