Add parse_error handling
This commit is contained in:
parent
1d083978ca
commit
467936cba4
5 changed files with 89 additions and 17 deletions
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
using namespace cppast;
|
||||
|
||||
detail::cxstring detail::get_display_name(const CXCursor& cur) noexcept
|
||||
{
|
||||
return cxstring(clang_getCursorDisplayName(cur));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::mutex mtx;
|
||||
|
|
@ -19,7 +24,7 @@ namespace
|
|||
void detail::print_cursor_info(const CXCursor& cur) noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
std::printf("[debug] cursor '%s' (%s)\n", cxstring(clang_getCursorDisplayName(cur)).c_str(),
|
||||
std::printf("[debug] cursor '%s' (%s)\n", get_display_name(cur).c_str(),
|
||||
cxstring(clang_getCursorKindSpelling(cur.kind)).c_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ namespace cppast
|
|||
{
|
||||
namespace detail
|
||||
{
|
||||
cxstring get_display_name(const CXCursor& cur) noexcept;
|
||||
|
||||
void print_cursor_info(const CXCursor& cur) noexcept;
|
||||
|
||||
void print_tokens(const cxtranslation_unit& tu, const CXFile& file,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "raii_wrapper.hpp"
|
||||
#include "parse_error.hpp"
|
||||
#include "preprocessor.hpp"
|
||||
#include "tokenizer.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -158,7 +160,7 @@ namespace
|
|||
}
|
||||
|
||||
std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx, std::string path,
|
||||
const compile_config& c) const
|
||||
const compile_config& c) const try
|
||||
{
|
||||
DEBUG_ASSERT(std::strcmp(c.name(), "libclang") == 0, detail::precondition_error_handler{},
|
||||
"config has mismatched type");
|
||||
|
|
@ -167,6 +169,7 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
|
|||
// preprocess + parse
|
||||
auto preprocessed = detail::preprocess(config, path.c_str(), logger());
|
||||
auto tu = get_cxunit(pimpl_->index, config, path.c_str(), preprocessed.source);
|
||||
auto file = clang_getFile(tu.get(), path.c_str());
|
||||
|
||||
// convert entity hierachies
|
||||
cpp_file::builder builder(path);
|
||||
|
|
@ -176,9 +179,12 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
|
|||
for (auto& e : preprocessed.entities)
|
||||
builder.add_child(std::move(e.entity));
|
||||
|
||||
detail::visit_tu(tu, path.c_str(), [&](const CXCursor&) {
|
||||
|
||||
});
|
||||
detail::visit_tu(tu, path.c_str(), [&](const CXCursor&) {});
|
||||
|
||||
return builder.finish(idx);
|
||||
}
|
||||
catch (detail::parse_error& ex)
|
||||
{
|
||||
logger().log("libclang parser", ex.get_diagnostic());
|
||||
return cpp_file::builder(path).finish(idx);
|
||||
}
|
||||
|
|
|
|||
56
src/libclang/parse_error.hpp
Normal file
56
src/libclang/parse_error.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
|
||||
// This file is subject to the license terms in the LICENSE file
|
||||
// found in the top-level directory of this distribution.
|
||||
|
||||
#ifndef CPPAST_PARSE_ERROR_HPP_INCLUDED
|
||||
#define CPPAST_PARSE_ERROR_HPP_INCLUDED
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <debug_assert.hpp>
|
||||
#include <cppast/diagnostic.hpp>
|
||||
|
||||
#include "debug_helper.hpp"
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// thrown on a parsing error
|
||||
// not meant to escape to the user
|
||||
class parse_error : public std::logic_error
|
||||
{
|
||||
public:
|
||||
parse_error(source_location loc, std::string message)
|
||||
: std::logic_error(std::move(message)), location_(std::move(loc))
|
||||
{
|
||||
}
|
||||
|
||||
parse_error(const CXCursor& cur, std::string message)
|
||||
: parse_error(source_location::make(get_display_name(cur).c_str()), std::move(message))
|
||||
{
|
||||
}
|
||||
|
||||
diagnostic get_diagnostic() const
|
||||
{
|
||||
return diagnostic{what(), location_, severity::error};
|
||||
}
|
||||
|
||||
private:
|
||||
source_location location_;
|
||||
};
|
||||
|
||||
// DEBUG_ASSERT handler for parse errors
|
||||
// throws a parse_error exception
|
||||
struct parse_error_handler : debug_assert::set_level<1>, debug_assert::allow_exception
|
||||
{
|
||||
static void handle(const debug_assert::source_location&, const char*,
|
||||
const CXCursor& cur, const char* message)
|
||||
{
|
||||
throw parse_error(cur, message);
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
||||
#endif // CPPAST_PARSE_ERROR_HPP_INCLUDED
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include "tokenizer.hpp"
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "parse_error.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -33,10 +34,12 @@ namespace
|
|||
class simple_tokenizer
|
||||
{
|
||||
public:
|
||||
explicit simple_tokenizer(const CXTranslationUnit& tu, const CXSourceRange& range) : tu_(tu)
|
||||
explicit simple_tokenizer(const CXTranslationUnit& tu, const CXSourceRange& range,
|
||||
const CXCursor& cur)
|
||||
: tu_(tu)
|
||||
{
|
||||
clang_tokenize(tu, range, &tokens_, &no_);
|
||||
DEBUG_ASSERT(no_ >= 1u, detail::assert_handler{});
|
||||
DEBUG_ASSERT(no_ >= 1u, detail::parse_error_handler{}, cur, "no tokens available");
|
||||
}
|
||||
|
||||
~simple_tokenizer()
|
||||
|
|
@ -63,12 +66,12 @@ namespace
|
|||
unsigned no_;
|
||||
};
|
||||
|
||||
bool token_after_is(const CXTranslationUnit& tu, const CXFile& file,
|
||||
bool token_after_is(const CXTranslationUnit& tu, const CXFile& file, const CXCursor& cur,
|
||||
const CXSourceLocation& loc, const char* token_str)
|
||||
{
|
||||
auto loc_after = get_next_location(tu, file, loc);
|
||||
|
||||
simple_tokenizer tokenizer(tu, clang_getRange(loc, loc_after));
|
||||
simple_tokenizer tokenizer(tu, clang_getRange(loc, loc_after), cur);
|
||||
detail::cxstring spelling(clang_getTokenSpelling(tu, tokenizer[0u]));
|
||||
return spelling == token_str;
|
||||
}
|
||||
|
|
@ -103,13 +106,13 @@ namespace
|
|||
return CXChildVisit_Continue;
|
||||
});
|
||||
|
||||
if (!range_shrunk && !token_after_is(tu, file, end, ";"))
|
||||
if (!range_shrunk && !token_after_is(tu, file, cur, end, ";"))
|
||||
{
|
||||
// we do not have a body, but it is not a declaration either
|
||||
do
|
||||
{
|
||||
end = get_next_location(tu, file, end);
|
||||
} while (!token_after_is(tu, file, end, ";"));
|
||||
} while (!token_after_is(tu, file, cur, end, ";"));
|
||||
}
|
||||
else if (clang_getCursorKind(cur) == CXCursor_CXXMethod)
|
||||
// necessary for some reason
|
||||
|
|
@ -121,7 +124,7 @@ namespace
|
|||
|| clang_getCursorKind(cur) == CXCursor_ParmDecl)
|
||||
{
|
||||
if (clang_getCursorKind(cur) == CXCursor_TemplateTypeParameter
|
||||
&& token_after_is(tu, file, end, "("))
|
||||
&& token_after_is(tu, file, cur, end, "("))
|
||||
{
|
||||
// if you have decltype as default argument for a type template parameter
|
||||
// libclang doesn't include the parameters
|
||||
|
|
@ -130,9 +133,9 @@ namespace
|
|||
for (auto paren_count = 1; paren_count != 0;
|
||||
next = get_next_location(tu, file, next))
|
||||
{
|
||||
if (token_after_is(tu, file, next, "("))
|
||||
if (token_after_is(tu, file, cur, next, "("))
|
||||
++paren_count;
|
||||
else if (token_after_is(tu, file, next, ")"))
|
||||
else if (token_after_is(tu, file, cur, next, ")"))
|
||||
--paren_count;
|
||||
prev = next;
|
||||
}
|
||||
|
|
@ -140,13 +143,13 @@ namespace
|
|||
}
|
||||
}
|
||||
else if (clang_getCursorKind(cur) == CXCursor_TypeAliasDecl
|
||||
&& !token_after_is(tu, file, end, ";"))
|
||||
&& !token_after_is(tu, file, cur, end, ";"))
|
||||
{
|
||||
// type alias tokens don't include everything
|
||||
do
|
||||
{
|
||||
end = get_next_location(tu, file, end);
|
||||
} while (!token_after_is(tu, file, end, ";"));
|
||||
} while (!token_after_is(tu, file, cur, end, ";"));
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +162,7 @@ detail::tokenizer::tokenizer(const detail::cxtranslation_unit& tu, const CXFile&
|
|||
{
|
||||
auto extent = get_extent(tu.get(), file, cur);
|
||||
|
||||
simple_tokenizer tokenizer(tu.get(), extent);
|
||||
simple_tokenizer tokenizer(tu.get(), extent, cur);
|
||||
tokens_.reserve(tokenizer.size());
|
||||
for (auto i = 0u; i != tokenizer.size(); ++i)
|
||||
tokens_.emplace_back(tu, tokenizer[i]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue