Updated cppast ref

This commit is contained in:
Bartek Kryza
2022-04-16 13:18:47 +02:00
parent e076bc7c29
commit fec81d7eb2
7 changed files with 1 additions and 994 deletions

View File

@@ -1,112 +0,0 @@
/**
* src/cx/compilation_database.cc
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "compilation_database.h"
#include "util/util.h"
#include <filesystem>
#include <spdlog/fmt/fmt.h>
#include <spdlog/spdlog.h>
namespace clanguml {
namespace cx {
compilation_database::compilation_database(CXCompilationDatabase &&d)
: m_database{std::move(d)}
, m_index{clang_createIndex(0, 1)}
{
}
compilation_database::~compilation_database()
{
// clang_CompilationDatabase_dispose(m_database);
}
compilation_database::compilation_database(compilation_database &&d)
: m_database{std::move(d.m_database)}
, m_index{std::move(d.m_index)}
{
}
compilation_database compilation_database::from_directory(
const std::string &dir)
{
CXCompilationDatabase_Error error;
auto path = std::filesystem::path{dir};
CXCompilationDatabase cdb =
clang_CompilationDatabase_fromDirectory(path.c_str(), &error);
if (error != CXCompilationDatabase_Error::CXCompilationDatabase_NoError) {
throw std::runtime_error(fmt::format(
"Cannot load compilation database database from: {}", dir));
}
return compilation_database{std::move(cdb)};
}
CXTranslationUnit compilation_database::parse_translation_unit(
const std::string &path)
{
const auto p = std::filesystem::canonical(path);
CXCompileCommands compile_commands =
clang_CompilationDatabase_getCompileCommands(m_database, p.c_str());
unsigned int compile_commands_count =
clang_CompileCommands_getSize(compile_commands);
int i;
// for (i = 0; i < compile_commands_count; i++) {
CXCompileCommand compile_command =
clang_CompileCommands_getCommand(compile_commands, 0);
auto cc_filename = clang_CompileCommand_getFilename(compile_command);
LOG_DBG(
"Processing compile command file: {}", clang_getCString(cc_filename));
auto num_args = clang_CompileCommand_getNumArgs(compile_command);
char **arguments = NULL;
if (num_args) {
int j;
arguments = (char **)malloc(sizeof(char *) * num_args);
for (j = 0; j < num_args; ++j) {
CXString arg = clang_CompileCommand_getArg(compile_command, j);
LOG_DBG("Processing argument: {}", clang_getCString(arg));
arguments[j] = strdup(clang_getCString(arg));
clang_disposeString(arg);
}
}
CXTranslationUnit tu = clang_parseTranslationUnit(m_index, nullptr,
(const char *const *)arguments, num_args, NULL, 0,
CXTranslationUnit_None);
if (num_args) {
int j;
for (j = 0; j < num_args; ++j) {
free(arguments[j]);
}
free(arguments);
}
//}
return tu;
}
CXCompilationDatabase &compilation_database::db() { return m_database; }
}
}

View File

@@ -1,50 +0,0 @@
/**
* src/cx/compilation_database.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <functional>
#include <memory>
#include <string>
namespace clanguml {
namespace cx {
class compilation_database {
public:
compilation_database(CXCompilationDatabase &&d);
~compilation_database();
compilation_database(compilation_database &&d);
CXCompilationDatabase &db();
CXIndex &index();
CXTranslationUnit parse_translation_unit(const std::string &path);
static compilation_database from_directory(const std::string &dir);
private:
CXCompilationDatabase m_database;
CXIndex m_index;
};
}
}

View File

@@ -1,328 +0,0 @@
/**
* src/cx/cursor.cc
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cx/cursor.h"
namespace clanguml::cx {
cursor::cursor()
: m_cursor{clang_getNullCursor()}
{
}
cursor::cursor(CXCursor &&c)
: m_cursor{std::move(c)}
{
}
cursor::cursor(const CXCursor &c)
: m_cursor{c}
{
}
cursor::cursor(const cursor &c)
: m_cursor{c.get()}
{
}
bool cursor::operator==(const cursor &b) const
{
return clang_equalCursors(m_cursor, b.get());
}
cx::type cursor::type() const { return {clang_getCursorType(m_cursor)}; }
std::string cursor::display_name() const
{
return to_string(clang_getCursorDisplayName(m_cursor));
}
std::string cursor::spelling() const
{
return to_string(clang_getCursorSpelling(m_cursor));
}
bool cursor::is_void() const
{
// Why do I have to do this like this?
return spelling() == "void";
}
/**
* @brief Return fully qualified cursor spelling
*
* This method generates a fully qualified name for the cursor by
* traversing the namespaces upwards.
*
* TODO: Add caching of this value.
*
* @return Fully qualified cursor spelling
*/
std::string cursor::fully_qualified() const
{
std::list<std::string> res;
cursor iterator{m_cursor};
if (iterator.spelling().empty())
return {};
int limit = 100;
while (iterator.kind() != CXCursor_TranslationUnit) {
auto name = iterator.spelling();
if (!name.empty())
res.push_front(iterator.spelling());
iterator = iterator.semantic_parent();
if (limit-- == 0)
throw std::runtime_error(fmt::format(
"Generating fully qualified name for '{}' failed at: '{}'",
spelling(), fmt::join(res, "::")));
}
return fmt::format("{}", fmt::join(res, "::"));
}
cursor cursor::referenced() const
{
return cx::cursor{clang_getCursorReferenced(m_cursor)};
}
cursor cursor::semantic_parent() const
{
return {clang_getCursorSemanticParent(m_cursor)};
}
cursor cursor::lexical_parent() const
{
return {clang_getCursorLexicalParent(m_cursor)};
}
CXCursorKind cursor::kind() const { return m_cursor.kind; }
std::string cursor::kind_spelling() const
{
return to_string(clang_getCursorKindSpelling(m_cursor.kind));
}
cursor cursor::definition() const
{
return clang_getCursorDefinition(m_cursor);
}
bool cursor::is_definition() const
{
return clang_isCursorDefinition(m_cursor);
}
bool cursor::is_declaration() const { return clang_isDeclaration(kind()); }
bool cursor::is_forward_declaration() const
{
auto definition = clang_getCursorDefinition(m_cursor);
if (clang_equalCursors(definition, clang_getNullCursor()))
return true;
return !clang_equalCursors(m_cursor, definition);
}
bool cursor::is_invalid_declaration() const
{
return clang_isInvalidDeclaration(m_cursor);
}
CXSourceLocation cursor::location() const
{
return clang_getCursorLocation(m_cursor);
}
bool cursor::is_reference() const { return clang_isReference(kind()); }
bool cursor::is_expression() const { return clang_isExpression(kind()); }
bool cursor::is_statement() const { return clang_isStatement(kind()); }
bool cursor::is_namespace() const { return kind() == CXCursor_Namespace; }
bool cursor::is_attribute() const { return clang_isAttribute(kind()); }
bool cursor::has_attrs() const { return clang_Cursor_hasAttrs(m_cursor); }
bool cursor::is_invalid() const { return clang_isInvalid(kind()); }
bool cursor::is_translation_unit() const
{
return clang_isTranslationUnit(kind());
}
bool cursor::is_preprocessing() const { return clang_isPreprocessing(kind()); }
bool cursor::is_method_virtual() const
{
return clang_CXXMethod_isVirtual(m_cursor);
}
bool cursor::is_static() const
{
return clang_Cursor_getStorageClass(m_cursor) == CX_SC_Static;
}
bool cursor::is_method_static() const
{
return clang_CXXMethod_isStatic(m_cursor);
}
bool cursor::is_method_const() const
{
return clang_CXXMethod_isConst(m_cursor);
}
bool cursor::is_method_pure_virtual() const
{
return clang_CXXMethod_isPureVirtual(m_cursor);
}
bool cursor::is_method_defaulted() const
{
return clang_CXXMethod_isDefaulted(m_cursor);
}
bool cursor::is_method_parameter() const { return kind() == CXCursor_ParmDecl; }
CXVisibilityKind cursor::visibitity() const
{
return clang_getCursorVisibility(m_cursor);
}
CXAvailabilityKind cursor::availability() const
{
return clang_getCursorAvailability(m_cursor);
}
CX_CXXAccessSpecifier cursor::cxxaccess_specifier() const
{
return clang_getCXXAccessSpecifier(m_cursor);
}
cx::type cursor::underlying_type() const
{
return clang_getTypedefDeclUnderlyingType(m_cursor);
}
int cursor::template_argument_count() const
{
return clang_Cursor_getNumTemplateArguments(m_cursor);
}
CXTemplateArgumentKind cursor::template_argument_kind(unsigned i) const
{
return clang_Cursor_getTemplateArgumentKind(m_cursor, i);
}
cx::type cursor::template_argument_type(unsigned i) const
{
return clang_Cursor_getTemplateArgumentType(m_cursor, i);
}
long long cursor::template_argument_value(unsigned i) const
{
return clang_Cursor_getTemplateArgumentValue(m_cursor, i);
}
cursor cursor::specialized_cursor_template() const
{
return clang_getSpecializedCursorTemplate(m_cursor);
}
CXTranslationUnit cursor::translation_unit() const
{
return clang_Cursor_getTranslationUnit(m_cursor);
}
bool cursor::is_template_parameter_variadic() const
{
const auto &tokens = tokenize();
return tokens.size() > 2 && tokens[1] == "...";
}
std::string cursor::usr() const
{
return to_string(clang_getCursorUSR(m_cursor));
}
CXSourceRange cursor::extent() const { return clang_getCursorExtent(m_cursor); }
std::vector<std::string> cursor::tokenize() const
{
auto range = extent();
std::vector<std::string> res;
CXToken *toks;
unsigned toks_count{0};
auto tu = translation_unit();
clang_tokenize(tu, range, &toks, &toks_count);
for (int i = 0; i < toks_count; i++) {
res.push_back(to_string(clang_getTokenSpelling(tu, toks[i])));
}
return res;
}
std::string cursor::default_value() const
{
assert(is_method_parameter());
auto toks = tokenize();
std::string res;
auto it = std::find(toks.begin(), toks.end(), "=");
if (it != toks.end()) {
res = fmt::format("{}", fmt::join(it + 1, toks.end(), ""));
}
return res;
}
std::vector<std::string> cursor::tokenize_template_parameters() const
{
auto toks = tokenize();
std::vector<std::string> res;
bool inside_template{false};
bool is_namespace{false};
for (int i = 0; i < toks.size(); i++) {
// libclang returns ">..>>" in template as a single token...
auto t = toks[i];
if (std::all_of(
t.begin(), t.end(), [](const char &c) { return c == '>'; })) {
toks[i] = ">";
for (int j = 0; j < t.size() - 1; j++)
toks.insert(toks.begin() + i, ">");
}
}
auto template_start = std::find(toks.begin(), toks.end(), "<");
auto template_end = std::find(toks.rbegin(), toks.rend(), ">");
decltype(res) template_contents(
template_start + 1, template_end.base() - 1);
return clanguml::util::split(
fmt::format("{}", fmt::join(template_contents, "")), ",");
}
const CXCursor &cursor::get() const { return m_cursor; }
}

View File

@@ -1,153 +0,0 @@
/**
* src/cx/cursor.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "cx/type.h"
#include <list>
#include <string>
namespace clanguml {
namespace cx {
class cursor {
public:
cursor();
cursor(CXCursor &&c);
cursor(const CXCursor &c);
cursor(const cursor &c);
~cursor() = default;
bool operator==(const cursor &b) const;
cx::type type() const;
std::string display_name() const;
std::string spelling() const;
bool is_void() const;
/**
* @brief Return fully qualified cursor spelling
*
* This method generates a fully qualified name for the cursor by
* traversing the namespaces upwards.
*
* TODO: Add caching of this value.
*
* @return Fully qualified cursor spelling
*/
std::string fully_qualified() const;
cursor referenced() const;
cursor semantic_parent() const;
cursor lexical_parent() const;
CXCursorKind kind() const;
std::string kind_spelling() const;
cursor definition() const;
bool is_definition() const;
bool is_declaration() const;
bool is_forward_declaration() const;
bool is_invalid_declaration() const;
CXSourceLocation location() const;
bool is_reference() const;
bool is_expression() const;
bool is_statement() const;
bool is_namespace() const;
bool is_attribute() const;
bool has_attrs() const;
bool is_invalid() const;
bool is_translation_unit() const;
bool is_preprocessing() const;
bool is_method_virtual() const;
bool is_static() const;
bool is_method_static() const;
bool is_method_const() const;
bool is_method_pure_virtual() const;
bool is_method_defaulted() const;
bool is_method_parameter() const;
CXVisibilityKind visibitity() const;
CXAvailabilityKind availability() const;
CX_CXXAccessSpecifier cxxaccess_specifier() const;
cx::type underlying_type() const;
int template_argument_count() const;
CXTemplateArgumentKind template_argument_kind(unsigned i) const;
cx::type template_argument_type(unsigned i) const;
long long template_argument_value(unsigned i) const;
cursor specialized_cursor_template() const;
CXTranslationUnit translation_unit() const;
bool is_template_parameter_variadic() const;
std::string usr() const;
CXSourceRange extent() const;
std::vector<std::string> tokenize() const;
std::string default_value() const;
std::vector<std::string> tokenize_template_parameters() const;
const CXCursor &get() const;
private:
CXCursor m_cursor;
};
}
}
template <> struct fmt::formatter<clanguml::cx::cursor> {
template <typename ParseContext> constexpr auto parse(ParseContext &ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const clanguml::cx::cursor &c, FormatContext &ctx)
{
return fmt::format_to(ctx.out(),
"(cx::cursor spelling={}, display_name={}, kind={}, "
"is_expression={}, template_argument_count={})",
c.spelling(), c.display_name(), c.kind_spelling(),
c.is_expression(), c.template_argument_count()
);
}
};

