File indexing completed on 2024-05-12 04:37:48
0001 /* 0002 SPDX-FileCopyrightText: 2012 Miha Čančula <miha@noughmad.eu> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "templateclassgenerator.h" 0008 #include "archivetemplateloader.h" 0009 #include <debug.h> 0010 0011 #include <interfaces/iproject.h> 0012 #include "language/codegen/documentchangeset.h" 0013 #include "codedescription.h" 0014 #include "templaterenderer.h" 0015 #include "sourcefiletemplate.h" 0016 #include <duchain/declaration.h> 0017 #include <duchain/duchainlock.h> 0018 #include <duchain/persistentsymboltable.h> 0019 #include <duchain/types/structuretype.h> 0020 #include <project/projectmodel.h> 0021 0022 #include <QFileInfo> 0023 0024 #include <array> 0025 0026 using namespace KDevelop; 0027 0028 /// @param base String such as 'public QObject' or 'QObject' 0029 InheritanceDescription descriptionFromString(const QString& base) 0030 { 0031 QStringList splitBase = base.split(QLatin1Char(' ')); 0032 QString identifier = splitBase.takeLast(); 0033 QString inheritanceMode = splitBase.join(QLatin1Char(' ')); 0034 0035 InheritanceDescription desc; 0036 desc.baseType = identifier; 0037 desc.inheritanceMode = inheritanceMode; 0038 return desc; 0039 } 0040 0041 class KDevelop::TemplateClassGeneratorPrivate 0042 { 0043 public: 0044 SourceFileTemplate fileTemplate; 0045 QUrl baseUrl; 0046 // changes state when rendering 0047 mutable TemplateRenderer renderer; 0048 0049 QString name; 0050 QString identifier; 0051 QStringList namespaces; 0052 QString license; 0053 0054 // lazily estimated 0055 mutable QHash<QString, QUrl> fileUrls; 0056 QHash<QString, KTextEditor::Cursor> filePositions; 0057 ClassDescription description; 0058 0059 QList<DeclarationPointer> directBaseClasses; 0060 QList<DeclarationPointer> allBaseClasses; 0061 0062 void fetchSuperClasses(const DeclarationPointer& declaration); 0063 }; 0064 0065 void TemplateClassGeneratorPrivate::fetchSuperClasses(const DeclarationPointer& declaration) 0066 { 0067 DUChainReadLocker lock; 0068 0069 //Prevent duplicity 0070 if (allBaseClasses.contains(declaration)) { 0071 return; 0072 } 0073 0074 allBaseClasses << declaration; 0075 0076 DUContext* context = declaration->internalContext(); 0077 if (context) { 0078 const auto importedParentContexts = context->importedParentContexts(); 0079 for (const DUContext::Import& import : importedParentContexts) { 0080 if (DUContext* parentContext = import.context(context->topContext())) { 0081 if (parentContext->type() == DUContext::Class) { 0082 fetchSuperClasses(DeclarationPointer(parentContext->owner())); 0083 } 0084 } 0085 } 0086 } 0087 } 0088 0089 TemplateClassGenerator::TemplateClassGenerator(const QUrl& baseUrl) 0090 : d_ptr(new TemplateClassGeneratorPrivate) 0091 { 0092 Q_D(TemplateClassGenerator); 0093 0094 Q_ASSERT(QFileInfo(baseUrl.toLocalFile()).isDir()); // assume folder 0095 0096 d->baseUrl = baseUrl; 0097 d->renderer.setEmptyLinesPolicy(TemplateRenderer::TrimEmptyLines); 0098 } 0099 0100 TemplateClassGenerator::~TemplateClassGenerator() = default; 0101 0102 void TemplateClassGenerator::setTemplateDescription(const SourceFileTemplate& fileTemplate) 0103 { 0104 Q_D(TemplateClassGenerator); 0105 0106 d->fileTemplate = fileTemplate; 0107 Q_ASSERT(fileTemplate.isValid()); 0108 } 0109 0110 DocumentChangeSet TemplateClassGenerator::generate() 0111 { 0112 Q_D(TemplateClassGenerator); 0113 0114 return d->renderer.renderFileTemplate(d->fileTemplate, d->baseUrl, fileUrls()); 0115 } 0116 0117 QHash<QString, QString> TemplateClassGenerator::fileLabels() const 0118 { 0119 Q_D(const TemplateClassGenerator); 0120 0121 Q_ASSERT(d->fileTemplate.isValid()); 0122 QHash<QString, QString> labels; 0123 0124 const auto outputFiles = d->fileTemplate.outputFiles(); 0125 labels.reserve(outputFiles.size()); 0126 for (const SourceFileTemplate::OutputFile& outputFile : outputFiles) { 0127 labels.insert(outputFile.identifier, outputFile.label); 0128 } 0129 0130 return labels; 0131 } 0132 0133 TemplateClassGenerator::UrlHash TemplateClassGenerator::fileUrls() const 0134 { 0135 Q_D(const TemplateClassGenerator); 0136 0137 if (d->fileUrls.isEmpty()) { 0138 const auto outputFiles = d->fileTemplate.outputFiles(); 0139 for (const SourceFileTemplate::OutputFile& outputFile : outputFiles) { 0140 QString outputName = d->renderer.render(outputFile.outputName, outputFile.identifier); 0141 QUrl url = d->baseUrl.resolved(QUrl(outputName)); 0142 d->fileUrls.insert(outputFile.identifier, url); 0143 } 0144 } 0145 0146 return d->fileUrls; 0147 } 0148 0149 QUrl TemplateClassGenerator::baseUrl() const 0150 { 0151 Q_D(const TemplateClassGenerator); 0152 0153 return d->baseUrl; 0154 } 0155 0156 QUrl TemplateClassGenerator::fileUrl(const QString& outputFile) const 0157 { 0158 return fileUrls().value(outputFile); 0159 } 0160 0161 void TemplateClassGenerator::setFileUrl(const QString& outputFile, const QUrl& url) 0162 { 0163 Q_D(TemplateClassGenerator); 0164 0165 d->fileUrls.insert(outputFile, url); 0166 d->renderer.addVariable(QLatin1String("output_file_") + outputFile.toLower(), QDir( 0167 d->baseUrl.path()).relativeFilePath(url.path())); 0168 d->renderer.addVariable(QLatin1String("output_file_") + outputFile.toLower() + QLatin1String( 0169 "_absolute"), url.toLocalFile()); 0170 } 0171 0172 KTextEditor::Cursor TemplateClassGenerator::filePosition(const QString& outputFile) const 0173 { 0174 Q_D(const TemplateClassGenerator); 0175 0176 return d->filePositions.value(outputFile); 0177 } 0178 0179 void TemplateClassGenerator::setFilePosition(const QString& outputFile, const KTextEditor::Cursor& position) 0180 { 0181 Q_D(TemplateClassGenerator); 0182 0183 d->filePositions.insert(outputFile, position); 0184 } 0185 0186 void TemplateClassGenerator::addVariables(const QVariantHash& variables) 0187 { 0188 Q_D(TemplateClassGenerator); 0189 0190 d->renderer.addVariables(variables); 0191 } 0192 0193 QString TemplateClassGenerator::renderString(const QString& text) const 0194 { 0195 Q_D(const TemplateClassGenerator); 0196 0197 return d->renderer.render(text); 0198 } 0199 0200 SourceFileTemplate TemplateClassGenerator::sourceFileTemplate() const 0201 { 0202 Q_D(const TemplateClassGenerator); 0203 0204 return d->fileTemplate; 0205 } 0206 0207 TemplateRenderer* TemplateClassGenerator::renderer() const 0208 { 0209 Q_D(const TemplateClassGenerator); 0210 0211 return &(d->renderer); 0212 } 0213 0214 QString TemplateClassGenerator::name() const 0215 { 0216 Q_D(const TemplateClassGenerator); 0217 0218 return d->name; 0219 } 0220 0221 void TemplateClassGenerator::setName(const QString& newName) 0222 { 0223 Q_D(TemplateClassGenerator); 0224 0225 d->name = newName; 0226 d->renderer.addVariable(QStringLiteral("name"), newName); 0227 } 0228 0229 QString TemplateClassGenerator::identifier() const 0230 { 0231 return name(); 0232 } 0233 0234 void TemplateClassGenerator::setIdentifier(const QString& identifier) 0235 { 0236 Q_D(TemplateClassGenerator); 0237 0238 d->renderer.addVariable(QStringLiteral("identifier"), identifier); 0239 const std::array<QString,5> separators { 0240 QStringLiteral("::"), 0241 QStringLiteral("."), 0242 QStringLiteral(":"), 0243 QStringLiteral("\\"), 0244 QStringLiteral("/"), 0245 }; 0246 QStringList ns; 0247 for (const QString& separator : separators) { 0248 ns = identifier.split(separator); 0249 if (ns.size() > 1) { 0250 break; 0251 } 0252 } 0253 0254 setName(ns.takeLast()); 0255 setNamespaces(ns); 0256 } 0257 0258 QStringList TemplateClassGenerator::namespaces() const 0259 { 0260 Q_D(const TemplateClassGenerator); 0261 0262 return d->namespaces; 0263 } 0264 0265 void TemplateClassGenerator::setNamespaces(const QStringList& namespaces) 0266 { 0267 Q_D(TemplateClassGenerator); 0268 0269 d->namespaces = namespaces; 0270 d->renderer.addVariable(QStringLiteral("namespaces"), namespaces); 0271 } 0272 0273 /// Specify license for this class 0274 void TemplateClassGenerator::setLicense(const QString& license) 0275 { 0276 Q_D(TemplateClassGenerator); 0277 0278 qCDebug(LANGUAGE) << "New Class: " << d->name << "Set license: " << d->license; 0279 d->license = license; 0280 d->renderer.addVariable(QStringLiteral("license"), license); 0281 } 0282 0283 /// Get the license specified for this classes 0284 QString TemplateClassGenerator::license() const 0285 { 0286 Q_D(const TemplateClassGenerator); 0287 0288 return d->license; 0289 } 0290 0291 void TemplateClassGenerator::setDescription(const ClassDescription& description) 0292 { 0293 Q_D(TemplateClassGenerator); 0294 0295 d->description = description; 0296 0297 QVariantHash variables; 0298 variables[QStringLiteral("description")] = QVariant::fromValue(description); 0299 variables[QStringLiteral("members")] = CodeDescription::toVariantList(description.members); 0300 variables[QStringLiteral("functions")] = CodeDescription::toVariantList(description.methods); 0301 variables[QStringLiteral("base_classes")] = CodeDescription::toVariantList(description.baseClasses); 0302 d->renderer.addVariables(variables); 0303 } 0304 0305 ClassDescription TemplateClassGenerator::description() const 0306 { 0307 Q_D(const TemplateClassGenerator); 0308 0309 return d->description; 0310 } 0311 0312 void TemplateClassGenerator::addBaseClass(const QString& base) 0313 { 0314 Q_D(TemplateClassGenerator); 0315 0316 const InheritanceDescription desc = descriptionFromString(base); 0317 0318 ClassDescription cd = description(); 0319 cd.baseClasses << desc; 0320 setDescription(cd); 0321 0322 //Search for all super classes 0323 auto visitor = [&](const IndexedDeclaration& indexedDeclaration) { 0324 auto declaration = DeclarationPointer(indexedDeclaration.declaration()); 0325 if (!declaration || declaration->isForwardDeclaration()) { 0326 return PersistentSymbolTable::VisitorState::Continue; 0327 } 0328 0329 // Check if it's a class/struct/etc 0330 if (declaration->type<StructureType>()) { 0331 d->fetchSuperClasses(declaration); 0332 d->directBaseClasses << declaration; 0333 return PersistentSymbolTable::VisitorState::Break; 0334 } 0335 return PersistentSymbolTable::VisitorState::Continue; 0336 }; 0337 const auto id = IndexedQualifiedIdentifier(QualifiedIdentifier(desc.baseType)); 0338 0339 DUChainReadLocker lock; 0340 PersistentSymbolTable::self().visitDeclarations(id, visitor); 0341 } 0342 0343 void TemplateClassGenerator::setBaseClasses(const QList<QString>& bases) 0344 { 0345 Q_D(TemplateClassGenerator); 0346 0347 // clear 0348 ClassDescription cd = description(); 0349 cd.baseClasses.clear(); 0350 setDescription(cd); 0351 0352 d->directBaseClasses.clear(); 0353 d->allBaseClasses.clear(); 0354 0355 // add all bases 0356 for (const QString& base : bases) { 0357 addBaseClass(base); 0358 } 0359 } 0360 0361 QList<DeclarationPointer> TemplateClassGenerator::directBaseClasses() const 0362 { 0363 Q_D(const TemplateClassGenerator); 0364 0365 return d->directBaseClasses; 0366 } 0367 0368 QList<DeclarationPointer> TemplateClassGenerator::allBaseClasses() const 0369 { 0370 Q_D(const TemplateClassGenerator); 0371 0372 return d->allBaseClasses; 0373 }