This reverts commit fd439e926c.
Bug: 111579848
Test: prebuilts/clang-tools/build-prebuilts.sh
Test: out/soong/dist/bin/header-abi-dumper --help
Change-Id: I6d12f28b0c78418aaa2837eed2a9f7a0d7c9ce32
215 lines
8.0 KiB
C++
215 lines
8.0 KiB
C++
// Copyright (C) 2016 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "ast_processing.h"
|
|
#include "abi_wrappers.h"
|
|
|
|
#include <clang/Lex/Token.h>
|
|
#include <clang/AST/QualTypeNames.h>
|
|
#include <clang/Index/CodegenNameGenerator.h>
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
using abi_wrapper::ABIWrapper;
|
|
using abi_wrapper::FunctionDeclWrapper;
|
|
using abi_wrapper::RecordDeclWrapper;
|
|
using abi_wrapper::EnumDeclWrapper;
|
|
using abi_wrapper::GlobalVarDeclWrapper;
|
|
|
|
HeaderASTVisitor::HeaderASTVisitor(
|
|
clang::MangleContext *mangle_contextp,
|
|
clang::ASTContext *ast_contextp,
|
|
const clang::CompilerInstance *compiler_instance_p,
|
|
const std::set<std::string> &exported_headers,
|
|
const clang::Decl *tu_decl,
|
|
abi_util::IRDumper *ir_dumper,
|
|
ast_util::ASTCaches *ast_caches)
|
|
: mangle_contextp_(mangle_contextp),
|
|
ast_contextp_(ast_contextp),
|
|
cip_(compiler_instance_p),
|
|
exported_headers_(exported_headers),
|
|
tu_decl_(tu_decl),
|
|
ir_dumper_(ir_dumper),
|
|
ast_caches_(ast_caches) { }
|
|
|
|
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
|
|
// Skip forward declarations, dependent records. Also skip anonymous records
|
|
// as they will be traversed through record fields.
|
|
if (!decl->isThisDeclarationADefinition() ||
|
|
decl->getTypeForDecl()->isDependentType() ||
|
|
decl->isAnonymousStructOrUnion() ||
|
|
!decl->hasNameForLinkage() ||
|
|
!decl->isExternallyVisible()) {
|
|
return true;
|
|
}
|
|
RecordDeclWrapper record_decl_wrapper(
|
|
mangle_contextp_, ast_contextp_, cip_, decl, ir_dumper_, ast_caches_);
|
|
return record_decl_wrapper.GetRecordDecl();
|
|
}
|
|
|
|
bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
|
|
if (!decl->isThisDeclarationADefinition() ||
|
|
decl->getTypeForDecl()->isDependentType() ||
|
|
!decl->hasNameForLinkage()) {
|
|
return true;
|
|
}
|
|
EnumDeclWrapper enum_decl_wrapper(
|
|
mangle_contextp_, ast_contextp_, cip_, decl, ir_dumper_, ast_caches_);
|
|
return enum_decl_wrapper.GetEnumDecl();
|
|
}
|
|
|
|
static bool MutateFunctionWithLinkageName(const abi_util::FunctionIR *function,
|
|
abi_util::IRDumper *ir_dumper,
|
|
std::string &linkage_name) {
|
|
auto added_function = std::make_unique<abi_util::FunctionIR>();
|
|
*added_function = *function;
|
|
added_function->SetLinkerSetKey(linkage_name);
|
|
return ir_dumper->AddLinkableMessageIR(added_function.get());
|
|
}
|
|
|
|
static bool AddMangledFunctions(const abi_util::FunctionIR *function,
|
|
abi_util:: IRDumper *ir_dumper,
|
|
std::vector<std::string> &manglings) {
|
|
for (auto &&mangling : manglings) {
|
|
if (!MutateFunctionWithLinkageName(function, ir_dumper, mangling)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool ShouldSkipFunctionDecl(const clang::FunctionDecl *decl) {
|
|
if (!decl->getDefinition()) {
|
|
return true;
|
|
}
|
|
if (decl->getLinkageAndVisibility().getLinkage() !=
|
|
clang::Linkage::ExternalLinkage) {
|
|
return true;
|
|
}
|
|
if (const clang::CXXMethodDecl *method_decl =
|
|
llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
|
|
if (method_decl->getParent()->getTypeForDecl()->isDependentType()) {
|
|
return true;
|
|
}
|
|
}
|
|
clang::FunctionDecl::TemplatedKind tkind = decl->getTemplatedKind();
|
|
switch (tkind) {
|
|
case clang::FunctionDecl::TK_NonTemplate:
|
|
case clang::FunctionDecl::TK_FunctionTemplateSpecialization:
|
|
case clang::FunctionDecl::TK_MemberSpecialization:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
|
|
if (ShouldSkipFunctionDecl(decl)) {
|
|
return true;
|
|
}
|
|
FunctionDeclWrapper function_decl_wrapper(mangle_contextp_, ast_contextp_,
|
|
cip_, decl, ir_dumper_,
|
|
ast_caches_);
|
|
auto function_wrapper = function_decl_wrapper.GetFunctionDecl();
|
|
// Destructors and Constructors can have more than 1 symbol generated from the
|
|
// same Decl.
|
|
clang::index::CodegenNameGenerator cg(*ast_contextp_);
|
|
std::vector<std::string> manglings = cg.getAllManglings(decl);
|
|
if (!manglings.empty()) {
|
|
return AddMangledFunctions(function_wrapper.get(), ir_dumper_, manglings);
|
|
}
|
|
std::string linkage_name =
|
|
ABIWrapper::GetMangledNameDecl(decl, mangle_contextp_);
|
|
return MutateFunctionWithLinkageName(function_wrapper.get(), ir_dumper_,
|
|
linkage_name);
|
|
}
|
|
|
|
bool HeaderASTVisitor::VisitVarDecl(const clang::VarDecl *decl) {
|
|
if(!decl->hasGlobalStorage()||
|
|
decl->getType().getTypePtr()->isDependentType()) {
|
|
// Non global / static variable declarations don't need to be dumped.
|
|
return true;
|
|
}
|
|
GlobalVarDeclWrapper global_var_decl_wrapper(mangle_contextp_, ast_contextp_,
|
|
cip_, decl, ir_dumper_,
|
|
ast_caches_);
|
|
return global_var_decl_wrapper.GetGlobalVarDecl();
|
|
}
|
|
|
|
static bool AreHeadersExported(const std::set<std::string> &exported_headers) {
|
|
return !exported_headers.empty();
|
|
}
|
|
|
|
// We don't need to recurse into Declarations which are not exported.
|
|
bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) {
|
|
if (!decl) {
|
|
return true;
|
|
}
|
|
std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
|
|
ast_caches_->decl_to_source_file_cache_.insert(
|
|
std::make_pair(decl, source_file));
|
|
// If no exported headers are specified we assume the whole AST is exported.
|
|
if ((decl != tu_decl_) && AreHeadersExported(exported_headers_) &&
|
|
(exported_headers_.find(source_file) == exported_headers_.end())) {
|
|
return true;
|
|
}
|
|
// If at all we're looking at the source file's AST decl node, it should be a
|
|
// function decl node.
|
|
if ((decl != tu_decl_) &&
|
|
(source_file == ast_caches_->translation_unit_source_) &&
|
|
!decl->isFunctionOrFunctionTemplate()) {
|
|
return true;
|
|
}
|
|
return RecursiveASTVisitor<HeaderASTVisitor>::TraverseDecl(decl);
|
|
}
|
|
|
|
HeaderASTConsumer::HeaderASTConsumer(
|
|
clang::CompilerInstance *compiler_instancep,
|
|
const std::string &out_dump_name,
|
|
std::set<std::string> &exported_headers,
|
|
abi_util::TextFormatIR text_format)
|
|
: cip_(compiler_instancep),
|
|
out_dump_name_(out_dump_name),
|
|
exported_headers_(exported_headers),
|
|
text_format_(text_format){ }
|
|
|
|
void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
|
|
clang::PrintingPolicy policy(ctx.getPrintingPolicy());
|
|
// Suppress 'struct' keyword for C source files while getting QualType string
|
|
// names to avoid inconsistency between C and C++ (for C++ files, this is true
|
|
// by default)
|
|
policy.SuppressTagKeyword = true;
|
|
ctx.setPrintingPolicy(policy);
|
|
clang::TranslationUnitDecl *translation_unit = ctx.getTranslationUnitDecl();
|
|
std::unique_ptr<clang::MangleContext> mangle_contextp(
|
|
ctx.createMangleContext());
|
|
const std::string &translation_unit_source =
|
|
ABIWrapper::GetDeclSourceFile(translation_unit, cip_);
|
|
ast_util::ASTCaches ast_caches(translation_unit_source);
|
|
if (!exported_headers_.empty()) {
|
|
exported_headers_.insert(translation_unit_source);
|
|
}
|
|
std::unique_ptr<abi_util::IRDumper> ir_dumper =
|
|
abi_util::IRDumper::CreateIRDumper(text_format_, out_dump_name_);
|
|
HeaderASTVisitor v(mangle_contextp.get(), &ctx, cip_, exported_headers_,
|
|
translation_unit, ir_dumper.get(), &ast_caches);
|
|
|
|
if (!v.TraverseDecl(translation_unit) || !ir_dumper->Dump()) {
|
|
llvm::errs() << "Serialization to ostream failed\n";
|
|
::exit(1);
|
|
}
|
|
}
|