View File

@@ -1,208 +0,0 @@
/**
* src/cx/type.cc
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "type.h"
#include "cursor.h"
namespace clanguml {
namespace cx {
type::type(CXType &&t)
: m_type{std::move(t)}
{
}
std::string type::spelling() const
{
return to_string(clang_getTypeSpelling(m_type));
}
bool type::operator==(const type &b) const
{
return clang_equalTypes(m_type, b.get());
}
type type::canonical() const { return {clang_getCanonicalType(m_type)}; }
bool type::is_unexposed() const { return kind() == CXType_Unexposed; }
bool type::is_const_qualified() const
{
return clang_isConstQualifiedType(m_type);
}
bool type::is_volatile_qualified() const
{
return clang_isVolatileQualifiedType(m_type);
}
bool type::is_restricted_qualified() const
{
return clang_isRestrictQualifiedType(m_type);
}
bool type::is_invalid() const { return kind() == CXType_Invalid; }
std::string type::typedef_name() const
{
return to_string(clang_getTypedefName(m_type));
}
type type::pointee_type() const { return {clang_getPointeeType(m_type)}; }
CXTypeKind type::kind() const { return m_type.kind; }
std::string type::kind_spelling() const
{
return to_string(clang_getTypeKindSpelling(m_type.kind));
}
CXCallingConv type::calling_convention() const
{
return clang_getFunctionTypeCallingConv(m_type);
}
type type::result_type() const { return clang_getResultType(m_type); }
int type::exception_specification_type() const
{
return clang_getExceptionSpecificationType(m_type);
}
int type::argument_type_count() const { return clang_getNumArgTypes(m_type); }
type type::argument_type(int i) const { return {clang_getArgType(m_type, i)}; }
bool type::is_function_variadic() const
{
return clang_isFunctionTypeVariadic(m_type);
}
bool type::is_pod() const { return clang_isPODType(m_type); }
bool type::is_pointer() const { return kind() == CXType_Pointer; }
bool type::is_record() const { return kind() == CXType_Record; }
type type::referenced() const
{
auto t = *this;
while (t.is_pointer() || t.is_reference()) {
t = t.pointee_type();
}
return t;
}
bool type::is_reference() const
{
return (kind() == CXType_LValueReference) ||
(kind() == CXType_RValueReference);
}
bool type::is_array() const { return clang_getArraySize(m_type) > -1; }
type type::array_type() const { return {clang_getArrayElementType(m_type)}; }
bool type::is_relationship() const
{
return is_pointer() || is_record() || is_reference() || !is_pod() ||
is_array() || is_template() ||
(spelling().find("std::array") ==
0 /* There must be a better way... */);
}
type type::element_type() const { return clang_getElementType(m_type); }
long long type::element_count() const { return clang_getNumElements(m_type); }
type type::array_element_type() const
{
return clang_getArrayElementType(m_type);
}
type type::named_type() const { return clang_Type_getNamedType(m_type); }
CXTypeNullabilityKind type::nullability() const
{
return clang_Type_getNullability(m_type);
}
type type::class_type() const { return clang_Type_getClassType(m_type); }
long long type::size_of() const { return clang_Type_getSizeOf(m_type); }
type type::modified_type() const { return clang_Type_getModifiedType(m_type); }
type type::value_type() const { return clang_Type_getValueType(m_type); }
bool type::is_template() const { return template_arguments_count() > 0; }
bool type::is_template_parameter() const
{
return canonical().spelling().find("type-parameter-") == 0;
}
int type::template_arguments_count() const
{
return clang_Type_getNumTemplateArguments(m_type);
}
type type::template_argument_type(int i) const
{
return clang_Type_getTemplateArgumentAsType(m_type, i);
}
const CXType &type::get() const { return m_type; }
CXRefQualifierKind type::cxxref_qualifier() const
{
return clang_Type_getCXXRefQualifier(m_type);
}
std::string type::unqualified() const
{
return clanguml::util::unqualify(spelling());
}
cursor type::type_declaration() const
{
return {clang_getTypeDeclaration(m_type)};
}
std::string type::instantiation_template() const
{
assert(is_template_instantiation());
auto s = spelling();
auto it = s.find('<');
auto template_base_name = s.substr(0, it);
auto cur = type_declaration();
return cur.fully_qualified();
}
bool type::is_template_instantiation() const
{
auto s = spelling();
auto it = s.find('<');
return it != std::string::npos &&
referenced().type_declaration().kind() != CXCursor_ClassTemplate;
}
}
}

