-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[clang][ssaf] Introduce entity abstraction for SSAF #169131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
61f84a4
d1f0e79
8da5617
0859de9
3ad2d3d
6b840ce
7467cf7
5750baf
c25b2bf
325f74d
ffc5104
d488921
df0e696
f7d033b
a7c5aa7
2c8c699
5b514e9
ba89f06
8bde909
4cab5a1
30ac699
97c31ee
140e84f
a6807ee
2fb3d37
db34258
691482c
0bf64a4
e8d8805
8889e79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 { | ||
steakhal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| namespace ssaf { | ||
|
|
||
ymand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// 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 | ||
steakhal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// | ||
| /// 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. | ||
ymand marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// | ||
| /// \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 | ||
| 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 | ||
steakhal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| #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); | ||
steakhal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 | ||
| 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. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have some concerns about how certain entities will be uniquely identified. There are lots of edge cases as the result of the compilation model of C and C++. Specifically, the same entity might be forward declared in multiple compilation units (in entirely different header files). Do we consider those to be the same entity or not? Or do we only care about complete types? We do not need to answer all of these questions but I think we should start planning around these scenarios early and document the behavior via some test.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a fair amount of complexity in relating entities indeed. |
||
| /// | ||
| /// 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 { | ||
ymand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| std::string USR; | ||
ymand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| llvm::SmallString<16> Suffix; | ||
steakhal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| NestedBuildNamespace Namespace; | ||
ymand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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); | ||
steakhal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| friend class LinkUnitResolution; | ||
| friend class SerializationFormat; | ||
| }; | ||
|
|
||
| } // namespace ssaf | ||
| } // namespace clang | ||
|
|
||
| #endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITY_NAME_H | ||
| 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)) | ||
jkorous-apple marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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", {}); | ||
jkorous-apple marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| } // namespace ssaf | ||
| } // namespace clang | ||
| 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 | ||
| ) |
| 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; | ||
steakhal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| 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 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: header name and the comment does not match.