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;
|
using namespace cppast;
|
||||||
|
|
||||||
|
detail::cxstring detail::get_display_name(const CXCursor& cur) noexcept
|
||||||
|
{
|
||||||
|
return cxstring(clang_getCursorDisplayName(cur));
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
std::mutex mtx;
|
std::mutex mtx;
|
||||||
|
|
@ -19,7 +24,7 @@ namespace
|
||||||
void detail::print_cursor_info(const CXCursor& cur) noexcept
|
void detail::print_cursor_info(const CXCursor& cur) noexcept
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
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());
|
cxstring(clang_getCursorKindSpelling(cur.kind)).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ namespace cppast
|
||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
cxstring get_display_name(const CXCursor& cur) noexcept;
|
||||||
|
|
||||||
void print_cursor_info(const CXCursor& cur) noexcept;
|
void print_cursor_info(const CXCursor& cur) noexcept;
|
||||||
|
|
||||||
void print_tokens(const cxtranslation_unit& tu, const CXFile& file,
|
void print_tokens(const cxtranslation_unit& tu, const CXFile& file,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@
|
||||||
|
|
||||||
#include "libclang_visitor.hpp"
|
#include "libclang_visitor.hpp"
|
||||||
#include "raii_wrapper.hpp"
|
#include "raii_wrapper.hpp"
|
||||||
|
#include "parse_error.hpp"
|
||||||
#include "preprocessor.hpp"
|
#include "preprocessor.hpp"
|
||||||
|
#include "tokenizer.hpp"
|
||||||
|
|
||||||
using namespace cppast;
|
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,
|
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{},
|
DEBUG_ASSERT(std::strcmp(c.name(), "libclang") == 0, detail::precondition_error_handler{},
|
||||||
"config has mismatched type");
|
"config has mismatched type");
|
||||||
|
|
@ -167,6 +169,7 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
|
||||||
// preprocess + parse
|
// preprocess + parse
|
||||||
auto preprocessed = detail::preprocess(config, path.c_str(), logger());
|
auto preprocessed = detail::preprocess(config, path.c_str(), logger());
|
||||||
auto tu = get_cxunit(pimpl_->index, config, path.c_str(), preprocessed.source);
|
auto tu = get_cxunit(pimpl_->index, config, path.c_str(), preprocessed.source);
|
||||||
|
auto file = clang_getFile(tu.get(), path.c_str());
|
||||||
|
|
||||||
// convert entity hierachies
|
// convert entity hierachies
|
||||||
cpp_file::builder builder(path);
|
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)
|
for (auto& e : preprocessed.entities)
|
||||||
builder.add_child(std::move(e.entity));
|
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);
|
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 "tokenizer.hpp"
|
||||||
|
|
||||||
#include "libclang_visitor.hpp"
|
#include "libclang_visitor.hpp"
|
||||||
|
#include "parse_error.hpp"
|
||||||
|
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
|
|
@ -33,10 +34,12 @@ namespace
|
||||||
class simple_tokenizer
|
class simple_tokenizer
|
||||||
{
|
{
|
||||||
public:
|
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_);
|
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()
|
~simple_tokenizer()
|
||||||
|
|
@ -63,12 +66,12 @@ namespace
|
||||||
unsigned no_;
|
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)
|
const CXSourceLocation& loc, const char* token_str)
|
||||||
{
|
{
|
||||||
auto loc_after = get_next_location(tu, file, loc);
|
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]));
|
detail::cxstring spelling(clang_getTokenSpelling(tu, tokenizer[0u]));
|
||||||
return spelling == token_str;
|
return spelling == token_str;
|
||||||
}
|
}
|
||||||
|
|
@ -103,13 +106,13 @@ namespace
|
||||||
return CXChildVisit_Continue;
|
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
|
// we do not have a body, but it is not a declaration either
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
end = get_next_location(tu, file, end);
|
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)
|
else if (clang_getCursorKind(cur) == CXCursor_CXXMethod)
|
||||||
// necessary for some reason
|
// necessary for some reason
|
||||||
|
|
@ -121,7 +124,7 @@ namespace
|
||||||
|| clang_getCursorKind(cur) == CXCursor_ParmDecl)
|
|| clang_getCursorKind(cur) == CXCursor_ParmDecl)
|
||||||
{
|
{
|
||||||
if (clang_getCursorKind(cur) == CXCursor_TemplateTypeParameter
|
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
|
// if you have decltype as default argument for a type template parameter
|
||||||
// libclang doesn't include the parameters
|
// libclang doesn't include the parameters
|
||||||
|
|
@ -130,9 +133,9 @@ namespace
|
||||||
for (auto paren_count = 1; paren_count != 0;
|
for (auto paren_count = 1; paren_count != 0;
|
||||||
next = get_next_location(tu, file, next))
|
next = get_next_location(tu, file, next))
|
||||||
{
|
{
|
||||||
if (token_after_is(tu, file, next, "("))
|
if (token_after_is(tu, file, cur, next, "("))
|
||||||
++paren_count;
|
++paren_count;
|
||||||
else if (token_after_is(tu, file, next, ")"))
|
else if (token_after_is(tu, file, cur, next, ")"))
|
||||||
--paren_count;
|
--paren_count;
|
||||||
prev = next;
|
prev = next;
|
||||||
}
|
}
|
||||||
|
|
@ -140,13 +143,13 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (clang_getCursorKind(cur) == CXCursor_TypeAliasDecl
|
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
|
// type alias tokens don't include everything
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
end = get_next_location(tu, file, end);
|
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);
|
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);
|
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());
|
tokens_.reserve(tokenizer.size());
|
||||||
for (auto i = 0u; i != tokenizer.size(); ++i)
|
for (auto i = 0u; i != tokenizer.size(); ++i)
|
||||||
tokens_.emplace_back(tu, tokenizer[i]);
|
tokens_.emplace_back(tu, tokenizer[i]);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue