diff --git a/include/cppast/parser.hpp b/include/cppast/parser.hpp index 63ac895..5d4abab 100644 --- a/include/cppast/parser.hpp +++ b/include/cppast/parser.hpp @@ -21,7 +21,7 @@ namespace cppast class diagnostic_logger { public: - diagnostic_logger() noexcept : error_(false) + diagnostic_logger() noexcept : verbose_(false) { } @@ -34,15 +34,6 @@ namespace cppast /// \notes `source` points to a string literal that gives additional context to what generates the message. bool log(const char* source, const diagnostic& d) const; - /// \returns Whether or not a diagnostic of [severity::error]() was logged. - /// \notes If an error happens, the parser will still continue to build the AST, - /// unless the error is critical - /// so the result will be incomplete if this function returns `true`. - bool error_logged() const noexcept - { - return error_; - } - /// \effects Sets whether or not the logger prints debugging diagnostics. void set_verbose(bool value) noexcept { @@ -58,8 +49,7 @@ namespace cppast private: virtual bool do_log(const char* source, const diagnostic& d) const = 0; - mutable std::atomic error_; - bool verbose_ = false; + bool verbose_; }; /// A [cppast::diagnostic_logger]() that logs to `stderr`. @@ -86,15 +76,30 @@ namespace cppast /// \returns The [cppast::cpp_file]() object describing it. /// It can be `nullptr`, if there was an error or the specified file already registered in the index. /// \requires The dynamic type of `config` must match the required config type. + /// \notes This function is thread safe. std::unique_ptr parse(const cpp_entity_index& idx, std::string path, const compile_config& config) const { return do_parse(idx, std::move(path), config); } + /// \returns Whether or not an error occurred during parsing. + /// If that happens, the AST might be incomplete. + bool error() const noexcept + { + return error_; + } + + /// \effects Resets the error state. + void reset_error() noexcept + { + error_ = false; + } + protected: /// \effects Creates it giving it a reference to the logger it uses. - explicit parser(type_safe::object_ref logger) : logger_(logger) + explicit parser(type_safe::object_ref logger) + : logger_(logger), error_(false) { } @@ -104,13 +109,22 @@ namespace cppast return *logger_; } + /// \effects Sets the error state. + /// This must be called when an error or critical diagnostic is logged and the AST is incomplete. + void set_error() const noexcept + { + error_ = true; + } + private: /// \effects Parses the given file. /// \returns The [cppast::cpp_file]() object describing it. + /// \requires The function must be thread safe. virtual std::unique_ptr do_parse(const cpp_entity_index& idx, std::string path, const compile_config& config) const = 0; type_safe::object_ref logger_; + mutable std::atomic error_; }; } // namespace cppast diff --git a/src/libclang/enum_parser.cpp b/src/libclang/enum_parser.cpp index 5409c99..95eb886 100644 --- a/src/libclang/enum_parser.cpp +++ b/src/libclang/enum_parser.cpp @@ -94,10 +94,12 @@ std::unique_ptr detail::parse_cpp_enum(const detail::parse_context& } catch (parse_error& ex) { + context.error = true; context.logger->log("libclang parser", ex.get_diagnostic()); } catch (std::logic_error& ex) { + context.error = true; context.logger->log("libclang parser", diagnostic{ex.what(), make_location(child), severity::error}); } diff --git a/src/libclang/function_parser.cpp b/src/libclang/function_parser.cpp index 074823a..b0a4bd4 100644 --- a/src/libclang/function_parser.cpp +++ b/src/libclang/function_parser.cpp @@ -46,10 +46,12 @@ namespace } catch (detail::parse_error& ex) { + context.error = true; context.logger->log("libclang parser", ex.get_diagnostic()); } catch (std::logic_error& ex) { + context.error = true; context.logger->log("libclang parser", diagnostic{ex.what(), detail::make_location(child), severity::error}); diff --git a/src/libclang/libclang_parser.cpp b/src/libclang/libclang_parser.cpp index cafede5..df27ec7 100644 --- a/src/libclang/libclang_parser.cpp +++ b/src/libclang/libclang_parser.cpp @@ -400,8 +400,12 @@ std::unique_ptr libclang_parser::do_parse(const cpp_entity_index& idx, auto include_iter = preprocessed.includes.begin(); // convert entity hierarchies - detail::parse_context context{tu.get(), file, type_safe::ref(logger()), type_safe::ref(idx), - detail::comment_context(preprocessed.comments)}; + detail::parse_context context{tu.get(), + file, + type_safe::ref(logger()), + type_safe::ref(idx), + detail::comment_context(preprocessed.comments), + false}; detail::visit_tu(tu, path.c_str(), [&](const CXCursor& cur) { if (clang_getCursorKind(cur) == CXCursor_InclusionDirective) { @@ -439,10 +443,14 @@ std::unique_ptr libclang_parser::do_parse(const cpp_entity_index& idx, builder.add_unmatched_comment(std::move(c.comment)); } + if (context.error) + set_error(); + return builder.finish(idx); } catch (detail::parse_error& ex) { logger().log("libclang parser", ex.get_diagnostic()); + set_error(); return nullptr; } diff --git a/src/libclang/parse_functions.cpp b/src/libclang/parse_functions.cpp index bdbb68d..c001d51 100644 --- a/src/libclang/parse_functions.cpp +++ b/src/libclang/parse_functions.cpp @@ -230,11 +230,13 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co } catch (parse_error& ex) { + context.error = true; context.logger->log("libclang parser", ex.get_diagnostic()); return nullptr; } catch (std::logic_error& ex) { + context.error = true; context.logger->log("libclang parser", diagnostic{ex.what(), detail::make_location(cur), severity::error}); return nullptr; diff --git a/src/libclang/parse_functions.hpp b/src/libclang/parse_functions.hpp index 4572437..7ef94a1 100644 --- a/src/libclang/parse_functions.hpp +++ b/src/libclang/parse_functions.hpp @@ -62,6 +62,7 @@ namespace cppast type_safe::object_ref logger; type_safe::object_ref idx; comment_context comments; + mutable bool error; }; // parse default value of variable, function parameter... diff --git a/src/parser.cpp b/src/parser.cpp index 64f59a3..05b7789 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -13,9 +13,7 @@ using namespace cppast; bool diagnostic_logger::log(const char* source, const diagnostic& d) const { - if (d.severity == severity::error || d.severity == severity::critical) - error_ = true; - else if (!verbose_ && d.severity == severity::debug) + if (!verbose_ && d.severity == severity::debug) return false; return do_log(source, d); } diff --git a/test/test_parser.hpp b/test/test_parser.hpp index ee38f2e..09ade72 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -36,7 +36,7 @@ inline std::unique_ptr parse_file(const cppast::cpp_entity_ind std::unique_ptr result; REQUIRE_NOTHROW(result = p.parse(idx, name, config)); - REQUIRE(!logger.error_logged()); + REQUIRE(!p.error()); return result; } diff --git a/tool/main.cpp b/tool/main.cpp index 2f90d87..b17ef99 100644 --- a/tool/main.cpp +++ b/tool/main.cpp @@ -180,7 +180,7 @@ std::unique_ptr parse_file(const cppast::libclang_compile_conf cppast::libclang_parser parser(type_safe::ref(logger)); // parse the file auto file = parser.parse(idx, filename, config); - if (fatal_error && logger.error_logged()) + if (fatal_error && parser.error()) return nullptr; return file; }