Fix a couple of bugs
This commit is contained in:
commit
5c5f30aa7a
10 changed files with 189 additions and 66 deletions
|
|
@ -49,7 +49,7 @@ namespace cppast
|
||||||
return semantic_parent_;
|
return semantic_parent_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns The name of the semantic parent, if it has own,
|
/// \returns The name of the semantic parent, if it has one,
|
||||||
/// else the empty string.
|
/// else the empty string.
|
||||||
/// \notes This may include template parameters.
|
/// \notes This may include template parameters.
|
||||||
std::string semantic_scope() const noexcept
|
std::string semantic_scope() const noexcept
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ namespace cppast
|
||||||
static int clang_version(const libclang_compile_config& config);
|
static int clang_version(const libclang_compile_config& config);
|
||||||
|
|
||||||
static const std::vector<std::string>& flags(const libclang_compile_config& config);
|
static const std::vector<std::string>& flags(const libclang_compile_config& config);
|
||||||
|
|
||||||
|
static bool write_preprocessed(const libclang_compile_config& config);
|
||||||
};
|
};
|
||||||
|
|
||||||
void for_each_file(const libclang_compilation_database& database, void* user_data,
|
void for_each_file(const libclang_compilation_database& database, void* user_data,
|
||||||
|
|
@ -34,9 +36,7 @@ namespace cppast
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \effects Creates it with a message.
|
/// \effects Creates it with a message.
|
||||||
libclang_error(std::string msg) : std::runtime_error(std::move(msg))
|
libclang_error(std::string msg) : std::runtime_error(std::move(msg)) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A compilation database.
|
/// A compilation database.
|
||||||
|
|
@ -121,6 +121,13 @@ namespace cppast
|
||||||
clang_version_ = major * 10000 + minor * 100 + patch;
|
clang_version_ = major * 10000 + minor * 100 + patch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Sets whether or not the preprocessed file will be written out.
|
||||||
|
/// Default value is `false`.
|
||||||
|
void write_preprocessed(bool b) noexcept
|
||||||
|
{
|
||||||
|
write_preprocessed_ = b;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void do_set_flags(cpp_standard standard, compile_flags flags) override;
|
void do_set_flags(cpp_standard standard, compile_flags flags) override;
|
||||||
|
|
||||||
|
|
@ -137,6 +144,7 @@ namespace cppast
|
||||||
|
|
||||||
std::string clang_binary_;
|
std::string clang_binary_;
|
||||||
int clang_version_;
|
int clang_version_;
|
||||||
|
bool write_preprocessed_;
|
||||||
|
|
||||||
friend detail::libclang_compile_config_access;
|
friend detail::libclang_compile_config_access;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,15 @@ namespace
|
||||||
detail::skip_brackets(stream);
|
detail::skip_brackets(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<CXCursor> get_semantic_parents(CXCursor cur)
|
||||||
|
{
|
||||||
|
std::vector<CXCursor> result;
|
||||||
|
for (; !clang_isTranslationUnit(clang_getCursorKind(cur));
|
||||||
|
cur = clang_getCursorSemanticParent(cur))
|
||||||
|
result.push_back(cur);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_class(const CXCursor& parent)
|
bool is_class(const CXCursor& parent)
|
||||||
{
|
{
|
||||||
auto kind = clang_getCursorKind(parent);
|
auto kind = clang_getCursorKind(parent);
|
||||||
|
|
@ -108,6 +117,9 @@ namespace
|
||||||
|| kind == CXCursor_ClassTemplatePartialSpecialization;
|
|| kind == CXCursor_ClassTemplatePartialSpecialization;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns the scope where the function is contained in
|
||||||
|
// for regular functions that is the lexcial parent
|
||||||
|
// for friend functions it is the enclosing scope of the class
|
||||||
CXCursor get_definition_scope(const CXCursor& cur, bool is_friend)
|
CXCursor get_definition_scope(const CXCursor& cur, bool is_friend)
|
||||||
{
|
{
|
||||||
auto parent = clang_getCursorLexicalParent(cur);
|
auto parent = clang_getCursorLexicalParent(cur);
|
||||||
|
|
@ -138,25 +150,63 @@ namespace
|
||||||
|
|
||||||
type_safe::optional<cpp_entity_ref> parse_scope(const CXCursor& cur, bool is_friend)
|
type_safe::optional<cpp_entity_ref> parse_scope(const CXCursor& cur, bool is_friend)
|
||||||
{
|
{
|
||||||
std::string scope;
|
std::string scope_name;
|
||||||
// find the semantic parents we need until we're at the same level of the parent where the definition is
|
|
||||||
// the semantic parents are all the scopes that need to be appended
|
auto friended = clang_getCursorReferenced(cur);
|
||||||
for (auto definition = get_definition_scope(cur, is_friend),
|
if (is_friend && !clang_Cursor_isNull(friended))
|
||||||
parent = clang_getCursorSemanticParent(cur);
|
|
||||||
!equivalent_cursor(definition, parent); parent = clang_getCursorSemanticParent(parent))
|
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(parent)),
|
// it refers to another function
|
||||||
|
// find the common parent between the two cursors
|
||||||
|
// scope is the scope from the common parent down to the function
|
||||||
|
|
||||||
|
auto friended_parents = get_semantic_parents(friended);
|
||||||
|
auto cur_parents = get_semantic_parents(get_definition_scope(cur, true));
|
||||||
|
|
||||||
|
// remove common parents
|
||||||
|
while (!friended_parents.empty() && !cur_parents.empty()
|
||||||
|
&& equivalent_cursor(friended_parents.back(), cur_parents.back()))
|
||||||
|
{
|
||||||
|
friended_parents.pop_back();
|
||||||
|
cur_parents.pop_back();
|
||||||
|
}
|
||||||
|
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(friended_parents.back()))
|
||||||
|
&& !friended_parents.empty(),
|
||||||
detail::parse_error_handler{}, cur,
|
detail::parse_error_handler{}, cur,
|
||||||
"infinite loop while calculating scope");
|
"invalid common parent of friend and friended");
|
||||||
auto parent_name = detail::cxstring(clang_getCursorDisplayName(parent));
|
|
||||||
scope = parent_name.std_str() + "::" + std::move(scope);
|
// scope consists of all remaining parents of friended
|
||||||
|
// (last one is cursor itself)
|
||||||
|
for (auto iter = friended_parents.rbegin(); iter != std::prev(friended_parents.rend());
|
||||||
|
++iter)
|
||||||
|
{
|
||||||
|
auto parent_name = detail::cxstring(clang_getCursorDisplayName(*iter));
|
||||||
|
scope_name += parent_name.std_str() + "::";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// find the difference between the definition scope parent and semantic parent
|
||||||
|
// all semantic parents in between form the scope
|
||||||
|
// the definition scope is the lexical parent for regular functions,
|
||||||
|
// and the scope outside of the class for friend functions
|
||||||
|
for (auto definition = get_definition_scope(cur, is_friend),
|
||||||
|
parent = clang_getCursorSemanticParent(cur);
|
||||||
|
!equivalent_cursor(definition, parent);
|
||||||
|
parent = clang_getCursorSemanticParent(parent))
|
||||||
|
{
|
||||||
|
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(parent)),
|
||||||
|
detail::parse_error_handler{}, cur,
|
||||||
|
"infinite loop while calculating scope");
|
||||||
|
auto parent_name = detail::cxstring(clang_getCursorDisplayName(parent));
|
||||||
|
scope_name = parent_name.std_str() + "::" + std::move(scope_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope.empty())
|
if (scope_name.empty())
|
||||||
return type_safe::nullopt;
|
return type_safe::nullopt;
|
||||||
else
|
else
|
||||||
return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||||
std::move(scope));
|
std::move(scope_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// just the tokens occurring in the prefix
|
// just the tokens occurring in the prefix
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <cppast/libclang_parser.hpp>
|
#include <cppast/libclang_parser.hpp>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <clang-c/CXCompilationDatabase.h>
|
#include <clang-c/CXCompilationDatabase.h>
|
||||||
|
|
@ -35,6 +36,12 @@ const std::vector<std::string>& detail::libclang_compile_config_access::flags(
|
||||||
return config.get_flags();
|
return config.get_flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool detail::libclang_compile_config_access::write_preprocessed(
|
||||||
|
const libclang_compile_config& config)
|
||||||
|
{
|
||||||
|
return config.write_preprocessed_;
|
||||||
|
}
|
||||||
|
|
||||||
libclang_compilation_database::libclang_compilation_database(const std::string& build_directory)
|
libclang_compilation_database::libclang_compilation_database(const std::string& build_directory)
|
||||||
{
|
{
|
||||||
static_assert(std::is_same<database, CXCompilationDatabase>::value, "forgot to update type");
|
static_assert(std::is_same<database, CXCompilationDatabase>::value, "forgot to update type");
|
||||||
|
|
@ -74,7 +81,7 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
libclang_compile_config::libclang_compile_config() : compile_config({})
|
libclang_compile_config::libclang_compile_config() : compile_config({}), write_preprocessed_(false)
|
||||||
{
|
{
|
||||||
// set given clang binary
|
// set given clang binary
|
||||||
auto ptr = CPPAST_CLANG_VERSION_STRING;
|
auto ptr = CPPAST_CLANG_VERSION_STRING;
|
||||||
|
|
@ -328,9 +335,7 @@ libclang_parser::libclang_parser(type_safe::object_ref<const diagnostic_logger>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
libclang_parser::~libclang_parser() noexcept
|
libclang_parser::~libclang_parser() noexcept {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
@ -373,10 +378,14 @@ namespace
|
||||||
auto sev = get_severity(diag);
|
auto sev = get_severity(diag);
|
||||||
if (sev)
|
if (sev)
|
||||||
{
|
{
|
||||||
auto loc = source_location::make_file(path); // line number won't help
|
auto diag_loc = clang_getDiagnosticLocation(diag);
|
||||||
auto text = detail::cxstring(clang_getDiagnosticSpelling(diag));
|
unsigned line;
|
||||||
|
clang_getPresumedLocation(diag_loc, nullptr, &line, nullptr);
|
||||||
|
|
||||||
logger.log("libclang", diagnostic{text.c_str(), loc, sev.value()});
|
auto loc = source_location::make_file(path, line);
|
||||||
|
auto text = detail::cxstring(clang_getDiagnosticSpelling(diag));
|
||||||
|
if (text != "too many errors emitted, stopping now")
|
||||||
|
logger.log("libclang", diagnostic{text.c_str(), loc, sev.value()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -444,8 +453,15 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
|
||||||
"config has mismatched type");
|
"config has mismatched type");
|
||||||
auto& config = static_cast<const libclang_compile_config&>(c);
|
auto& config = static_cast<const libclang_compile_config&>(c);
|
||||||
|
|
||||||
// preprocess + parse
|
// preprocess
|
||||||
auto preprocessed = detail::preprocess(config, path.c_str(), logger());
|
auto preprocessed = detail::preprocess(config, path.c_str(), logger());
|
||||||
|
if (detail::libclang_compile_config_access::write_preprocessed(config))
|
||||||
|
{
|
||||||
|
std::ofstream file(path + ".pp");
|
||||||
|
file << preprocessed.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse
|
||||||
auto tu = get_cxunit(logger(), pimpl_->index, config, path.c_str(), preprocessed.source);
|
auto tu = get_cxunit(logger(), pimpl_->index, config, path.c_str(), preprocessed.source);
|
||||||
auto file = clang_getFile(tu.get(), path.c_str());
|
auto file = clang_getFile(tu.get(), path.c_str());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ namespace
|
||||||
// -x c++: force C++ as input language
|
// -x c++: force C++ as input language
|
||||||
// -I.: add current working directory to include search path
|
// -I.: add current working directory to include search path
|
||||||
// -E: print preprocessor output
|
// -E: print preprocessor output
|
||||||
// -CC: keep comments, even in macro
|
// -C: keep comments
|
||||||
// -dD: print macro definitions as well
|
// -dD: print macro definitions as well
|
||||||
auto flags = std::string("-x c++ -I. -E -CC -dD");
|
auto flags = std::string("-x c++ -I. -E -C -dD");
|
||||||
if (detail::libclang_compile_config_access::clang_version(c) >= 40000)
|
if (detail::libclang_compile_config_access::clang_version(c) >= 40000)
|
||||||
// -Xclang -dI: print include directives as well (clang >= 4.0.0)
|
// -Xclang -dI: print include directives as well (clang >= 4.0.0)
|
||||||
flags += " -Xclang -dI";
|
flags += " -Xclang -dI";
|
||||||
|
|
@ -735,7 +735,7 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
|
||||||
{
|
{
|
||||||
case linemarker::line_directive:
|
case linemarker::line_directive:
|
||||||
break; // ignore
|
break; // ignore
|
||||||
// no need to handle it, preprocessed output doesn't need to match line numbers precisely
|
// no need to handle it, preprocessed output doesn't need to match line numbers precisely
|
||||||
|
|
||||||
case linemarker::enter_new:
|
case linemarker::enter_new:
|
||||||
if (file_depth == 0u && lm.value().file.front() != '<')
|
if (file_depth == 0u && lm.value().file.front() != '<')
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,23 @@ namespace
|
||||||
str.erase(0, 1);
|
str.erase(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remove_suffix(std::string& str, const char* suffix)
|
bool can_extend_suffix(const std::string& str, std::size_t suffix_length)
|
||||||
|
{
|
||||||
|
if (str.length() <= suffix_length + 1u)
|
||||||
|
{
|
||||||
|
auto c = str[str.length() - suffix_length - 1u];
|
||||||
|
return std::isalnum(c) || c == '_';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if identifier only removes maximal suffix according to tokenization
|
||||||
|
bool remove_suffix(std::string& str, const char* suffix, bool is_identifier)
|
||||||
{
|
{
|
||||||
auto length = std::strlen(suffix);
|
auto length = std::strlen(suffix);
|
||||||
if (str.length() >= length && str.compare(str.length() - length, length, suffix) == 0)
|
if (str.length() >= length && str.compare(str.length() - length, length, suffix) == 0
|
||||||
|
&& (!is_identifier || !can_extend_suffix(str, length)))
|
||||||
{
|
{
|
||||||
str.erase(str.length() - length);
|
str.erase(str.length() - length);
|
||||||
remove_trailing_ws(str);
|
remove_trailing_ws(str);
|
||||||
|
|
@ -46,10 +59,23 @@ namespace
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remove_prefix(std::string& str, const char* prefix)
|
bool can_extend_prefix(const std::string& str, std::size_t prefix_length)
|
||||||
|
{
|
||||||
|
if (prefix_length < str.size())
|
||||||
|
{
|
||||||
|
auto c = str[prefix_length];
|
||||||
|
return std::isalnum(c) || c == '_';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if identifier only removes maximal suffix according to tokenization
|
||||||
|
bool remove_prefix(std::string& str, const char* prefix, bool is_identifier)
|
||||||
{
|
{
|
||||||
auto length = std::strlen(prefix);
|
auto length = std::strlen(prefix);
|
||||||
if (str.length() >= length && str.compare(0u, length, prefix) == 0)
|
if (str.length() >= length && str.compare(0u, length, prefix) == 0
|
||||||
|
&& (!is_identifier || !can_extend_prefix(str, length)))
|
||||||
{
|
{
|
||||||
str.erase(0u, length);
|
str.erase(0u, length);
|
||||||
remove_leading_ws(str);
|
remove_leading_ws(str);
|
||||||
|
|
@ -69,16 +95,16 @@ namespace
|
||||||
cpp_cv suffix_cv(std::string& spelling)
|
cpp_cv suffix_cv(std::string& spelling)
|
||||||
{
|
{
|
||||||
auto cv = cpp_cv_none;
|
auto cv = cpp_cv_none;
|
||||||
if (remove_suffix(spelling, "const"))
|
if (remove_suffix(spelling, "const", true))
|
||||||
{
|
{
|
||||||
if (remove_suffix(spelling, "volatile"))
|
if (remove_suffix(spelling, "volatile", true))
|
||||||
cv = cpp_cv_const_volatile;
|
cv = cpp_cv_const_volatile;
|
||||||
else
|
else
|
||||||
cv = cpp_cv_const;
|
cv = cpp_cv_const;
|
||||||
}
|
}
|
||||||
else if (remove_suffix(spelling, "volatile"))
|
else if (remove_suffix(spelling, "volatile", true))
|
||||||
{
|
{
|
||||||
if (remove_suffix(spelling, "const"))
|
if (remove_suffix(spelling, "const", true))
|
||||||
cv = cpp_cv_const_volatile;
|
cv = cpp_cv_const_volatile;
|
||||||
else
|
else
|
||||||
cv = cpp_cv_volatile;
|
cv = cpp_cv_volatile;
|
||||||
|
|
@ -88,20 +114,19 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
// const/volatile at the beginning
|
// const/volatile at the beginning
|
||||||
// (weird that the better version is less performant, isn't it?)
|
|
||||||
cpp_cv prefix_cv(std::string& spelling)
|
cpp_cv prefix_cv(std::string& spelling)
|
||||||
{
|
{
|
||||||
auto cv = cpp_cv_none;
|
auto cv = cpp_cv_none;
|
||||||
if (remove_prefix(spelling, "const"))
|
if (remove_prefix(spelling, "const", true))
|
||||||
{
|
{
|
||||||
if (remove_prefix(spelling, "volatile"))
|
if (remove_prefix(spelling, "volatile", true))
|
||||||
cv = cpp_cv_const_volatile;
|
cv = cpp_cv_const_volatile;
|
||||||
else
|
else
|
||||||
cv = cpp_cv_const;
|
cv = cpp_cv_const;
|
||||||
}
|
}
|
||||||
else if (remove_prefix(spelling, "volatile"))
|
else if (remove_prefix(spelling, "volatile", true))
|
||||||
{
|
{
|
||||||
if (remove_prefix(spelling, "const"))
|
if (remove_prefix(spelling, "const", true))
|
||||||
cv = cpp_cv_const_volatile;
|
cv = cpp_cv_const_volatile;
|
||||||
else
|
else
|
||||||
cv = cpp_cv_volatile;
|
cv = cpp_cv_volatile;
|
||||||
|
|
@ -172,9 +197,9 @@ namespace
|
||||||
|
|
||||||
// remove struct/class/union prefix on inline type definition
|
// remove struct/class/union prefix on inline type definition
|
||||||
// i.e. C's typedef struct idiom
|
// i.e. C's typedef struct idiom
|
||||||
remove_prefix(spelling, "struct");
|
remove_prefix(spelling, "struct", true);
|
||||||
remove_prefix(spelling, "class");
|
remove_prefix(spelling, "class", true);
|
||||||
remove_prefix(spelling, "union");
|
remove_prefix(spelling, "union", true);
|
||||||
|
|
||||||
auto entity = b(std::move(spelling));
|
auto entity = b(std::move(spelling));
|
||||||
if (!entity)
|
if (!entity)
|
||||||
|
|
@ -277,9 +302,9 @@ namespace
|
||||||
|
|
||||||
cpp_reference member_function_ref_qualifier(std::string& spelling)
|
cpp_reference member_function_ref_qualifier(std::string& spelling)
|
||||||
{
|
{
|
||||||
if (remove_suffix(spelling, "&&"))
|
if (remove_suffix(spelling, "&&", false))
|
||||||
return cpp_ref_rvalue;
|
return cpp_ref_rvalue;
|
||||||
else if (remove_suffix(spelling, "&"))
|
else if (remove_suffix(spelling, "&", false))
|
||||||
return cpp_ref_lvalue;
|
return cpp_ref_lvalue;
|
||||||
return cpp_ref_none;
|
return cpp_ref_none;
|
||||||
}
|
}
|
||||||
|
|
@ -453,9 +478,9 @@ namespace
|
||||||
return nullptr; // don't use decltype here
|
return nullptr; // don't use decltype here
|
||||||
|
|
||||||
return make_leave_type(type, [&](std::string&& spelling) -> std::unique_ptr<cpp_type> {
|
return make_leave_type(type, [&](std::string&& spelling) -> std::unique_ptr<cpp_type> {
|
||||||
if (!remove_prefix(spelling, "decltype("))
|
if (!remove_prefix(spelling, "decltype(", false))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
remove_suffix(spelling, "..."); // variadic decltype. fun
|
remove_suffix(spelling, "...", false); // variadic decltype. fun
|
||||||
DEBUG_ASSERT(!spelling.empty() && spelling.back() == ')', detail::parse_error_handler{},
|
DEBUG_ASSERT(!spelling.empty() && spelling.back() == ')', detail::parse_error_handler{},
|
||||||
type, "unexpected spelling");
|
type, "unexpected spelling");
|
||||||
spelling.pop_back();
|
spelling.pop_back();
|
||||||
|
|
@ -652,7 +677,7 @@ namespace
|
||||||
case CXType_Typedef:
|
case CXType_Typedef:
|
||||||
return make_leave_type(type, [&](std::string&& spelling) {
|
return make_leave_type(type, [&](std::string&& spelling) {
|
||||||
auto decl = clang_getTypeDeclaration(type);
|
auto decl = clang_getTypeDeclaration(type);
|
||||||
if (remove_prefix(spelling, "(anonymous"))
|
if (remove_prefix(spelling, "(anonymous", false))
|
||||||
spelling = ""; // anonymous type
|
spelling = ""; // anonymous type
|
||||||
return cpp_user_defined_type::build(
|
return cpp_user_defined_type::build(
|
||||||
cpp_type_ref(detail::get_entity_id(decl), std::move(spelling)));
|
cpp_type_ref(detail::get_entity_id(decl), std::move(spelling)));
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ template<template<typename>class... T>
|
||||||
struct templated{
|
struct templated{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using struct_=int;
|
||||||
|
|
||||||
|
struct_ var2;
|
||||||
|
|
||||||
struct foo{
|
struct foo{
|
||||||
int a;
|
int a;
|
||||||
|
|
||||||
|
|
@ -56,6 +60,10 @@ struct templated
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using struct_ = int;
|
||||||
|
|
||||||
|
struct_ var2;
|
||||||
|
|
||||||
struct foo
|
struct foo
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,21 @@ class g {};
|
||||||
|
|
||||||
namespace ns
|
namespace ns
|
||||||
{
|
{
|
||||||
|
namespace other_ns
|
||||||
|
{
|
||||||
|
namespace inner
|
||||||
|
{
|
||||||
|
/// h2
|
||||||
|
void h2() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// h
|
/// h
|
||||||
class h {};
|
class h
|
||||||
|
{
|
||||||
|
/// friend void other_ns::inner::h2();
|
||||||
|
friend void other_ns::inner::h2();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// b::f
|
/// b::f
|
||||||
|
|
@ -115,7 +128,7 @@ int d() {}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
cpp_entity_index idx;
|
cpp_entity_index idx;
|
||||||
auto check_definition = [&](cpp_entity_id id, const char* name) {
|
auto check_definition = [&](cpp_entity_id id, const char* name) {
|
||||||
auto def = idx.lookup_definition(id);
|
auto def = idx.lookup_definition(id);
|
||||||
REQUIRE(def.has_value());
|
REQUIRE(def.has_value());
|
||||||
REQUIRE(def.value().comment());
|
REQUIRE(def.value().comment());
|
||||||
|
|
@ -184,6 +197,13 @@ int d() {}
|
||||||
REQUIRE(func.definition());
|
REQUIRE(func.definition());
|
||||||
check_definition(func.definition().value(), "b::f");
|
check_definition(func.definition().value(), "b::f");
|
||||||
}
|
}
|
||||||
|
else if (func.name() == "h2")
|
||||||
|
{
|
||||||
|
REQUIRE(func.semantic_scope() == "other_ns::inner::");
|
||||||
|
REQUIRE(func.is_declaration());
|
||||||
|
REQUIRE(func.definition());
|
||||||
|
check_definition(func.definition().value(), "h2");
|
||||||
|
}
|
||||||
else if (func.name() == "operator int")
|
else if (func.name() == "operator int")
|
||||||
{
|
{
|
||||||
REQUIRE(func.semantic_scope() == "b::");
|
REQUIRE(func.semantic_scope() == "b::");
|
||||||
|
|
@ -269,5 +289,5 @@ int d() {}
|
||||||
else
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
});
|
});
|
||||||
REQUIRE(count == 17u);
|
REQUIRE(count == 18u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,23 +173,20 @@ f **/
|
||||||
#define g(name) \
|
#define g(name) \
|
||||||
class name \
|
class name \
|
||||||
{ \
|
{ \
|
||||||
/** i
|
|
||||||
i */ \
|
|
||||||
void i(); \
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// h
|
/// h
|
||||||
/// h
|
/// h
|
||||||
g(h)
|
g(h)
|
||||||
|
|
||||||
/// j
|
/// i
|
||||||
/// j
|
/// i
|
||||||
using j = int;
|
using i = int;
|
||||||
|
|
||||||
/// k
|
/// j
|
||||||
/// k
|
/// j
|
||||||
template <typename T/**/>
|
template <typename T/**/>
|
||||||
void k();
|
void j();
|
||||||
)";
|
)";
|
||||||
|
|
||||||
auto file = parse({}, "comment-matching.cpp", code);
|
auto file = parse({}, "comment-matching.cpp", code);
|
||||||
|
|
|
||||||
|
|
@ -87,12 +87,8 @@ void print_entity(std::ostream& out, const cppast::cpp_entity& e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// no need to handle indentation, as only a single line is used
|
// no need to handle indentation, as only a single line is used
|
||||||
void do_indent() override
|
void do_indent() override {}
|
||||||
{
|
void do_unindent() override {}
|
||||||
}
|
|
||||||
void do_unindent() override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// called when a generic token sequence should be generated
|
// called when a generic token sequence should be generated
|
||||||
// there are specialized callbacks for various token kinds,
|
// there are specialized callbacks for various token kinds,
|
||||||
|
|
@ -249,6 +245,9 @@ int main(int argc, char* argv[]) try
|
||||||
cppast::libclang_compile_config(database, options["file"].as<std::string>());
|
cppast::libclang_compile_config(database, options["file"].as<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.count("verbose"))
|
||||||
|
config.write_preprocessed(true);
|
||||||
|
|
||||||
if (options.count("include_directory"))
|
if (options.count("include_directory"))
|
||||||
for (auto& include : options["include_directory"].as<std::vector<std::string>>())
|
for (auto& include : options["include_directory"].as<std::vector<std::string>>())
|
||||||
config.add_include_dir(include);
|
config.add_include_dir(include);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue