Merge "Split ast frontend and ast processing." am: 3646941fc6 am: 9ef644da11

am: dd0b9930ce

Change-Id: I99e85c172706acd7fef56af5a6f1ac75c83c4cbd
This commit is contained in:
Jayant Chowdhary
2017-01-14 00:34:45 +00:00
committed by android-build-merger
9 changed files with 124 additions and 194 deletions

View File

@@ -77,14 +77,14 @@ cc_defaults {
}
cc_binary_host {
name: "header-checker",
name: "header-abi-dumper",
defaults: [
"header-checker-defaults",
"header-checker-lib-debug-defaults",
],
srcs: ["src/*.cpp"],
srcs: ["header-abi-dumper/src/*.cpp"],
target: {
windows: {

View File

@@ -0,0 +1,37 @@
#include "ast_processing.h"
bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
llvm::errs() << "struct: " << decl->getName() << "\n";
return true;
}
bool HeaderASTVisitor::VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) {
llvm::errs() << "class: " << decl->getName() << "\n";
return true;
}
bool HeaderASTVisitor::VisitFunctionDecl(const clang::FunctionDecl *decl) {
llvm::errs() << "func: " << decl->getName() << "\n";
return true;
}
void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
llvm::errs() << "HandleTranslationUnit ------------------------------\n";
clang::TranslationUnitDecl* translation_unit = ctx.getTranslationUnitDecl();
HeaderASTVisitor v;
v.TraverseDecl(translation_unit);
}
void HeaderASTConsumer::HandleVTable(clang::CXXRecordDecl *crd) {
llvm::errs() << "HandleVTable: " << crd->getName() << "\n";
}
llvm::StringRef HeaderASTPPCallbacks::ToString(const clang::Token &tok) {
return tok.getIdentifierInfo()->getName();
}
void HeaderASTPPCallbacks::MacroDefined(const clang::Token &macro_name_tok,
const clang::MacroDirective *) {
assert(macro_name_tok.isAnyIdentifier());
llvm::errs() << "defines: " << ToString(macro_name_tok) << "\n";
}

View File

@@ -0,0 +1,28 @@
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Lex/PPCallbacks.h>
#include <clang/Lex/Preprocessor.h>
class HeaderASTVisitor
: public clang::RecursiveASTVisitor<HeaderASTVisitor> {
public:
bool VisitRecordDecl(const clang::RecordDecl *decl);
bool VisitCXXRecordDecl(const clang::CXXRecordDecl *decl);
bool VisitFunctionDecl(const clang::FunctionDecl *decl);
};
class HeaderASTConsumer : public clang::ASTConsumer {
public:
void HandleTranslationUnit(clang::ASTContext &ctx) override;
void HandleVTable(clang::CXXRecordDecl *crd) override;
};
class HeaderASTPPCallbacks : public clang::PPCallbacks {
private:
llvm::StringRef ToString(const clang::Token &tok);
public:
void MacroDefined(const clang::Token &macro_name_tok,
const clang::MacroDirective *) override;
};

View File

@@ -0,0 +1,47 @@
// 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 "frontend_action.h"
#include "ast_processing.h"
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/MultiplexConsumer.h>
#include <clang/Lex/Token.h>
#include <clang/Serialization/ASTWriter.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/Support/raw_ostream.h>
#include <memory>
#include <string>
HeaderCheckerFrontendAction::HeaderCheckerFrontendAction(
const std::string &dump_name)
: dump_name_(dump_name) {}
std::unique_ptr<clang::ASTConsumer>
HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci,
llvm::StringRef header_file) {
// Add preprocessor callbacks.
clang::Preprocessor &pp = ci.getPreprocessor();
pp.addPPCallbacks(llvm::make_unique<HeaderASTPPCallbacks>());
// Create AST consumers.
std::vector<std::unique_ptr<clang::ASTConsumer>> consumers;
consumers.push_back(llvm::make_unique<HeaderASTConsumer>());
// Still have a MultiplexConsumer in case other consumers need to be
// added later.
return llvm::make_unique<clang::MultiplexConsumer>(std::move(consumers));
}

View File

@@ -28,20 +28,12 @@ namespace clang {
class HeaderCheckerFrontendAction : public clang::ASTFrontendAction {
private:
std::string ref_dump_name_;
std::unique_ptr<clang::ASTUnit> ref_dump_;
bool should_generate_ref_dump_;
std::string dump_name_;
public:
HeaderCheckerFrontendAction(const std::string &ref_dump_name,
bool should_generate_ref_dump);
HeaderCheckerFrontendAction(const std::string &dump_name);
protected:
bool BeginSourceFileAction(clang::CompilerInstance &ci,
llvm::StringRef header_file) override;
void EndSourceFileAction() override;
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance &ci, llvm::StringRef header_file) override;
};

View File

@@ -19,11 +19,9 @@
#include <clang/Frontend/FrontendActions.h>
HeaderCheckerFrontendActionFactory::HeaderCheckerFrontendActionFactory(
const std::string &ref_dump_name, bool should_generate_ref_dump)
: ref_dump_name_(ref_dump_name),
should_generate_ref_dump_(should_generate_ref_dump) { }
const std::string &dump_name)
: dump_name_(dump_name) {}
clang::FrontendAction *HeaderCheckerFrontendActionFactory::create() {
return new HeaderCheckerFrontendAction(ref_dump_name_,
should_generate_ref_dump_);
return new HeaderCheckerFrontendAction(dump_name_);
}

View File

@@ -20,12 +20,10 @@
class HeaderCheckerFrontendActionFactory
: public clang::tooling::FrontendActionFactory {
private:
std::string ref_dump_name_;
bool should_generate_ref_dump_;
std::string dump_name_;
public:
HeaderCheckerFrontendActionFactory(const std::string &ref_dump_name,
bool should_generate_ref_dump);
HeaderCheckerFrontendActionFactory(const std::string &ref_dump_name);
clang::FrontendAction *create() override;
};

View File

