Skip to content

[InstallAPI] Hookup Input files & basic ASTVisitor #82552

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

Merged
merged 1 commit into from
Feb 28, 2024
Merged
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
22 changes: 20 additions & 2 deletions clang/include/clang/InstallAPI/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#ifndef LLVM_CLANG_INSTALLAPI_CONTEXT_H
#define LLVM_CLANG_INSTALLAPI_CONTEXT_H

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/InstallAPI/HeaderFile.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include "llvm/TextAPI/RecordVisitor.h"
#include "llvm/TextAPI/RecordsSlice.h"
Expand All @@ -24,8 +27,23 @@ struct InstallAPIContext {
/// Library attributes that are typically passed as linker inputs.
llvm::MachO::RecordsSlice::BinaryAttrs BA;

/// Active target triple to parse.
llvm::Triple TargetTriple{};
/// All headers that represent a library.
HeaderSeq InputHeaders;

/// Active language mode to parse in.
Language LangMode = Language::ObjC;

/// Active header access type.
HeaderType Type = HeaderType::Unknown;

/// Active TargetSlice for symbol record collection.
std::shared_ptr<llvm::MachO::RecordsSlice> Slice;

/// FileManager for all I/O operations.
FileManager *FM = nullptr;

/// DiagnosticsEngine for all error reporting.
DiagnosticsEngine *Diags = nullptr;

/// File Path of output location.
llvm::StringRef OutputLoc{};
Expand Down
48 changes: 48 additions & 0 deletions clang/include/clang/InstallAPI/Frontend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//===- InstallAPI/Frontend.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
//
//===----------------------------------------------------------------------===//
///
/// Top level wrappers for InstallAPI frontend operations.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_FRONTEND_H
#define LLVM_CLANG_INSTALLAPI_FRONTEND_H

#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/InstallAPI/Context.h"
#include "clang/InstallAPI/Visitor.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"

namespace clang {
namespace installapi {

/// Create a buffer that contains all headers to scan
/// for global symbols with.
std::unique_ptr<llvm::MemoryBuffer>
createInputBuffer(const InstallAPIContext &Ctx);

class InstallAPIAction : public ASTFrontendAction {
public:
explicit InstallAPIAction(llvm::MachO::RecordsSlice &Records)
: Records(Records) {}

std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override {
return std::make_unique<InstallAPIVisitor>(CI.getASTContext(), Records);
}

private:
llvm::MachO::RecordsSlice &Records;
};
} // namespace installapi
} // namespace clang

#endif // LLVM_CLANG_INSTALLAPI_FRONTEND_H
23 changes: 23 additions & 0 deletions clang/include/clang/InstallAPI/HeaderFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "clang/Basic/LangStandard.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Regex.h"
#include <optional>
#include <string>
Expand All @@ -32,6 +33,20 @@ enum class HeaderType {
Project,
};

inline StringRef getName(const HeaderType T) {
switch (T) {
case HeaderType::Public:
return "Public";
case HeaderType::Private:
return "Private";
case HeaderType::Project:
return "Project";
case HeaderType::Unknown:
return "Unknown";
}
llvm_unreachable("unexpected header type");
}

class HeaderFile {
/// Full input path to header.
std::string FullPath;
Expand All @@ -52,6 +67,14 @@ class HeaderFile {

static llvm::Regex getFrameworkIncludeRule();

HeaderType getType() const { return Type; }
StringRef getIncludeName() const { return IncludeName; }
StringRef getPath() const { return FullPath; }

bool useIncludeName() const {
return Type != HeaderType::Project && !IncludeName.empty();
}

bool operator==(const HeaderFile &Other) const {
return std::tie(Type, FullPath, IncludeName, Language) ==
std::tie(Other.Type, Other.FullPath, Other.IncludeName,
Expand Down
51 changes: 51 additions & 0 deletions clang/include/clang/InstallAPI/Visitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===- InstallAPI/Visitor.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
//
//===----------------------------------------------------------------------===//
///
/// ASTVisitor Interface for InstallAPI frontend operations.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_VISITOR_H
#define LLVM_CLANG_INSTALLAPI_VISITOR_H

#include "clang/AST/Mangle.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendActions.h"
#include "llvm/ADT/Twine.h"
#include "llvm/TextAPI/RecordsSlice.h"

namespace clang {
namespace installapi {

/// ASTVisitor for collecting declarations that represent global symbols.
class InstallAPIVisitor final : public ASTConsumer,
public RecursiveASTVisitor<InstallAPIVisitor> {
public:
InstallAPIVisitor(ASTContext &ASTCtx, llvm::MachO::RecordsSlice &Slice)
: Slice(Slice),
MC(ItaniumMangleContext::create(ASTCtx, ASTCtx.getDiagnostics())),
Layout(ASTCtx.getTargetInfo().getDataLayoutString()) {}
void HandleTranslationUnit(ASTContext &ASTCtx) override;

/// Collect global variables.
bool VisitVarDecl(const VarDecl *D);

private:
std::string getMangledName(const NamedDecl *D) const;
std::string getBackendMangledName(llvm::Twine Name) const;

llvm::MachO::RecordsSlice &Slice;
std::unique_ptr<clang::ItaniumMangleContext> MC;
StringRef Layout;
};

} // namespace installapi
} // namespace clang

#endif // LLVM_CLANG_INSTALLAPI_VISITOR_H
3 changes: 3 additions & 0 deletions clang/lib/InstallAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
set(LLVM_LINK_COMPONENTS
Support
TextAPI
Core
)

add_clang_library(clangInstallAPI
FileList.cpp
Frontend.cpp
HeaderFile.cpp
Visitor.cpp

LINK_LIBS
clangAST
Expand Down
58 changes: 58 additions & 0 deletions clang/lib/InstallAPI/Frontend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===- Frontend.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/InstallAPI/Frontend.h"
#include "clang/AST/Availability.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"

using namespace llvm;
using namespace llvm::MachO;

namespace clang::installapi {

static StringRef getFileExtension(clang::Language Lang) {
switch (Lang) {
default:
llvm_unreachable("Unexpected language option.");
case clang::Language::C:
return ".c";
case clang::Language::CXX:
return ".cpp";
case clang::Language::ObjC:
return ".m";
case clang::Language::ObjCXX:
return ".mm";
}
}

std::unique_ptr<MemoryBuffer> createInputBuffer(const InstallAPIContext &Ctx) {
assert(Ctx.Type != HeaderType::Unknown &&
"unexpected access level for parsing");
SmallString<4096> Contents;
raw_svector_ostream OS(Contents);
for (const HeaderFile &H : Ctx.InputHeaders) {
if (H.getType() != Ctx.Type)
continue;
if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX)
OS << "#include ";
else
OS << "#import ";
if (H.useIncludeName())
OS << "<" << H.getIncludeName() << ">";
else
OS << "\"" << H.getPath() << "\"";
}
if (Contents.empty())
return nullptr;

return llvm::MemoryBuffer::getMemBufferCopy(
Contents, "installapi-includes" + getFileExtension(Ctx.LangMode));
}

} // namespace clang::installapi
94 changes: 94 additions & 0 deletions clang/lib/InstallAPI/Visitor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//===- Visitor.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/InstallAPI/Visitor.h"
#include "clang/AST/Availability.h"
#include "clang/Basic/Linkage.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"

using namespace llvm;
using namespace llvm::MachO;

namespace clang::installapi {

// Exported NamedDecl needs to have externally visibiliy linkage and
// default visibility from LinkageComputer.
static bool isExported(const NamedDecl *D) {
auto LV = D->getLinkageAndVisibility();
return isExternallyVisible(LV.getLinkage()) &&
(LV.getVisibility() == DefaultVisibility);
}

static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal) {
SymbolFlags Result = SymbolFlags::None;
if (WeakDef)
Result |= SymbolFlags::WeakDefined;
if (ThreadLocal)
Result |= SymbolFlags::ThreadLocalValue;

return Result;
}

void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) {
if (ASTCtx.getDiagnostics().hasErrorOccurred())
return;

auto *D = ASTCtx.getTranslationUnitDecl();
TraverseDecl(D);
}

std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const {
SmallString<256> Name;
if (MC->shouldMangleDeclName(D)) {
raw_svector_ostream NStream(Name);
MC->mangleName(D, NStream);
} else
Name += D->getNameAsString();

return getBackendMangledName(Name);
}

std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const {
SmallString<256> FinalName;
Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout));
return std::string(FinalName);
}

/// Collect all global variables.
bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
// Skip function parameters.
if (isa<ParmVarDecl>(D))
return true;

// Skip variables in records. They are handled seperately for C++.
if (D->getDeclContext()->isRecord())
return true;

// Skip anything inside functions or methods.
if (!D->isDefinedOutsideFunctionOrMethod())
return true;

// If this is a template but not specialization or instantiation, skip.
if (D->getASTContext().getTemplateOrSpecializationInfo(D) &&
D->getTemplateSpecializationKind() == TSK_Undeclared)
return true;

// TODO: Capture SourceLocation & Availability for Decls.
const RecordLinkage Linkage =
isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
const bool WeakDef = D->hasAttr<WeakAttr>();
const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
Slice.addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable,
getFlags(WeakDef, ThreadLocal));
return true;
}

} // namespace clang::installapi
5 changes: 5 additions & 0 deletions clang/test/InstallAPI/basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
// CHECK-NOT: warning:

//--- basic_inputs.json
{
"headers": [
],
"version": "3"
}

//--- expected.tbd
{
Expand Down
Loading