kde-extraapps/kdevelop/languages/cpp/codegen/cppclasshelper.cpp
2015-07-26 14:23:17 +03:00

219 lines
6.2 KiB
C++

/*
* KDevelop C++ Language Support
*
* Copyright 2008 Hamish Rodda <rodda@kde.org>
* Copyright 2012 Miha Čančula <miha@noughmad.eu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "cppclasshelper.h"
#include <codecompletion/missingincludeitem.h>
#include <language/duchain/declaration.h>
#include <language/codegen/documentchangeset.h>
#include <language/codegen/codedescription.h>
#include <KTemporaryFile>
using namespace KDevelop;
CppClassHelper::CppClassHelper()
{
}
CppClassHelper::~CppClassHelper()
{
}
TemplateClassGenerator* CppClassHelper::createGenerator(const KUrl& baseUrl)
{
return new CppTemplateNewClass(baseUrl);
}
QList<DeclarationPointer> CppClassHelper::defaultMethods(const QString& name) const
{
KTemporaryFile file;
file.setSuffix( ".cpp" );
file.setAutoRemove(false);
file.open();
QTextStream stream(&file);
stream << "class " << name << " {\n"
<< " public:\n"
// default ctor
<< " " << name << "();\n"
// copy ctor
<< " " << name << "(const " << name << "& other);\n"
// default dtor
<< " ~" << name << "();\n"
// assignment operator
<< " " << name << "& operator=(const " << name << "& other);\n"
// equality operator
<< " bool operator==(const " << name << "& other) const;\n"
<< "};\n";
file.close();
ReferencedTopDUContext context(DUChain::self()->waitForUpdate( IndexedString(file.fileName()),
TopDUContext::AllDeclarationsAndContexts ));
DUChainReadLocker lock;
QList<DeclarationPointer> methods;
if (context && context->childContexts().size() == 1) {
foreach (Declaration* declaration, context->childContexts().first()->localDeclarations())
{
methods << DeclarationPointer(declaration);
}
}
file.remove();
return methods;
}
CppTemplateNewClass::CppTemplateNewClass(const KUrl& url)
: TemplateClassGenerator(url)
{
}
CppTemplateNewClass::~CppTemplateNewClass()
{
}
QVariantHash CppTemplateNewClass::extraVariables()
{
QVariantHash variables;
QMap<QString, VariableDescriptionList> variableDescriptions;
QMap<QString, FunctionDescriptionList> functionDescriptions;
QMap<QString, FunctionDescriptionList> slotDescriptions;
FunctionDescriptionList signalDescriptions;
foreach (const FunctionDescription& function, description().methods)
{
QString access = function.access;
if (access.isEmpty())
{
access = "public";
}
if (function.isSignal)
{
signalDescriptions << function;
}
else if (function.isSlot)
{
slotDescriptions[access] << function;
}
else
{
functionDescriptions[access] << function;
}
}
foreach (const VariableDescription& variable, description().members)
{
QString access = variable.access;
if (access.isEmpty())
{
access = "public";
}
variableDescriptions[access] << variable;
}
QMap<QString, VariableDescriptionList>::const_iterator vit, vend;
vit = variableDescriptions.constBegin();
vend = variableDescriptions.constEnd();
for (; vit != vend; ++vit)
{
variables[vit.key() + "_members"] = CodeDescription::toVariantList(vit.value());
}
QMap<QString, FunctionDescriptionList>::const_iterator fit, fend;
fit = functionDescriptions.constBegin();
fend = functionDescriptions.constEnd();
for (; fit != fend; ++fit)
{
variables[fit.key() + "_functions"] = CodeDescription::toVariantList(fit.value());
}
fit = slotDescriptions.constBegin();
fend = slotDescriptions.constEnd();
for (; fit != fend; ++fit)
{
variables[fit.key() + "_slots"] = CodeDescription::toVariantList(fit.value());
}
variables["signals"] = CodeDescription::toVariantList(signalDescriptions);
variables["needs_qobject_macro"] = !slotDescriptions.isEmpty() || !signalDescriptions.isEmpty();
QStringList includedFiles;
DUChainReadLocker locker(DUChain::lock());
KUrl sourceUrl;
QHash<QString, KUrl> urls = fileUrls();
if (!urls.isEmpty())
{
sourceUrl = urls.constBegin().value();
}
else
{
// includeDirectiveFromUrl() expects a header URL
sourceUrl = baseUrl();
sourceUrl.addPath(name().toLower() + ".h");
}
foreach (const DeclarationPointer& base, directBaseClasses())
{
if (!base)
{
continue;
}
kDebug() << "Looking for includes for class" << base->identifier().toString();
KSharedPtr<Cpp::MissingIncludeCompletionItem> item = Cpp::includeDirectiveFromUrl(sourceUrl, IndexedDeclaration(base.data()));
if(item)
{
kDebug() << "Found one in" << item->m_canonicalPath;
includedFiles << item->m_addedInclude;
}
}
variables["included_files"] = includedFiles;
return variables;
}
DocumentChangeSet CppTemplateNewClass::generate()
{
addVariables(extraVariables());
return TemplateClassGenerator::generate();
}
void CppTemplateNewClass::addBaseClass(const QString& base)
{
//strip access specifier
QStringList splitBase = base.split(' ', QString::SkipEmptyParts);
//if no access specifier is found use public by default
if(splitBase.size() == 1)
{
splitBase.prepend("public");
}
//Call base function with the access specifier
TemplateClassGenerator::addBaseClass(splitBase.join(" "));
}