@@ -34,16 +34,11 @@ static llvm::cl::opt<std::string> header_file(
llvm::cl::Positional, llvm::cl::desc("<header>"), llvm::cl::Required,
llvm::cl::cat(header_checker_category));
static llvm::cl::opt<std::string> ref_dump(
"r", llvm::cl::value_desc("refdump"), llvm::cl::Required,
static llvm::cl::opt<std::string> out_dump(
"o", llvm::cl::value_desc("out_dump"), llvm::cl::Required,
llvm::cl::desc("Specify the reference dump file name"),
llvm::cl::cat(header_checker_category));
static llvm::cl::opt<bool> gen_ref_dump(
"g", llvm::cl::init(false),
llvm::cl::desc("Generate reference dump for header file"),
llvm::cl::cat(header_checker_category));
// Hide irrelevant command line options defined in LLVM libraries.
static void HideIrrelevantCommandLineOptions() {
llvm::StringMap<llvm::cl::Option *> &map = llvm::cl::getRegisteredOptions();
@@ -75,11 +70,6 @@ int main(int argc, const char **argv) {
::exit(1);
}
if (!gen_ref_dump && !llvm::sys::fs::exists(ref_dump)) {
llvm::errs() << "ERROR: Reference file \"" << ref_dump << "\" not found\n";
::exit(1);
}
// Check the availability of clang compilation options.
if (!compilations) {
llvm::errs() << "ERROR: Clang compilation options not specified.\n";
@@ -92,7 +82,7 @@ int main(int argc, const char **argv) {
clang::tooling::ClangTool tool(*compilations, header_files);
std::unique_ptr<clang::tooling::FrontendActionFactory> factory(
new HeaderCheckerFrontendActionFactory(ref_dump, gen_ref_dump));
new HeaderCheckerFrontendActionFactory(out_dump));
return tool.run(factory.get());
}

View File

@@ -1,160 +0,0 @@
// 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 "frontend_action.h"
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/MultiplexConsumer.h>
#include <clang/Lex/PPCallbacks.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/Token.h>
#include <clang/Serialization/ASTWriter.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/Support/raw_ostream.h>
#include <memory>
#include <string>
static constexpr bool kLoadRefAsImplicitPCH = false;
class HeaderCheckVisitor
: public clang::RecursiveASTVisitor<HeaderCheckVisitor> {
public:
bool VisitRecordDecl(const clang::RecordDecl *decl) {
llvm::errs() << "struct: " << decl->getName() << "\n";
return true;
}
bool VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) {
llvm::errs() << "class: " << decl->getName() << "\n";
return true;
}
bool VisitFunctionDecl(const clang::FunctionDecl *decl) {
llvm::errs() << "func: " << decl->getName() << "\n";
return true;
}
};
class HeaderCheckerConsumer : public clang::ASTConsumer {
public:
void HandleTranslationUnit(clang::ASTContext &ctx) override {
llvm::errs() << "HandleTranslationUnit ------------------------------\n";
clang::TranslationUnitDecl* translation_unit = ctx.getTranslationUnitDecl();
HeaderCheckVisitor v;
v.TraverseDecl(translation_unit);
}
void HandleVTable(clang::CXXRecordDecl *crd) override {
llvm::errs() << "HandleVTable: " << crd->getName() << "\n";
}
};
class HeaderCheckerPPCallbacks : public clang::PPCallbacks {
private:
llvm::StringRef ToString(const clang::Token &tok) {
return tok.getIdentifierInfo()->getName();
}
public:
void MacroDefined(const clang::Token &macro_name_tok,
const clang::MacroDirective *) override {
assert(macro_name_tok.isAnyIdentifier());
llvm::errs() << "defines: " << ToString(macro_name_tok) << "\n";
}
};
HeaderCheckerFrontendAction::HeaderCheckerFrontendAction(
const std::string &ref_dump_name, bool should_generate_ref_dump)
: ref_dump_name_(ref_dump_name),
should_generate_ref_dump_(should_generate_ref_dump) { }
static bool VisitRefDumpDecls(void *ctx, const clang::Decl *decl) {
HeaderCheckVisitor v;
v.TraverseDecl(const_cast<clang::Decl *>(decl));
return true;
}
bool HeaderCheckerFrontendAction::BeginSourceFileAction(
clang::CompilerInstance &ci, llvm::StringRef header_file) {
// Load reference dump file.
if (llvm::sys::fs::exists(ref_dump_name_)) {
if (kLoadRefAsImplicitPCH) {
ci.getPreprocessorOpts().ImplicitPCHInclude = ref_dump_name_;
} else {
clang::DiagnosticsEngine &diag = ci.getDiagnostics();
diag.getClient()->BeginSourceFile(ci.getLangOpts(),
&ci.getPreprocessor());
// FIXME: Must replace getPCHContainerReader() with other ASTReader.
ref_dump_ = clang::ASTUnit::LoadFromASTFile(
ref_dump_name_, ci.getPCHContainerReader(), &diag,
ci.getFileSystemOpts(), ci.getCodeGenOpts().DebugTypeExtRefs);
diag.getClient()->EndSourceFile();
if (ref_dump_) {
llvm::errs() << "Loaded: " << ref_dump_name_ << " : "
<< ref_dump_->top_level_size() << "\n";
ref_dump_->visitLocalTopLevelDecls(nullptr, VisitRefDumpDecls);
llvm::errs() << "----------------------------------------\n";
}
}
}
return true;
}
void HeaderCheckerFrontendAction::EndSourceFileAction() {
ref_dump_.reset();
}
std::unique_ptr<clang::ASTConsumer>
HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci,
llvm::StringRef header_file) {
// Add preprocessor callbacks.
clang::Preprocessor &pp = ci.getPreprocessor();
pp.addPPCallbacks(llvm::make_unique<HeaderCheckerPPCallbacks>());
// Create AST consumers.
std::vector<std::unique_ptr<clang::ASTConsumer>> consumers;
consumers.push_back(llvm::make_unique<HeaderCheckerConsumer>());
if (should_generate_ref_dump_) {
std::string sysroot;
llvm::raw_pwrite_stream *ref_dump_os = ci.createOutputFile(
ref_dump_name_, true, false, header_file, "", true);
if (!ref_dump_os) {
llvm::errs() << "ERROR: Failed to create reference dump file: "
<< ref_dump_name_ << "\n";
return nullptr;
}
auto buffer = std::make_shared<clang::PCHBuffer>();
consumers.push_back(
llvm::make_unique<clang::PCHGenerator>(
ci.getPreprocessor(), ref_dump_name_, nullptr, "", buffer,
ci.getFrontendOpts().ModuleFileExtensions, false, false));
consumers.push_back(
ci.getPCHContainerWriter().CreatePCHContainerGenerator(
ci, header_file, ref_dump_name_, ref_dump_os, buffer));
}
return llvm::make_unique<clang::MultiplexConsumer>(std::move(consumers));
}