#include "./serializationcodegenerator.h" #include #include #include #include #include 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(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(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(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:; } } void SerializationCodeGenerator::computeRelevantClass(RelevantClass &possiblyRelevantClass) const { // skip all classes which are only forward-declared if (!possiblyRelevantClass.record->isCompleteDefinition()) { possiblyRelevantClass.isRelevant = IsRelevant::No; return; } // 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 == possiblyRelevantClass.qualifiedName) { possiblyRelevantClass.isRelevant = IsRelevant::Yes; return; } } // skip all classes which are only included if (isOnlyIncluded(possiblyRelevantClass.record)) { possiblyRelevantClass.isRelevant = IsRelevant::No; return; } // consider all classes inheriting from an instantiation of "JsonSerializable" relevant if (const auto *const relevantBase = inheritsFromInstantiationOf(possiblyRelevantClass.record, m_qualifiedNameOfRecords)) { cerr << "record: " << possiblyRelevantClass.qualifiedName << '\n'; for (const clang::CXXBaseSpecifier base : possiblyRelevantClass.record->bases()) { cerr << "base: " << base.getType().getAsString() << '\n'; } cerr << "relevant base: " << relevantBase->getType().getAsString(); possiblyRelevantClass.relevantBase = relevantBase->getType().getAsString(); possiblyRelevantClass.isRelevant = IsRelevant::Yes; return; } } std::vector SerializationCodeGenerator::findRelevantClasses() const { std::vector relevantClasses; for (clang::CXXRecordDecl *const record : m_records) { auto &relevantClass = relevantClasses.emplace_back(record->getQualifiedNameAsString(), record); computeRelevantClass(relevantClass); if (relevantClass.isRelevant != IsRelevant::Yes) { relevantClasses.pop_back(); } } return relevantClasses; } std::vector SerializationCodeGenerator::findRelevantBaseClasses( const SerializationCodeGenerator::RelevantClass &relevantClass, const std::vector &relevantBases) { vector relevantBaseClasses; for (const RelevantClass &otherClass : relevantBases) { if (relevantClass.record != otherClass.record && relevantClass.record->isDerivedFrom(otherClass.record)) { relevantBaseClasses.push_back(&otherClass); } } return relevantBaseClasses; } } // namespace ReflectiveRapidJSON