View File

@@ -1,142 +0,0 @@
/**
* src/cx/type.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
#include "cx/util.h"
#include "util/util.h"
namespace clanguml {
namespace cx {
using util::to_string;
class cursor;
class type {
public:
type(CXType &&t);
~type() = default;
std::string spelling() const;
bool operator==(const type &b) const;
type canonical() const;
bool is_unexposed() const;
bool is_const_qualified() const;
bool is_volatile_qualified() const;
bool is_restricted_qualified() const;
bool is_invalid() const;
std::string typedef_name() const;
type pointee_type() const;
cursor type_declaration() const;
CXTypeKind kind() const;
std::string kind_spelling() const;
CXCallingConv calling_convention() const;
type result_type() const;
int exception_specification_type() const;
int argument_type_count() const;
type argument_type(int i) const;
bool is_function_variadic() const;
bool is_pod() const;
bool is_pointer() const;
bool is_record() const;
/**
* @brief Return final referenced type.
*
* This method allows to extract a final type in case a type consists of a
* single or multiple pointers or references.
*
* @return Referenced type.
*/
type referenced() const;
bool is_reference() const;
bool is_array() const;
type array_type() const;
bool is_relationship() const;
type element_type() const;
long long element_count() const;
type array_element_type() const;
type named_type() const;
CXTypeNullabilityKind nullability() const;
type class_type() const;
long long size_of() const;
type modified_type() const;
type value_type() const;
bool is_template() const;
bool is_template_parameter() const;
int template_arguments_count() const;
type template_argument_type(int i) const;
const CXType &get() const;
CXRefQualifierKind cxxref_qualifier() const;
bool is_template_instantiation() const;
std::string instantiation_template() const;
/**
* @brief Remove all qualifiers from field declaration.
*
* @return Unqualified identifier.
*/
std::string unqualified() const;
private:
CXType m_type;
};
}
}
template <> struct fmt::formatter<clanguml::cx::type> {
template <typename ParseContext> constexpr auto parse(ParseContext &ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const clanguml::cx::type &t, FormatContext &ctx)
{
return fmt::format_to(ctx.out(),
"(cx::type spelling={}, kind={}, pointee={}, "
"is_pod={}, canonical={}, is_relationship={})",
t.spelling(), t.kind_spelling(), t.pointee_type().spelling(),
t.is_pod(), t.canonical().spelling(), t.is_relationship());
}
};