Skip to content

Commit

Permalink
[InstallAPI] Hookup Input files & basic ASTVisitor (#82552)
Browse files Browse the repository at this point in the history
This patch takes in json files as input to determine that header files
to process, and in which order, to pass along for CC1 invocations. This
patch also includes an ASTVisitor to collect simple global variables.
  • Loading branch information
cyndyishida committed Feb 28, 2024
1 parent ad43ea3 commit c6cbf81
Show file tree
Hide file tree
Showing 12 changed files with 472 additions and 8 deletions.
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

0 comments on commit c6cbf81

Please sign in to comment.