Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions clang/include/clang/Analysis/Scalable/ASTEntityMapping.h
Original file line number Diff line number Diff line change
@@ -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
84 changes: 84 additions & 0 deletions clang/include/clang/Analysis/Scalable/Model/BuildNamespace.h
Original file line number Diff line number Diff line change
@@ -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
47 changes: 47 additions & 0 deletions clang/include/clang/Analysis/Scalable/Model/EntityName.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions clang/lib/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ add_clang_library(clangAnalysis
add_subdirectory(plugins)
add_subdirectory(FlowSensitive)
add_subdirectory(LifetimeSafety)
add_subdirectory(Scalable)
85 changes: 85 additions & 0 deletions clang/lib/Analysis/Scalable/ASTEntityMapping.cpp
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions clang/lib/Analysis/Scalable/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
72 changes: 72 additions & 0 deletions clang/lib/Analysis/Scalable/Model/BuildNamespace.cpp
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading