Allow specifying additional classes for JSON serialization
This commit is contained in:
parent
d039daf938
commit
a7feb57f22
|
@ -33,7 +33,7 @@ public:
|
|||
~CodeFactory();
|
||||
|
||||
const std::vector<std::unique_ptr<CodeGenerator>> &generators() const;
|
||||
template <typename GeneratorType> void addGenerator();
|
||||
template <typename GeneratorType, typename... Args> void addGenerator(Args &&... args);
|
||||
|
||||
bool run();
|
||||
clang::CompilerInstance *compilerInstance();
|
||||
|
@ -55,9 +55,9 @@ private:
|
|||
clang::CompilerInstance *m_compilerInstance;
|
||||
};
|
||||
|
||||
template <typename GeneratorType> void CodeFactory::addGenerator()
|
||||
template <typename GeneratorType, typename... Args> void CodeFactory::addGenerator(Args &&... args)
|
||||
{
|
||||
m_generators.emplace_back(std::make_unique<GeneratorType>(*this));
|
||||
m_generators.emplace_back(std::make_unique<GeneratorType>(*this, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
inline const std::vector<std::unique_ptr<CodeGenerator>> &CodeFactory::generators() const
|
||||
|
|
|
@ -7,9 +7,18 @@
|
|||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace ApplicationUtilities;
|
||||
|
||||
namespace ReflectiveRapidJSON {
|
||||
|
||||
JsonSerializationCodeGenerator::Options::Options()
|
||||
: additionalClassesArg("json-classes", '\0', "specifies additional classes to consider for JSON serialization")
|
||||
{
|
||||
additionalClassesArg.setCombinable(true);
|
||||
additionalClassesArg.setValueNames({ "class-name" });
|
||||
additionalClassesArg.setRequiredValueCount(Argument::varValueCount);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Prints an LLVM string reference without instantiating a std::string first.
|
||||
*/
|
||||
|
@ -29,8 +38,10 @@ void JsonSerializationCodeGenerator::addDeclaration(clang::Decl *decl)
|
|||
return;
|
||||
}
|
||||
// add classes derived from any instantiation of "ReflectiveRapidJSON::JsonSerializable"
|
||||
if (inheritsFromInstantiationOf(record, JsonSerializable<void>::qualifiedName)) {
|
||||
m_relevantClasses.emplace_back(record->getQualifiedNameAsString(), record);
|
||||
// and also add classes explicitely specified via "--additional-classes" argument
|
||||
string qualifiedName(qualifiedNameIfRelevant(record));
|
||||
if (!qualifiedName.empty()) {
|
||||
m_relevantClasses.emplace_back(move(qualifiedName), record);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -106,6 +117,31 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const
|
|||
"} // namespace ReflectiveRapidJSON\n";
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the qualified name of the specified \a record if it is considered relevant.
|
||||
*/
|
||||
string JsonSerializationCodeGenerator::qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const
|
||||
{
|
||||
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
||||
if (inheritsFromInstantiationOf(record, JsonSerializable<void>::qualifiedName)) {
|
||||
return record->getQualifiedNameAsString();
|
||||
}
|
||||
|
||||
// consider all classes specified via "--additional-classes" argument relevant
|
||||
if (!m_options.additionalClassesArg.isPresent()) {
|
||||
return string();
|
||||
}
|
||||
|
||||
const string qualifiedName(record->getQualifiedNameAsString());
|
||||
for (const char *className : m_options.additionalClassesArg.values()) {
|
||||
if (className == qualifiedName) {
|
||||
return qualifiedName;
|
||||
}
|
||||
}
|
||||
|
||||
return string();
|
||||
}
|
||||
|
||||
std::vector<const JsonSerializationCodeGenerator::RelevantClass *> JsonSerializationCodeGenerator::findRelevantBaseClasses(
|
||||
const RelevantClass &relevantClass) const
|
||||
{
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "./codegenerator.h"
|
||||
|
||||
#include <c++utilities/application/argumentparser.h>
|
||||
|
||||
namespace ReflectiveRapidJSON {
|
||||
|
||||
/*!
|
||||
|
@ -11,30 +13,41 @@ namespace ReflectiveRapidJSON {
|
|||
*/
|
||||
class JsonSerializationCodeGenerator : public CodeGenerator {
|
||||
public:
|
||||
JsonSerializationCodeGenerator(CodeFactory &factory);
|
||||
struct Options {
|
||||
Options();
|
||||
|
||||
void addDeclaration(clang::Decl *decl) override;
|
||||
void generate(std::ostream &os) const override;
|
||||
ApplicationUtilities::Argument additionalClassesArg;
|
||||
};
|
||||
|
||||
private:
|
||||
struct RelevantClass {
|
||||
explicit RelevantClass(const std::string &qualifiedName, clang::CXXRecordDecl *record);
|
||||
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;
|
||||
std::string qualifiedNameIfRelevant(clang::CXXRecordDecl *record) const;
|
||||
|
||||
private:
|
||||
std::vector<const RelevantClass *> findRelevantBaseClasses(const RelevantClass &relevantClass) const;
|
||||
|
||||
std::vector<RelevantClass> m_relevantClasses;
|
||||
const Options &m_options;
|
||||
};
|
||||
|
||||
inline JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory)
|
||||
inline JsonSerializationCodeGenerator::JsonSerializationCodeGenerator(CodeFactory &factory, const Options &options)
|
||||
: CodeGenerator(factory)
|
||||
, m_options(options)
|
||||
{
|
||||
}
|
||||
|
||||
inline JsonSerializationCodeGenerator::RelevantClass::RelevantClass(const std::string &qualifiedName, clang::CXXRecordDecl *record)
|
||||
inline JsonSerializationCodeGenerator::RelevantClass::RelevantClass(std::string &&qualifiedName, clang::CXXRecordDecl *record)
|
||||
: qualifiedName(qualifiedName)
|
||||
, record(record)
|
||||
{
|
||||
|
|
|
@ -27,8 +27,9 @@ int main(int argc, char *argv[])
|
|||
|
||||
// setup argument parser
|
||||
ArgumentParser parser;
|
||||
OperationArgument generateArg("generate", 'g', "runs the code generator");
|
||||
generateArg.setImplicit(true);
|
||||
ConfigValueArgument inputFileArg("input-file", 'i', "specifies the input file", { "path" });
|
||||
inputFileArg.setRequired(true);
|
||||
ConfigValueArgument outputFileArg("output-file", 'o', "specifies the output file", { "path" });
|
||||
Argument generatorsArg("generators", 'g', "specifies the generators (by default all generators are enabled)");
|
||||
generatorsArg.setValueNames({ "json" });
|
||||
|
@ -36,9 +37,11 @@ int main(int argc, char *argv[])
|
|||
generatorsArg.setRequiredValueCount(Argument::varValueCount);
|
||||
generatorsArg.setCombinable(true);
|
||||
ConfigValueArgument clangOptionsArg("clang-opt", 'c', "specifies an argument to be passed to Clang", { "option" });
|
||||
JsonSerializationCodeGenerator::Options jsonOptions;
|
||||
HelpArgument helpArg(parser);
|
||||
NoColorArgument noColorArg;
|
||||
parser.setMainArguments({ &inputFileArg, &outputFileArg, &generatorsArg, &clangOptionsArg, &noColorArg, &helpArg });
|
||||
generateArg.setSubArguments({ &inputFileArg, &outputFileArg, &generatorsArg, &clangOptionsArg, &jsonOptions.additionalClassesArg });
|
||||
parser.setMainArguments({ &generateArg, &noColorArg, &helpArg });
|
||||
|
||||
// parse arguments
|
||||
parser.parseArgsOrExit(argc, argv);
|
||||
|
@ -67,7 +70,7 @@ int main(int argc, char *argv[])
|
|||
// find and construct generators by name
|
||||
for (const char *generatorName : generatorsArg.values(0)) {
|
||||
if (!strcmp(generatorName, "json")) {
|
||||
factory.addGenerator<JsonSerializationCodeGenerator>();
|
||||
factory.addGenerator<JsonSerializationCodeGenerator>(jsonOptions);
|
||||
} else {
|
||||
cerr << Phrases::Error << "The specified generator \"" << generatorName << "\" does not exist." << Phrases::EndFlush;
|
||||
return -5;
|
||||
|
@ -75,7 +78,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
} else {
|
||||
// add default generators
|
||||
factory.addGenerator<JsonSerializationCodeGenerator>();
|
||||
factory.addGenerator<JsonSerializationCodeGenerator>(jsonOptions);
|
||||
}
|
||||
|
||||
// read AST elements from input files and run the code generator
|
||||
|
|
|
@ -66,8 +66,9 @@ void JsonGeneratorTests::testGeneratorItself()
|
|||
const vector<const char *> clangOptions{};
|
||||
|
||||
stringstream buffer;
|
||||
JsonSerializationCodeGenerator::Options jsonOptions;
|
||||
CodeFactory factory(TestApplication::appPath(), inputFiles, clangOptions, buffer);
|
||||
factory.addGenerator<JsonSerializationCodeGenerator>();
|
||||
factory.addGenerator<JsonSerializationCodeGenerator>(jsonOptions);
|
||||
CPPUNIT_ASSERT(factory.run());
|
||||
assertEqualityLinewise(m_expectedCode, toArrayOfLines(buffer.str()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue