diff --git a/vndk/tools/header-checker/Android.bp b/vndk/tools/header-checker/Android.bp index 8e0ba1132..4fa4d5238 100644 --- a/vndk/tools/header-checker/Android.bp +++ b/vndk/tools/header-checker/Android.bp @@ -55,6 +55,7 @@ cc_binary_host { srcs: [ "header-abi-dumper/src/abi_wrappers.cpp", "header-abi-dumper/src/ast_processing.cpp", + "header-abi-dumper/src/diagnostic_consumer.cpp", "header-abi-dumper/src/fixed_argv.cpp", "header-abi-dumper/src/frontend_action.cpp", "header-abi-dumper/src/frontend_action_factory.cpp", diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp index ec2aa1e38..c7c8ff992 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp +++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp @@ -47,6 +47,10 @@ HeaderASTVisitor::HeaderASTVisitor( ast_caches_(ast_caches) {} bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) { + // Avoid segmentation fault in getASTRecordLayout. + if (decl->isInvalidDecl()) { + return true; + } // Skip forward declarations, dependent records. Also skip anonymous records // as they will be traversed through record fields. if (!decl->isThisDeclarationADefinition() || @@ -176,14 +180,8 @@ bool HeaderASTVisitor::TraverseDecl(clang::Decl *decl) { } HeaderASTConsumer::HeaderASTConsumer( - clang::CompilerInstance *compiler_instancep, - const std::string &out_dump_name, - std::set &exported_headers, - abi_util::TextFormatIR text_format) - : cip_(compiler_instancep), - out_dump_name_(out_dump_name), - exported_headers_(exported_headers), - text_format_(text_format) {} + clang::CompilerInstance *compiler_instancep, HeaderCheckerOptions &options) + : cip_(compiler_instancep), options_(options) {} void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) { clang::PrintingPolicy policy(ctx.getPrintingPolicy()); @@ -198,13 +196,15 @@ void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) { 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); + if (!options_.exported_headers_.empty()) { + options_.exported_headers_.insert(translation_unit_source); } std::unique_ptr 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); + abi_util::IRDumper::CreateIRDumper(options_.text_format_, + options_.dump_name_); + HeaderASTVisitor v(mangle_contextp.get(), &ctx, cip_, + options_.exported_headers_, translation_unit, + ir_dumper.get(), &ast_caches); if (!v.TraverseDecl(translation_unit) || !ir_dumper->Dump()) { llvm::errs() << "Serialization to ostream failed\n"; diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h index 2fd14255f..c234db05a 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h +++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h @@ -16,7 +16,7 @@ #define AST_PROCESSING_H_ #include "ast_util.h" -#include "ir_representation.h" +#include "header_checker.h" #include #include @@ -69,17 +69,13 @@ class HeaderASTVisitor class HeaderASTConsumer : public clang::ASTConsumer { public: HeaderASTConsumer(clang::CompilerInstance *compiler_instancep, - const std::string &out_dump_name, - std::set &exported_headers, - abi_util::TextFormatIR text_format); + HeaderCheckerOptions &options); void HandleTranslationUnit(clang::ASTContext &ctx) override; private: clang::CompilerInstance *cip_; - const std::string &out_dump_name_; - std::set &exported_headers_; - abi_util::TextFormatIR text_format_; + HeaderCheckerOptions &options_; }; #endif // AST_PROCESSING_H_ diff --git a/vndk/tools/header-checker/header-abi-dumper/src/diagnostic_consumer.cpp b/vndk/tools/header-checker/header-abi-dumper/src/diagnostic_consumer.cpp new file mode 100644 index 000000000..e99e9b0ce --- /dev/null +++ b/vndk/tools/header-checker/header-abi-dumper/src/diagnostic_consumer.cpp @@ -0,0 +1,64 @@ +// Copyright (C) 2018 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 "diagnostic_consumer.h" + +#include +#include +#include + +HeaderCheckerDiagnosticConsumer::HeaderCheckerDiagnosticConsumer( + std::unique_ptr wrapped) + : wrapped_(std::move(wrapped)) {} + +void HeaderCheckerDiagnosticConsumer::clear() { + // Default implementation resets warning/error count. + DiagnosticConsumer::clear(); + wrapped_->clear(); +} + +void HeaderCheckerDiagnosticConsumer::BeginSourceFile( + const clang::LangOptions &lang_opts, + const clang::Preprocessor *preprocessor) { + wrapped_->BeginSourceFile(lang_opts, preprocessor); +} + +void HeaderCheckerDiagnosticConsumer::EndSourceFile() { + wrapped_->EndSourceFile(); +} + +void HeaderCheckerDiagnosticConsumer::finish() { wrapped_->finish(); } + +bool HeaderCheckerDiagnosticConsumer::IncludeInDiagnosticCounts() const { + return false; +} + +void HeaderCheckerDiagnosticConsumer::HandleDiagnostic( + clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) { + if (level < clang::DiagnosticsEngine::Level::Error) { + return; + } + unsigned id = info.getID(); + if (id == clang::diag::err_pp_hash_error || + id == clang::diag::fatal_too_many_errors) { + return; + } + unsigned category = clang::DiagnosticIDs::getCategoryNumberForDiag(id); + if (category == clang::diag::DiagCat_Semantic_Issue) { + return; + } + // Default implementation increases warning/error count. + DiagnosticConsumer::HandleDiagnostic(level, info); + wrapped_->HandleDiagnostic(level, info); +} diff --git a/vndk/tools/header-checker/header-abi-dumper/src/diagnostic_consumer.h b/vndk/tools/header-checker/header-abi-dumper/src/diagnostic_consumer.h new file mode 100644 index 000000000..927c8caf8 --- /dev/null +++ b/vndk/tools/header-checker/header-abi-dumper/src/diagnostic_consumer.h @@ -0,0 +1,37 @@ +// Copyright (C) 2018 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. + +#ifndef DIAGNOSTIC_CONSUMER_H_ +#define DIAGNOSTIC_CONSUMER_H_ + +#include + +class HeaderCheckerDiagnosticConsumer : public clang::DiagnosticConsumer { + private: + std::unique_ptr wrapped_; + + public: + HeaderCheckerDiagnosticConsumer( + std::unique_ptr wrapped); + void clear() override; + void BeginSourceFile(const clang::LangOptions &lang_opts, + const clang::Preprocessor *preprocessor) override; + void EndSourceFile() override; + void finish() override; + bool IncludeInDiagnosticCounts() const override; + void HandleDiagnostic(clang::DiagnosticsEngine::Level level, + const clang::Diagnostic &info) override; +}; + +#endif // DIAGNOSTIC_CONSUMER_H_ diff --git a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp index 01fc133a5..0bbe8832a 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp +++ b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.cpp @@ -15,6 +15,7 @@ #include "frontend_action.h" #include "ast_processing.h" +#include "diagnostic_consumer.h" #include "header_abi_util.h" #include "ir_representation.h" @@ -25,15 +26,29 @@ #include HeaderCheckerFrontendAction::HeaderCheckerFrontendAction( - const std::string &dump_name, std::set &exported_headers, - abi_util::TextFormatIR text_format) - : dump_name_(dump_name), exported_headers_(exported_headers), - text_format_(text_format) {} + HeaderCheckerOptions &options) + : options_(options) {} std::unique_ptr HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef header_file) { // Create AST consumers. - return llvm::make_unique(&ci, dump_name_, - exported_headers_, text_format_); + return llvm::make_unique(&ci, options_); +} + +bool HeaderCheckerFrontendAction::BeginInvocation(clang::CompilerInstance &ci) { + if (options_.suppress_errors_) { + clang::DiagnosticsEngine &diagnostics = ci.getDiagnostics(); + diagnostics.setClient( + new HeaderCheckerDiagnosticConsumer(diagnostics.takeClient()), + /* ShouldOwnClient */ true); + } + return true; +} + +bool HeaderCheckerFrontendAction::BeginSourceFileAction( + clang::CompilerInstance &ci) { + ci.getPreprocessor().SetSuppressIncludeNotFoundError( + options_.suppress_errors_); + return true; } diff --git a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h index 82b6b648e..166e3b637 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h +++ b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action.h @@ -15,7 +15,7 @@ #ifndef FRONTEND_ACTION_H_ #define FRONTEND_ACTION_H_ -#include "ir_representation.h" +#include "header_checker.h" #include #include @@ -32,19 +32,17 @@ namespace clang { class HeaderCheckerFrontendAction : public clang::ASTFrontendAction { private: - const std::string &dump_name_; - std::set &exported_headers_; - abi_util::TextFormatIR text_format_; + HeaderCheckerOptions &options_; public: - HeaderCheckerFrontendAction( - const std::string &dump_name, - std::set &exported_headers, - abi_util::TextFormatIR text_format); + HeaderCheckerFrontendAction(HeaderCheckerOptions &options); protected: std::unique_ptr CreateASTConsumer( clang::CompilerInstance &ci, llvm::StringRef header_file) override; + + bool BeginInvocation(clang::CompilerInstance &ci) override; + bool BeginSourceFileAction(clang::CompilerInstance &ci) override; }; #endif // FRONTEND_ACTION_H_ diff --git a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.cpp b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.cpp index 27822fe78..bf1448a4e 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.cpp +++ b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.cpp @@ -19,13 +19,9 @@ #include HeaderCheckerFrontendActionFactory::HeaderCheckerFrontendActionFactory( - const std::string &dump_name, - std::set &exported_headers, - abi_util::TextFormatIR text_format) - : dump_name_(dump_name), exported_headers_(exported_headers), - text_format_(text_format) {} + HeaderCheckerOptions &options) + : options_(options) {} clang::FrontendAction *HeaderCheckerFrontendActionFactory::create() { - return new HeaderCheckerFrontendAction(dump_name_, exported_headers_, - text_format_); + return new HeaderCheckerFrontendAction(options_); } diff --git a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.h b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.h index 1688f266c..1f470c950 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.h +++ b/vndk/tools/header-checker/header-abi-dumper/src/frontend_action_factory.h @@ -15,6 +15,7 @@ #ifndef FRONTEND_ACTION_FACTORY_H_ #define FRONTEND_ACTION_FACTORY_H_ +#include "frontend_action.h" #include "ir_representation.h" #include @@ -24,15 +25,10 @@ class HeaderCheckerFrontendActionFactory : public clang::tooling::FrontendActionFactory { private: - const std::string &dump_name_; - std::set &exported_headers_; - abi_util::TextFormatIR text_format_; + HeaderCheckerOptions &options_; public: - HeaderCheckerFrontendActionFactory( - const std::string &dump_name, - std::set &exported_headers, - abi_util::TextFormatIR text_format); + HeaderCheckerFrontendActionFactory(HeaderCheckerOptions &options); clang::FrontendAction *create() override; }; diff --git a/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp b/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp index 02ba155a5..1661634b0 100644 --- a/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp +++ b/vndk/tools/header-checker/header-abi-dumper/src/header_checker.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "header_checker.h" + #include "fixed_argv.h" #include "frontend_action_factory.h" #include "header_abi_util.h" @@ -50,6 +52,11 @@ static llvm::cl::opt no_filter( "no-filter", llvm::cl::desc("Do not filter any abi"), llvm::cl::Optional, llvm::cl::cat(header_checker_category)); +static llvm::cl::opt suppress_errors( + "suppress-errors", + llvm::cl::desc("Suppress preprocess and semantic errors"), + llvm::cl::Optional, llvm::cl::cat(header_checker_category)); + static llvm::cl::opt output_format( "output-format", llvm::cl::desc("Specify format of output dump file"), llvm::cl::values(clEnumValN(abi_util::TextFormatIR::ProtobufTextFormat, @@ -72,7 +79,6 @@ static void HideIrrelevantCommandLineOptions() { } } - int main(int argc, const char **argv) { HideIrrelevantCommandLineOptions(); @@ -124,11 +130,11 @@ int main(int argc, const char **argv) { // Initialize clang tools and run front-end action. std::vector header_files{ header_file }; + HeaderCheckerOptions options(out_dump, std::move(exported_headers), + output_format, suppress_errors); clang::tooling::ClangTool tool(*compilations, header_files); std::unique_ptr factory( - new HeaderCheckerFrontendActionFactory(out_dump, exported_headers, - output_format)); - + new HeaderCheckerFrontendActionFactory(options)); return tool.run(factory.get()); } diff --git a/vndk/tools/header-checker/header-abi-dumper/src/header_checker.h b/vndk/tools/header-checker/header-abi-dumper/src/header_checker.h new file mode 100644 index 000000000..cb695e6d1 --- /dev/null +++ b/vndk/tools/header-checker/header-abi-dumper/src/header_checker.h @@ -0,0 +1,39 @@ +// Copyright (C) 2018 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. + +#ifndef HEADER_CHECKER_H_ +#define HEADER_CHECKER_H_ + +#include "ir_representation.h" + +#include +#include + +class HeaderCheckerOptions { + public: + std::string dump_name_; + std::set exported_headers_; + abi_util::TextFormatIR text_format_; + bool suppress_errors_; + + public: + HeaderCheckerOptions(std::string dump_name, + std::set exported_headers, + abi_util::TextFormatIR text_format, bool suppress_errors) + : dump_name_(std::move(dump_name)), + exported_headers_(std::move(exported_headers)), + text_format_(text_format), suppress_errors_(suppress_errors) {} +}; + +#endif // HEADER_CHECKER_H_