Reduce code duplication between serialization generators
This commit is contained in:
parent
e93be04e35
commit
c170993392
|
@ -8,6 +8,7 @@ set(LINK_TESTS_AGAINST_APP_TARGET ON)
|
|||
# add project files
|
||||
set(HEADER_FILES
|
||||
codegenerator.h
|
||||
serializationcodegenerator.h
|
||||
jsonserializationcodegenerator.h
|
||||
binaryserializationcodegenerator.h
|
||||
codefactory.h
|
||||
|
@ -18,6 +19,7 @@ set(HEADER_FILES
|
|||
)
|
||||
set(SRC_FILES
|
||||
codegenerator.cpp
|
||||
serializationcodegenerator.cpp
|
||||
jsonserializationcodegenerator.cpp
|
||||
binaryserializationcodegenerator.cpp
|
||||
codefactory.cpp
|
||||
|
|
|
@ -26,50 +26,12 @@ BinarySerializationCodeGenerator::Options::Options()
|
|||
visibilityArg.setPreDefinedCompletionValues("LIB_EXPORT");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds all class declarations (to the internal member variable m_records).
|
||||
* \remarks "AdaptedBinarySerializable" specializations are directly filtered and added to m_adaptionRecords (instead of m_records).
|
||||
*/
|
||||
void BinarySerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
||||
BinarySerializationCodeGenerator::BinarySerializationCodeGenerator(CodeFactory &factory, const Options &options)
|
||||
: SerializationCodeGenerator(factory)
|
||||
, m_options(options)
|
||||
{
|
||||
switch (decl->getKind()) {
|
||||
case clang::Decl::Kind::CXXRecord:
|
||||
case clang::Decl::Kind::ClassTemplateSpecialization: {
|
||||
auto *const record = static_cast<clang::CXXRecordDecl *>(decl);
|
||||
// skip forward declarations
|
||||
if (!record->hasDefinition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for template specializations to adapt a 3rd party class/struct
|
||||
if (decl->getKind() == clang::Decl::Kind::ClassTemplateSpecialization) {
|
||||
auto *const templateSpecializationRecord = static_cast<clang::ClassTemplateSpecializationDecl *>(decl);
|
||||
// check whether the name of the template specialization matches
|
||||
if (templateSpecializationRecord->getQualifiedNameAsString() == AdaptedBinarySerializable<void>::qualifiedName) {
|
||||
// get the template argument of the template specialization (exactly one argument expected)
|
||||
const auto &templateArgs = templateSpecializationRecord->getTemplateArgs();
|
||||
if (templateArgs.size() != 1 || templateArgs.get(0).getKind() != clang::TemplateArgument::Type) {
|
||||
return; // FIXME: use Clang diagnostics to print warning
|
||||
}
|
||||
// get the type the template argument refers to (that's the type of the 3rd party class/struct to adapt)
|
||||
auto *const templateRecord = templateArgs.get(0).getAsType()->getAsCXXRecordDecl();
|
||||
if (!templateRecord) {
|
||||
return; // FIXME: use Clang diagnostics to print warning
|
||||
}
|
||||
// save the relevant information for the code generation
|
||||
m_adaptionRecords.emplace_back(templateRecord->getQualifiedNameAsString(), templateSpecializationRecord);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add any other records
|
||||
m_records.emplace_back(record);
|
||||
} break;
|
||||
case clang::Decl::Kind::Enum:
|
||||
// TODO: add enums
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
m_qualifiedNameOfRecords = BinarySerializable<void>::qualifiedName;
|
||||
m_qualifiedNameOfAdaptionRecords = AdaptedBinarySerializable<void>::qualifiedName;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -77,26 +39,14 @@ void BinarySerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
|||
*/
|
||||
string BinarySerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const
|
||||
{
|
||||
// consider all classes for which a specialization of the "AdaptedBinarySerializable" struct is available
|
||||
const string qualifiedName(record->getQualifiedNameAsString());
|
||||
for (const auto &adaptionRecord : m_adaptionRecords) {
|
||||
// skip all adaption records which are only included
|
||||
if (isOnlyIncluded(adaptionRecord.record)) {
|
||||
continue;
|
||||
}
|
||||
if (adaptionRecord.qualifiedName == qualifiedName) {
|
||||
return qualifiedName;
|
||||
}
|
||||
}
|
||||
|
||||
// skip all classes which are only included
|
||||
if (isOnlyIncluded(record)) {
|
||||
return string();
|
||||
}
|
||||
|
||||
// consider all classes inheriting from an instantiation of "BinarySerializable" relevant
|
||||
if (inheritsFromInstantiationOf(record, BinarySerializable<void>::qualifiedName)) {
|
||||
switch (isQualifiedNameIfRelevant(record, qualifiedName)) {
|
||||
case IsRelevant::Yes:
|
||||
return qualifiedName;
|
||||
case IsRelevant::No:
|
||||
return string();
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
// consider all classes specified via "--additional-classes" argument relevant
|
||||
|
@ -112,37 +62,6 @@ string BinarySerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecor
|
|||
return string();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Searches the records added via addDeclaration() and returns the relevant ones.
|
||||
* \sa Whether a record is relevant is determined using the qualifiedNameIfRelevant() method.
|
||||
*/
|
||||
std::vector<BinarySerializationCodeGenerator::RelevantClass> BinarySerializationCodeGenerator::findRelevantClasses() const
|
||||
{
|
||||
std::vector<RelevantClass> relevantClasses;
|
||||
for (clang::CXXRecordDecl *record : m_records) {
|
||||
string qualifiedName(qualifiedNameIfRelevant(record));
|
||||
if (!qualifiedName.empty()) {
|
||||
relevantClasses.emplace_back(move(qualifiedName), record);
|
||||
}
|
||||
}
|
||||
return relevantClasses;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the relevant base classes of the specified \a relevantClass. All base classes in \a relevantBases are considered relevant.
|
||||
*/
|
||||
std::vector<const BinarySerializationCodeGenerator::RelevantClass *> BinarySerializationCodeGenerator::findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases)
|
||||
{
|
||||
vector<const RelevantClass *> relevantBaseClasses;
|
||||
for (const RelevantClass &otherClass : relevantBases) {
|
||||
if (relevantClass.record != otherClass.record && relevantClass.record->isDerivedFrom(otherClass.record)) {
|
||||
relevantBaseClasses.push_back(&otherClass);
|
||||
}
|
||||
}
|
||||
return relevantBaseClasses;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates pull() and push() helper functions in the ReflectiveRapidJSON::BinaryReflector namespace for the relevant classes.
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef REFLECTIVE_RAPIDJSON_CODE_BINARY_SERIALIZATION_GENERATOR_H
|
||||
#define REFLECTIVE_RAPIDJSON_CODE_BINARY_SERIALIZATION_GENERATOR_H
|
||||
|
||||
#include "./codegenerator.h"
|
||||
#include "./serializationcodegenerator.h"
|
||||
|
||||
#include <c++utilities/application/argumentparser.h>
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace ReflectiveRapidJSON {
|
|||
* \brief The BinarySerializationCodeGenerator class generates code for JSON (de)serialization
|
||||
* of objects inheriting from an instantiation of JsonSerializable.
|
||||
*/
|
||||
class BinarySerializationCodeGenerator : public CodeGenerator {
|
||||
class BinarySerializationCodeGenerator : public SerializationCodeGenerator {
|
||||
public:
|
||||
struct Options {
|
||||
Options();
|
||||
|
@ -22,49 +22,22 @@ public:
|
|||
ApplicationUtilities::ConfigValueArgument visibilityArg;
|
||||
};
|
||||
|
||||
private:
|
||||
struct RelevantClass {
|
||||
explicit RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record);
|
||||
|
||||
std::string qualifiedName;
|
||||
clang::CXXRecordDecl *record;
|
||||
};
|
||||
|
||||
public:
|
||||
BinarySerializationCodeGenerator(CodeFactory &factory, const Options &options);
|
||||
|
||||
void addDeclaration(clang::Decl *decl) override;
|
||||
void generate(std::ostream &os) const override;
|
||||
|
||||
private:
|
||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const;
|
||||
std::vector<RelevantClass> findRelevantClasses() const;
|
||||
static std::vector<const RelevantClass *> findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases);
|
||||
protected:
|
||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const override;
|
||||
|
||||
std::vector<clang::CXXRecordDecl *> m_records;
|
||||
std::vector<RelevantClass> m_adaptionRecords;
|
||||
const Options &m_options;
|
||||
};
|
||||
|
||||
inline BinarySerializationCodeGenerator::BinarySerializationCodeGenerator(CodeFactory &factory, const Options &options)
|
||||
: CodeGenerator(factory)
|
||||
, m_options(options)
|
||||
{
|
||||
}
|
||||
|
||||
inline void BinarySerializationCodeGenerator::Options::appendTo(ApplicationUtilities::Argument *arg)
|
||||
{
|
||||
arg->addSubArgument(&additionalClassesArg);
|
||||
arg->addSubArgument(&visibilityArg);
|
||||
}
|
||||
|
||||
inline BinarySerializationCodeGenerator::RelevantClass::RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record)
|
||||
: qualifiedName(qualifiedName)
|
||||
, record(record)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace ReflectiveRapidJSON
|
||||
|
||||
#endif // REFLECTIVE_RAPIDJSON_CODE_BINARY_SERIALIZATION_GENERATOR_H
|
||||
|
|
|
@ -10,14 +10,6 @@ using namespace std;
|
|||
|
||||
namespace ReflectiveRapidJSON {
|
||||
|
||||
/*!
|
||||
* \brief Prints an LLVM string reference without instantiating a std::string first.
|
||||
*/
|
||||
ostream &operator<<(ostream &os, llvm::StringRef str)
|
||||
{
|
||||
return os.write(str.data(), static_cast<streamsize>(str.size()));
|
||||
}
|
||||
|
||||
CodeGenerator::~CodeGenerator()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class CXXRecordDecl;
|
||||
|
@ -17,8 +15,6 @@ namespace ReflectiveRapidJSON {
|
|||
|
||||
class CodeFactory;
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, llvm::StringRef str);
|
||||
|
||||
/*!
|
||||
* \brief The CodeGenerator class is the base for generators used by the CodeFactory class.
|
||||
*/
|
||||
|
|
|
@ -26,50 +26,12 @@ JsonSerializationCodeGenerator::Options::Options()
|
|||
visibilityArg.setPreDefinedCompletionValues("LIB_EXPORT");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds all class declarations (to the internal member variable m_records).
|
||||
* \remarks "AdaptedJsonSerializable" specializations are directly filtered and added to m_adaptionRecords (instead of m_records).
|
||||
*/
|
||||
void JsonSerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
||||
JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory, const Options &options)
|
||||
: SerializationCodeGenerator(factory)
|
||||
, m_options(options)
|
||||
{
|
||||
switch (decl->getKind()) {
|
||||
case clang::Decl::Kind::CXXRecord:
|
||||
case clang::Decl::Kind::ClassTemplateSpecialization: {
|
||||
auto *const record = static_cast<clang::CXXRecordDecl *>(decl);
|
||||
// skip forward declarations
|
||||
if (!record->hasDefinition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for template specializations to adapt a 3rd party class/struct
|
||||
if (decl->getKind() == clang::Decl::Kind::ClassTemplateSpecialization) {
|
||||
auto *const templateSpecializationRecord = static_cast<clang::ClassTemplateSpecializationDecl *>(decl);
|
||||
// check whether the name of the template specialization matches
|
||||
if (templateSpecializationRecord->getQualifiedNameAsString() == AdaptedJsonSerializable<void>::qualifiedName) {
|
||||
// get the template argument of the template specialization (exactly one argument expected)
|
||||
const auto &templateArgs = templateSpecializationRecord->getTemplateArgs();
|
||||
if (templateArgs.size() != 1 || templateArgs.get(0).getKind() != clang::TemplateArgument::Type) {
|
||||
return; // FIXME: use Clang diagnostics to print warning
|
||||
}
|
||||
// get the type the template argument refers to (that's the type of the 3rd party class/struct to adapt)
|
||||
auto *const templateRecord = templateArgs.get(0).getAsType()->getAsCXXRecordDecl();
|
||||
if (!templateRecord) {
|
||||
return; // FIXME: use Clang diagnostics to print warning
|
||||
}
|
||||
// save the relevant information for the code generation
|
||||
m_adaptionRecords.emplace_back(templateRecord->getQualifiedNameAsString(), templateSpecializationRecord);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add any other records
|
||||
m_records.emplace_back(record);
|
||||
} break;
|
||||
case clang::Decl::Kind::Enum:
|
||||
// TODO: add enums
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
m_qualifiedNameOfRecords = JsonSerializable<void>::qualifiedName;
|
||||
m_qualifiedNameOfAdaptionRecords = AdaptedJsonSerializable<void>::qualifiedName;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -77,26 +39,14 @@ void JsonSerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
|||
*/
|
||||
string JsonSerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const
|
||||
{
|
||||
// consider all classes for which a specialization of the "AdaptedJsonSerializable" struct is available
|
||||
const string qualifiedName(record->getQualifiedNameAsString());
|
||||
for (const auto &adaptionRecord : m_adaptionRecords) {
|
||||
// skip all adaption records which are only included
|
||||
if (isOnlyIncluded(adaptionRecord.record)) {
|
||||
continue;
|
||||
}
|
||||
if (adaptionRecord.qualifiedName == qualifiedName) {
|
||||
return qualifiedName;
|
||||
}
|
||||
}
|
||||
|
||||
// skip all classes which are only included
|
||||
if (isOnlyIncluded(record)) {
|
||||
return string();
|
||||
}
|
||||
|
||||
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
||||
if (inheritsFromInstantiationOf(record, JsonSerializable<void>::qualifiedName)) {
|
||||
switch (isQualifiedNameIfRelevant(record, qualifiedName)) {
|
||||
case IsRelevant::Yes:
|
||||
return qualifiedName;
|
||||
case IsRelevant::No:
|
||||
return string();
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
// consider all classes specified via "--additional-classes" argument relevant
|
||||
|
@ -112,37 +62,6 @@ string JsonSerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecordD
|
|||
return string();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Searches the records added via addDeclaration() and returns the relevant ones.
|
||||
* \sa Whether a record is relevant is determined using the qualifiedNameIfRelevant() method.
|
||||
*/
|
||||
std::vector<JsonSerializationCodeGenerator::RelevantClass> JsonSerializationCodeGenerator::findRelevantClasses() const
|
||||
{
|
||||
std::vector<RelevantClass> relevantClasses;
|
||||
for (clang::CXXRecordDecl *record : m_records) {
|
||||
string qualifiedName(qualifiedNameIfRelevant(record));
|
||||
if (!qualifiedName.empty()) {
|
||||
relevantClasses.emplace_back(move(qualifiedName), record);
|
||||
}
|
||||
}
|
||||
return relevantClasses;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the relevant base classes of the specified \a relevantClass. All base classes in \a relevantBases are considered relevant.
|
||||
*/
|
||||
std::vector<const JsonSerializationCodeGenerator::RelevantClass *> JsonSerializationCodeGenerator::findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases)
|
||||
{
|
||||
vector<const RelevantClass *> relevantBaseClasses;
|
||||
for (const RelevantClass &otherClass : relevantBases) {
|
||||
if (relevantClass.record != otherClass.record && relevantClass.record->isDerivedFrom(otherClass.record)) {
|
||||
relevantBaseClasses.push_back(&otherClass);
|
||||
}
|
||||
}
|
||||
return relevantBaseClasses;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates pull() and push() helper functions in the ReflectiveRapidJSON::JsonReflector namespace for the relevant classes.
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef REFLECTIVE_RAPIDJSON_CODE_JSON_SERIALIZATION_GENERATOR_H
|
||||
#define REFLECTIVE_RAPIDJSON_CODE_JSON_SERIALIZATION_GENERATOR_H
|
||||
|
||||
#include "./codegenerator.h"
|
||||
#include "./serializationcodegenerator.h"
|
||||
|
||||
#include <c++utilities/application/argumentparser.h>
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace ReflectiveRapidJSON {
|
|||
* \brief The JsonSerializationCodeGenerator class generates code for JSON (de)serialization
|
||||
* of objects inheriting from an instantiation of JsonSerializable.
|
||||
*/
|
||||
class JsonSerializationCodeGenerator : public CodeGenerator {
|
||||
class JsonSerializationCodeGenerator : public SerializationCodeGenerator {
|
||||
public:
|
||||
struct Options {
|
||||
Options();
|
||||
|
@ -22,49 +22,22 @@ public:
|
|||
ApplicationUtilities::ConfigValueArgument visibilityArg;
|
||||
};
|
||||
|
||||
private:
|
||||
struct RelevantClass {
|
||||
explicit RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record);
|
||||
|
||||
std::string qualifiedName;
|
||||
clang::CXXRecordDecl *record;
|
||||
};
|
||||
|
||||
public:
|
||||
JsonSerializationCodeGenerator(CodeFactory &factory, const Options &options);
|
||||
|
||||
void addDeclaration(clang::Decl *decl) override;
|
||||
void generate(std::ostream &os) const override;
|
||||
|
||||
private:
|
||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const;
|
||||
std::vector<RelevantClass> findRelevantClasses() const;
|
||||
static std::vector<const RelevantClass *> findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases);
|
||||
protected:
|
||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const override;
|
||||
|
||||
std::vector<clang::CXXRecordDecl *> m_records;
|
||||
std::vector<RelevantClass> m_adaptionRecords;
|
||||
const Options &m_options;
|
||||
};
|
||||
|
||||
inline JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory, const Options &options)
|
||||
: CodeGenerator(factory)
|
||||
, m_options(options)
|
||||
{
|
||||
}
|
||||
|
||||
inline void JsonSerializationCodeGenerator::Options::appendTo(ApplicationUtilities::Argument *arg)
|
||||
{
|
||||
arg->addSubArgument(&additionalClassesArg);
|
||||
arg->addSubArgument(&visibilityArg);
|
||||
}
|
||||
|
||||
inline JsonSerializationCodeGenerator::RelevantClass::RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record)
|
||||
: qualifiedName(qualifiedName)
|
||||
, record(record)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace ReflectiveRapidJSON
|
||||
|
||||
#endif // REFLECTIVE_RAPIDJSON_CODE_JSON_SERIALIZATION_GENERATOR_H
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
#include "./serializationcodegenerator.h"
|
||||
|
||||
#include <c++utilities/application/global.h>
|
||||
|
||||
#include <clang/AST/DeclCXX.h>
|
||||
#include <clang/AST/DeclFriend.h>
|
||||
#include <clang/AST/DeclTemplate.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace ReflectiveRapidJSON {
|
||||
|
||||
/*!
|
||||
* \brief Prints an LLVM string reference without instantiating a std::string first.
|
||||
*/
|
||||
ostream &operator<<(ostream &os, llvm::StringRef str)
|
||||
{
|
||||
return os.write(str.data(), static_cast<streamsize>(str.size()));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds all class declarations (to the internal member variable m_records).
|
||||
* \remarks "AdaptedXXXSerializable" specializations are directly filtered and added to m_adaptionRecords (instead of m_records).
|
||||
*/
|
||||
void SerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
||||
{
|
||||
switch (decl->getKind()) {
|
||||
case clang::Decl::Kind::CXXRecord:
|
||||
case clang::Decl::Kind::ClassTemplateSpecialization: {
|
||||
auto *const record = static_cast<clang::CXXRecordDecl *>(decl);
|
||||
// skip forward declarations
|
||||
if (!record->hasDefinition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for template specializations to adapt a 3rd party class/struct
|
||||
if (m_qualifiedNameOfAdaptionRecords && decl->getKind() == clang::Decl::Kind::ClassTemplateSpecialization) {
|
||||
auto *const templateSpecializationRecord = static_cast<clang::ClassTemplateSpecializationDecl *>(decl);
|
||||
// check whether the name of the template specialization matches
|
||||
if (templateSpecializationRecord->getQualifiedNameAsString() == m_qualifiedNameOfAdaptionRecords) {
|
||||
// get the template argument of the template specialization (exactly one argument expected)
|
||||
const auto &templateArgs = templateSpecializationRecord->getTemplateArgs();
|
||||
if (templateArgs.size() != 1 || templateArgs.get(0).getKind() != clang::TemplateArgument::Type) {
|
||||
return; // FIXME: use Clang diagnostics to print warning
|
||||
}
|
||||
// get the type the template argument refers to (that's the type of the 3rd party class/struct to adapt)
|
||||
auto *const templateRecord = templateArgs.get(0).getAsType()->getAsCXXRecordDecl();
|
||||
if (!templateRecord) {
|
||||
return; // FIXME: use Clang diagnostics to print warning
|
||||
}
|
||||
// save the relevant information for the code generation
|
||||
m_adaptionRecords.emplace_back(templateRecord->getQualifiedNameAsString(), templateSpecializationRecord);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add any other records
|
||||
m_records.emplace_back(record);
|
||||
} break;
|
||||
case clang::Decl::Kind::Enum:
|
||||
// TODO: add enums
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
SerializationCodeGenerator::IsRelevant SerializationCodeGenerator::isQualifiedNameIfRelevant(clang::CXXRecordDecl *record, const std::string &qualifiedName) const
|
||||
{
|
||||
// consider all classes for which a specialization of the "AdaptedJsonSerializable" struct is available
|
||||
for (const auto &adaptionRecord : m_adaptionRecords) {
|
||||
// skip all adaption records which are only included
|
||||
if (isOnlyIncluded(adaptionRecord.record)) {
|
||||
continue;
|
||||
}
|
||||
if (adaptionRecord.qualifiedName == qualifiedName) {
|
||||
return IsRelevant::Yes;
|
||||
}
|
||||
}
|
||||
|
||||
// skip all classes which are only included
|
||||
if (isOnlyIncluded(record)) {
|
||||
return IsRelevant::No;
|
||||
}
|
||||
|
||||
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
||||
if (inheritsFromInstantiationOf(record, m_qualifiedNameOfRecords)) {
|
||||
return IsRelevant::Yes;
|
||||
}
|
||||
|
||||
return IsRelevant::Maybe;
|
||||
}
|
||||
|
||||
std::vector<SerializationCodeGenerator::RelevantClass> SerializationCodeGenerator::findRelevantClasses() const
|
||||
{
|
||||
std::vector<RelevantClass> relevantClasses;
|
||||
for (clang::CXXRecordDecl *record : m_records) {
|
||||
string qualifiedName(qualifiedNameIfRelevant(record));
|
||||
if (!qualifiedName.empty()) {
|
||||
relevantClasses.emplace_back(move(qualifiedName), record);
|
||||
}
|
||||
}
|
||||
return relevantClasses;
|
||||
}
|
||||
|
||||
std::vector<const SerializationCodeGenerator::RelevantClass *> SerializationCodeGenerator::findRelevantBaseClasses(const SerializationCodeGenerator::RelevantClass &relevantClass, const std::vector<SerializationCodeGenerator::RelevantClass> &relevantBases)
|
||||
{
|
||||
vector<const RelevantClass *> relevantBaseClasses;
|
||||
for (const RelevantClass &otherClass : relevantBases) {
|
||||
if (relevantClass.record != otherClass.record && relevantClass.record->isDerivedFrom(otherClass.record)) {
|
||||
relevantBaseClasses.push_back(&otherClass);
|
||||
}
|
||||
}
|
||||
return relevantBaseClasses;
|
||||
}
|
||||
|
||||
} // namespace ReflectiveRapidJSON
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef REFLECTIVE_RAPIDJSON_SERIALIZATION_CODE_GENERATOR_H
|
||||
#define REFLECTIVE_RAPIDJSON_SERIALIZATION_CODE_GENERATOR_H
|
||||
|
||||
#include "./codegenerator.h"
|
||||
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
|
||||
namespace ReflectiveRapidJSON {
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, llvm::StringRef str);
|
||||
|
||||
/*!
|
||||
* \brief The SerializationCodeGenerator class is the common base for (de)serialization
|
||||
* related code generation.
|
||||
*/
|
||||
class SerializationCodeGenerator : public CodeGenerator {
|
||||
public:
|
||||
struct RelevantClass {
|
||||
explicit RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record);
|
||||
|
||||
std::string qualifiedName;
|
||||
clang::CXXRecordDecl *record;
|
||||
};
|
||||
|
||||
SerializationCodeGenerator(CodeFactory &factory);
|
||||
|
||||
void addDeclaration(clang::Decl *decl) override;
|
||||
|
||||
protected:
|
||||
enum class IsRelevant {
|
||||
Yes, No, Maybe
|
||||
};
|
||||
IsRelevant isQualifiedNameIfRelevant(clang::CXXRecordDecl *record, const std::string &qualifiedName) const;
|
||||
virtual std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const = 0;
|
||||
std::vector<RelevantClass> findRelevantClasses() const;
|
||||
static std::vector<const RelevantClass *> findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass, const std::vector<RelevantClass> &relevantBases);
|
||||
|
||||
protected:
|
||||
const char *m_qualifiedNameOfRecords;
|
||||
const char *m_qualifiedNameOfAdaptionRecords;
|
||||
|
||||
private:
|
||||
std::vector<clang::CXXRecordDecl *> m_records;
|
||||
std::vector<RelevantClass> m_adaptionRecords;
|
||||
};
|
||||
|
||||
inline SerializationCodeGenerator::RelevantClass::RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record)
|
||||
: qualifiedName(qualifiedName)
|
||||
, record(record)
|
||||
{
|
||||
}
|
||||
|
||||
inline SerializationCodeGenerator::SerializationCodeGenerator(CodeFactory &factory)
|
||||
: CodeGenerator(factory)
|
||||
, m_qualifiedNameOfRecords(nullptr)
|
||||
, m_qualifiedNameOfAdaptionRecords(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace ReflectiveRapidJSON
|
||||
|
||||
#endif // REFLECTIVE_RAPIDJSON_SERIALIZATION_CODE_GENERATOR_H
|
Loading…
Reference in New Issue