Improve diagnostic interface

This commit is contained in:
Jonathan Müller 2017-10-12 07:48:20 +02:00
commit 6b55a13a83
5 changed files with 72 additions and 56 deletions

View file

@ -5,6 +5,7 @@
#ifndef CPPAST_DIAGNOSTIC_HPP_INCLUDED
#define CPPAST_DIAGNOSTIC_HPP_INCLUDED
#include <sstream>
#include <string>
#include <type_safe/optional.hpp>
@ -17,30 +18,33 @@ namespace cppast
{
type_safe::optional<std::string> entity;
type_safe::optional<std::string> file;
type_safe::optional<unsigned> line;
type_safe::optional<unsigned> line, column;
/// \returns A source location where all information is available.
static source_location make(std::string entity, std::string file, unsigned line)
static source_location make(std::string entity, std::string file, unsigned line,
unsigned column)
{
return {std::move(entity), std::move(file), line};
return {std::move(entity), std::move(file), line, column};
}
/// \returns A source location where only file and line information is available.
static source_location make_file(std::string file, unsigned line)
/// \returns A source location where only file information is available.
static source_location make_file(std::string file,
type_safe::optional<unsigned> line = type_safe::nullopt,
type_safe::optional<unsigned> column = type_safe::nullopt)
{
return {type_safe::nullopt, std::move(file), line};
}
/// \returns A source location where only the file is available.
static source_location make_file(std::string file)
{
return {type_safe::nullopt, std::move(file), type_safe::nullopt};
return {type_safe::nullopt, std::move(file), line, column};
}
/// \returns A source location where only the entity name is available.
static source_location make_entity(std::string entity)
{
return {std::move(entity), type_safe::nullopt, type_safe::nullopt};
return {std::move(entity), type_safe::nullopt, type_safe::nullopt, type_safe::nullopt};
}
/// \returns A source location where no information is avilable.
static source_location make_unknown()
{
return {type_safe::nullopt, type_safe::nullopt, type_safe::nullopt, type_safe::nullopt};
}
/// \returns A possible string representation of the source location.
@ -51,8 +55,17 @@ namespace cppast
if (file)
{
result += file.value() + ":";
if (line)
result += std::to_string(line.value()) + ":";
{
result += std::to_string(line.value());
if (column)
result += "," + std::to_string(column.value());
result += ":";
}
if (entity)
result += " (" + entity.value() + "):";
}
@ -100,6 +113,27 @@ namespace cppast
source_location location;
cppast::severity severity;
};
namespace detail
{
template <typename... Args>
std::string format(Args&&... args)
{
std::ostringstream stream;
int dummy[] = {(stream << std::forward<Args>(args), 0)...};
(void)dummy;
return stream.str();
}
} // namespace detail
/// Creates a diagnostic.
/// \returns A diagnostic with the specified severity and location.
/// The message is created by streaming each argument in order to a [std::ostringstream]().
template <typename... Args>
diagnostic format_diagnostic(severity sev, source_location loc, Args&&... args)
{
return {detail::format(std::forward<Args>(args)...), std::move(loc), sev};
}
} // namespace cppast
#endif // CPPAST_DIAGNOSTIC_HPP_INCLUDED

View file

@ -6,7 +6,6 @@
#define CPPAST_PARSE_ERROR_HPP_INCLUDED
#include <stdexcept>
#include <sstream>
#include <debug_assert.hpp>
#include <cppast/diagnostic.hpp>
@ -78,15 +77,6 @@ namespace cppast
throw parse_error(type, std::move(message));
}
};
template <typename... Args>
std::string format(Args&&... args)
{
std::ostringstream stream;
int dummy[] = {(stream << std::forward<Args>(args), 0)...};
(void)dummy;
return stream.str();
}
}
} // namespace cppast::detail

View file

@ -113,11 +113,10 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
{
if (context.logger->is_verbose())
{
auto message = detail::format("parsing cursor of type '",
detail::get_cursor_kind_spelling(cur).c_str(), "'");
context.logger->log("libclang parser",
diagnostic{std::move(message), detail::make_location(cur),
severity::debug});
format_diagnostic(severity::debug, detail::make_location(cur),
"parsing cursor of type '",
detail::get_cursor_kind_spelling(cur).c_str(), "'"));
}
auto kind = clang_getCursorKind(cur);
@ -211,8 +210,9 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
auto msg = detail::format("unhandled cursor of kind '",
detail::get_cursor_kind_spelling(cur).c_str(), "'");
context.logger->log("libclang parser",
diagnostic{std::move(msg), detail::make_location(cur),
severity::warning});
format_diagnostic(severity::warning, detail::make_location(cur),
"unhandled cursor of kind '",
detail::get_cursor_kind_spelling(cur).c_str(), "'"));
// build unexposed entity
auto name = detail::get_cursor_name(cur);

View file

@ -102,7 +102,7 @@ namespace
DEBUG_ASSERT(*ptr == ':', detail::assert_handler{});
++ptr;
return {type_safe::nullopt, std::move(filename), std::move(line)};
return {type_safe::nullopt, std::move(filename), std::move(line), type_safe::nullopt};
}
severity parse_severity(const char*& ptr)
@ -708,13 +708,10 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
else if (auto macro = parse_macro(p, result, file_depth == 0u))
{
if (logger.is_verbose())
{
auto message = detail::format("parsing macro '", macro->name(), "'");
logger.log("preprocessor",
diagnostic{std::move(message),
source_location::make_file(path, p.cur_line()),
severity::debug});
}
format_diagnostic(severity::debug,
source_location::make_file(path, p.cur_line()),
"parsing macro '", macro->name(), "'"));
result.macros.push_back({std::move(macro), p.cur_line()});
}
@ -723,13 +720,11 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
if (file_depth == 0u)
{
if (logger.is_verbose())
{
auto message = detail::format("undefining macro '", undef.value(), "'");
logger.log("preprocessor",
diagnostic{std::move(message),
source_location::make_file(path, p.cur_line()),
severity::debug});
}
format_diagnostic(severity::debug,
source_location::make_file(path, p.cur_line()),
"undefining macro '", undef.value(), "'"));
result.macros.erase(std::remove_if(result.macros.begin(), result.macros.end(),
[&](const pp_macro& e) {
return e.macro->name() == undef.value();
@ -740,14 +735,12 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
else if (auto include = parse_include(p, file_depth == 0u))
{
if (logger.is_verbose())
{
auto message =
detail::format("parsing include '", include.value().file.name(), "'");
logger.log("preprocessor",
diagnostic{std::move(message),
source_location::make_file(path, p.cur_line()),
severity::debug});
}
format_diagnostic(severity::debug,
source_location::make_file(path, p.cur_line()),
"parsing include '", include.value().file.name(),
"'"));
result.includes.push_back(std::move(include.value()));
}
else if (bump_pragma(p))

View file

@ -552,12 +552,11 @@ namespace
case CXType_OCLQueue:
case CXType_OCLReserveID:
#endif
{
auto msg = detail::format("unexpected type of kind '",
detail::get_type_kind_spelling(type).c_str(), "'");
auto location = detail::make_location(type);
context.logger->log("libclang parser", diagnostic{msg, location, severity::warning});
}
context.logger->log("libclang parser",
format_diagnostic(severity::warning, detail::make_location(type),
"unexpected type of kind '",
detail::get_type_kind_spelling(type).c_str(),
"'"));
// fallthrough
case CXType_Dependent: // seems to have something to do with expressions, just ignore that (for now?)
case CXType_Unexposed: