Merge "Split ast frontend and ast processing." am: 3646941fc6 am: 9ef644da11
am: dd0b9930ce
Change-Id: I99e85c172706acd7fef56af5a6f1ac75c83c4cbd
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
};
|
||||
@@ -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_);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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