Merge "Split ast frontend and ast processing."
am: 3646941fc6
Change-Id: I699a683bce33462127204b6e26a551326f49020b
This commit is contained in:
@@ -77,14 +77,14 @@ cc_defaults {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cc_binary_host {
|
cc_binary_host {
|
||||||
name: "header-checker",
|
name: "header-abi-dumper",
|
||||||
|
|
||||||
defaults: [
|
defaults: [
|
||||||
"header-checker-defaults",
|
"header-checker-defaults",
|
||||||
"header-checker-lib-debug-defaults",
|
"header-checker-lib-debug-defaults",
|
||||||
],
|
],
|
||||||
|
|
||||||
srcs: ["src/*.cpp"],
|
srcs: ["header-abi-dumper/src/*.cpp"],
|
||||||
|
|
||||||
target: {
|
target: {
|
||||||
windows: {
|
windows: {
|
||||||
|
|||||||
@@ -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 ¯o_name_tok,
|
||||||
|
const clang::MacroDirective *) {
|
||||||
|
assert(macro_name_tok.isAnyIdentifier());
|
||||||
|
llvm::errs() << "defines: " << ToString(macro_name_tok) << "\n";
|
||||||
|
}
|
||||||
@@ -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 ¯o_name_tok,
|
||||||
|
const clang::MacroDirective *) override;
|
||||||
|
};
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
@@ -28,20 +28,12 @@ namespace clang {
|
|||||||
|
|
||||||
class HeaderCheckerFrontendAction : public clang::ASTFrontendAction {
|
class HeaderCheckerFrontendAction : public clang::ASTFrontendAction {
|
||||||
private:
|
private:
|
||||||
std::string ref_dump_name_;
|
std::string dump_name_;
|
||||||
std::unique_ptr<clang::ASTUnit> ref_dump_;
|
|
||||||
bool should_generate_ref_dump_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HeaderCheckerFrontendAction(const std::string &ref_dump_name,
|
HeaderCheckerFrontendAction(const std::string &dump_name);
|
||||||
bool should_generate_ref_dump);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool BeginSourceFileAction(clang::CompilerInstance &ci,
|
|
||||||
llvm::StringRef header_file) override;
|
|
||||||
|
|
||||||
void EndSourceFileAction() override;
|
|
||||||
|
|
||||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
||||||
clang::CompilerInstance &ci, llvm::StringRef header_file) override;
|
clang::CompilerInstance &ci, llvm::StringRef header_file) override;
|
||||||
};
|
};
|
||||||
@@ -19,11 +19,9 @@
|
|||||||
#include <clang/Frontend/FrontendActions.h>
|
#include <clang/Frontend/FrontendActions.h>
|
||||||
|
|
||||||
HeaderCheckerFrontendActionFactory::HeaderCheckerFrontendActionFactory(
|
HeaderCheckerFrontendActionFactory::HeaderCheckerFrontendActionFactory(
|
||||||
const std::string &ref_dump_name, bool should_generate_ref_dump)
|
const std::string &dump_name)
|
||||||
: ref_dump_name_(ref_dump_name),
|
: dump_name_(dump_name) {}
|
||||||
should_generate_ref_dump_(should_generate_ref_dump) { }
|
|
||||||
|
|
||||||
clang::FrontendAction *HeaderCheckerFrontendActionFactory::create() {
|
clang::FrontendAction *HeaderCheckerFrontendActionFactory::create() {
|
||||||
return new HeaderCheckerFrontendAction(ref_dump_name_,
|
return new HeaderCheckerFrontendAction(dump_name_);
|
||||||
should_generate_ref_dump_);
|
|
||||||
}
|
}
|
||||||
@@ -20,12 +20,10 @@
|
|||||||
class HeaderCheckerFrontendActionFactory
|
class HeaderCheckerFrontendActionFactory
|
||||||
: public clang::tooling::FrontendActionFactory {
|
: public clang::tooling::FrontendActionFactory {
|
||||||
private:
|
private:
|
||||||
std::string ref_dump_name_;
|
std::string dump_name_;
|
||||||
bool should_generate_ref_dump_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HeaderCheckerFrontendActionFactory(const std::string &ref_dump_name,
|
HeaderCheckerFrontendActionFactory(const std::string &ref_dump_name);
|
||||||
bool should_generate_ref_dump);
|
|
||||||
|
|
||||||
clang::FrontendAction *create() override;
|
clang::FrontendAction *create() override;
|
||||||
};
|
};
|
||||||
@@ -34,16 +34,11 @@ static llvm::cl::opt<std::string> header_file(
|
|||||||
llvm::cl::Positional, llvm::cl::desc("<header>"), llvm::cl::Required,
|
llvm::cl::Positional, llvm::cl::desc("<header>"), llvm::cl::Required,
|
||||||
llvm::cl::cat(header_checker_category));
|
llvm::cl::cat(header_checker_category));
|
||||||
|
|
||||||
static llvm::cl::opt<std::string> ref_dump(
|
static llvm::cl::opt<std::string> out_dump(
|
||||||
"r", llvm::cl::value_desc("refdump"), llvm::cl::Required,
|
"o", llvm::cl::value_desc("out_dump"), llvm::cl::Required,
|
||||||
llvm::cl::desc("Specify the reference dump file name"),
|
llvm::cl::desc("Specify the reference dump file name"),
|
||||||
llvm::cl::cat(header_checker_category));
|
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.
|
// Hide irrelevant command line options defined in LLVM libraries.
|
||||||
static void HideIrrelevantCommandLineOptions() {
|
static void HideIrrelevantCommandLineOptions() {
|
||||||
llvm::StringMap<llvm::cl::Option *> &map = llvm::cl::getRegisteredOptions();
|
llvm::StringMap<llvm::cl::Option *> &map = llvm::cl::getRegisteredOptions();
|
||||||
@@ -75,11 +70,6 @@ int main(int argc, const char **argv) {
|
|||||||
::exit(1);
|
::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.
|
// Check the availability of clang compilation options.
|
||||||
if (!compilations) {
|
if (!compilations) {
|
||||||
llvm::errs() << "ERROR: Clang compilation options not specified.\n";
|
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);
|
clang::tooling::ClangTool tool(*compilations, header_files);
|
||||||
|
|
||||||
std::unique_ptr<clang::tooling::FrontendActionFactory> factory(
|
std::unique_ptr<clang::tooling::FrontendActionFactory> factory(
|
||||||
new HeaderCheckerFrontendActionFactory(ref_dump, gen_ref_dump));
|
new HeaderCheckerFrontendActionFactory(out_dump));
|
||||||
|
|
||||||
return tool.run(factory.get());
|
return tool.run(factory.get());
|
||||||
}
|
}
|
||||||
@@ -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 ¯o_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));
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user