forked from qt-creator/qt-creator
"New Class" wizard: Check custom base class for QObject parent
That is, if the user specifies a custom base class, we check whether its constructor takes a "QObject *parent" parameter, and if it does, we give the derived class one as well. This is technically a heuristic, but the pattern is pretty stable in the Qt world. Fixes: QTCREATORBUG-25156 Change-Id: Ie64440929df61cca7258d6d692c5de62970f9a65 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -13,6 +13,8 @@ public:
|
|||||||
%{CN}::%{CN}(QObject *parent) : QObject(parent)%{JS: ('%{SharedDataInit}') ? ', %{SharedDataInit}' : ''}
|
%{CN}::%{CN}(QObject *parent) : QObject(parent)%{JS: ('%{SharedDataInit}') ? ', %{SharedDataInit}' : ''}
|
||||||
@elsif '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow'
|
@elsif '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow'
|
||||||
%{CN}::%{CN}(QWidget *parent) : %{Base}(parent)%{JS: ('%{SharedDataInit}') ? ', %{SharedDataInit}' : ''}
|
%{CN}::%{CN}(QWidget *parent) : %{Base}(parent)%{JS: ('%{SharedDataInit}') ? ', %{SharedDataInit}' : ''}
|
||||||
|
@elsif %{JS: Cpp.hasQObjectParent('%{Base}')}
|
||||||
|
%{CN}::%{CN}(QObject *parent) : %{Base}(parent)%{JS: ('%{SharedDataInit}') ? ', %{SharedDataInit}' : ''}
|
||||||
@else
|
@else
|
||||||
%{CN}::%{CN}()%{JS: ('%{SharedDataInit}') ? ' : %{SharedDataInit}' : ''}
|
%{CN}::%{CN}()%{JS: ('%{SharedDataInit}') ? ' : %{SharedDataInit}' : ''}
|
||||||
@endif
|
@endif
|
||||||
|
@@ -33,7 +33,7 @@ class %{CN}
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@endif
|
@endif
|
||||||
public:
|
public:
|
||||||
@if '%{Base}' === 'QObject'
|
@if '%{Base}' === 'QObject' || %{JS: Cpp.hasQObjectParent('%{Base}')}
|
||||||
explicit %{CN}(QObject *parent = nullptr);
|
explicit %{CN}(QObject *parent = nullptr);
|
||||||
@elsif '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow'
|
@elsif '%{Base}' === 'QWidget' || '%{Base}' === 'QMainWindow'
|
||||||
explicit %{CN}(QWidget *parent = nullptr);
|
explicit %{CN}(QWidget *parent = nullptr);
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#include "cpprefactoringchanges.h"
|
#include "cpprefactoringchanges.h"
|
||||||
#include "cpprefactoringengine.h"
|
#include "cpprefactoringengine.h"
|
||||||
#include "cppsourceprocessor.h"
|
#include "cppsourceprocessor.h"
|
||||||
|
#include "cpptoolsjsextension.h"
|
||||||
#include "cpptoolsplugin.h"
|
#include "cpptoolsplugin.h"
|
||||||
#include "cpptoolsconstants.h"
|
#include "cpptoolsconstants.h"
|
||||||
#include "cpptoolsreuse.h"
|
#include "cpptoolsreuse.h"
|
||||||
@@ -54,6 +55,7 @@
|
|||||||
#include <coreplugin/documentmanager.h>
|
#include <coreplugin/documentmanager.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/jsexpander.h>
|
||||||
#include <coreplugin/progressmanager/progressmanager.h>
|
#include <coreplugin/progressmanager/progressmanager.h>
|
||||||
#include <coreplugin/vcsmanager.h>
|
#include <coreplugin/vcsmanager.h>
|
||||||
#include <cplusplus/ASTPath.h>
|
#include <cplusplus/ASTPath.h>
|
||||||
@@ -575,6 +577,13 @@ CppModelManager *CppModelManager::instance()
|
|||||||
return m_instance;
|
return m_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppModelManager::registerJsExtension()
|
||||||
|
{
|
||||||
|
Core::JsExpander::registerGlobalObject("Cpp", [this] {
|
||||||
|
return new CppToolsJsExtension(&d->m_locatorData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void CppModelManager::initCppTools()
|
void CppModelManager::initCppTools()
|
||||||
{
|
{
|
||||||
// Objects
|
// Objects
|
||||||
|
@@ -98,6 +98,8 @@ public:
|
|||||||
|
|
||||||
static CppModelManager *instance();
|
static CppModelManager *instance();
|
||||||
|
|
||||||
|
void registerJsExtension();
|
||||||
|
|
||||||
// Documented in source file.
|
// Documented in source file.
|
||||||
enum ProgressNotificationMode {
|
enum ProgressNotificationMode {
|
||||||
ForcedProgressNotification,
|
ForcedProgressNotification,
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
#include "cpptoolsjsextension.h"
|
#include "cpptoolsjsextension.h"
|
||||||
|
|
||||||
#include "cppfilesettingspage.h"
|
#include "cppfilesettingspage.h"
|
||||||
|
#include "cpplocatordata.h"
|
||||||
|
#include "cppworkingcopy.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
@@ -33,9 +35,13 @@
|
|||||||
#include <projectexplorer/projectnodes.h>
|
#include <projectexplorer/projectnodes.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
|
|
||||||
|
#include <cplusplus/AST.h>
|
||||||
|
#include <cplusplus/ASTPath.h>
|
||||||
|
#include <cplusplus/Overview.h>
|
||||||
#include <utils/codegeneration.h>
|
#include <utils/codegeneration.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QElapsedTimer>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@@ -118,6 +124,90 @@ QString CppToolsJsExtension::closeNamespaces(const QString &klass) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CppToolsJsExtension::hasQObjectParent(const QString &klassName) const
|
||||||
|
{
|
||||||
|
// This is a synchronous function, but the look-up is potentially expensive.
|
||||||
|
// Since it's not crucial information, we just abort if retrieving it takes too long,
|
||||||
|
// in order not to freeze the UI.
|
||||||
|
// TODO: Any chance to at least cache between successive invocations for the same dialog?
|
||||||
|
// I don't see it atm...
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
static const int timeout = 5000;
|
||||||
|
|
||||||
|
// Find symbol.
|
||||||
|
QList<IndexItem::Ptr> candidates;
|
||||||
|
m_locatorData->filterAllFiles([&](const IndexItem::Ptr &item) {
|
||||||
|
if (timer.elapsed() > timeout)
|
||||||
|
return IndexItem::VisitorResult::Break;
|
||||||
|
if (item->scopedSymbolName() == klassName) {
|
||||||
|
candidates = {item};
|
||||||
|
return IndexItem::VisitorResult::Break;
|
||||||
|
}
|
||||||
|
if (item->symbolName() == klassName)
|
||||||
|
candidates << item;
|
||||||
|
return IndexItem::VisitorResult::Recurse;
|
||||||
|
});
|
||||||
|
if (timer.elapsed() > timeout)
|
||||||
|
return false;
|
||||||
|
if (candidates.isEmpty())
|
||||||
|
return false;
|
||||||
|
const IndexItem::Ptr item = candidates.first();
|
||||||
|
|
||||||
|
// Find class in AST.
|
||||||
|
const CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot();
|
||||||
|
const WorkingCopy workingCopy = CppModelManager::instance()->workingCopy();
|
||||||
|
QByteArray source = workingCopy.source(item->fileName());
|
||||||
|
if (source.isEmpty()) {
|
||||||
|
QFile file(item->fileName());
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
return false;
|
||||||
|
source = file.readAll();
|
||||||
|
}
|
||||||
|
const auto doc = snapshot.preprocessedDocument(source, item->fileName());
|
||||||
|
if (!doc)
|
||||||
|
return false;
|
||||||
|
doc->check();
|
||||||
|
if (!doc->translationUnit())
|
||||||
|
return false;
|
||||||
|
if (timer.elapsed() > timeout)
|
||||||
|
return false;
|
||||||
|
CPlusPlus::ClassSpecifierAST *classSpec = nullptr;
|
||||||
|
const QList<CPlusPlus::AST *> astPath = CPlusPlus::ASTPath(doc)(item->line(), item->column());
|
||||||
|
for (auto it = astPath.rbegin(); it != astPath.rend(); ++it) {
|
||||||
|
if ((classSpec = (*it)->asClassSpecifier()))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!classSpec)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check whether constructor has a QObject parent parameter.
|
||||||
|
CPlusPlus::Overview overview;
|
||||||
|
const CPlusPlus::Class * const klass = classSpec->symbol;
|
||||||
|
if (!klass)
|
||||||
|
return false;
|
||||||
|
for (auto it = klass->memberBegin(); it != klass->memberEnd(); ++it) {
|
||||||
|
const CPlusPlus::Symbol * const member = *it;
|
||||||
|
if (overview.prettyName(member->name()) != item->symbolName())
|
||||||
|
continue;
|
||||||
|
const CPlusPlus::Function *function = (*it)->asFunction();
|
||||||
|
if (!function)
|
||||||
|
function = member->type().type()->asFunctionType();
|
||||||
|
if (!function)
|
||||||
|
continue;
|
||||||
|
for (int i = 0; i < function->argumentCount(); ++i) {
|
||||||
|
const CPlusPlus::Symbol * const arg = function->argumentAt(i);
|
||||||
|
const QString argName = overview.prettyName(arg->name());
|
||||||
|
const QString argType = overview.prettyType(arg->type())
|
||||||
|
.split("::", Qt::SkipEmptyParts).last();
|
||||||
|
if (argName == "parent" && argType == "QObject *")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QString CppToolsJsExtension::includeStatement(
|
QString CppToolsJsExtension::includeStatement(
|
||||||
const QString &fullyQualifiedClassName,
|
const QString &fullyQualifiedClassName,
|
||||||
const QString &suffix,
|
const QString &suffix,
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
namespace CppTools {
|
namespace CppTools {
|
||||||
|
class CppLocatorData; // FIXME: Belongs in namespace Internal
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +42,8 @@ class CppToolsJsExtension : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CppToolsJsExtension(QObject *parent = nullptr) : QObject(parent) { }
|
explicit CppToolsJsExtension(CppLocatorData *locatorData, QObject *parent = nullptr)
|
||||||
|
: QObject(parent), m_locatorData(locatorData) { }
|
||||||
|
|
||||||
// Generate header guard:
|
// Generate header guard:
|
||||||
Q_INVOKABLE QString headerGuard(const QString &in) const;
|
Q_INVOKABLE QString headerGuard(const QString &in) const;
|
||||||
@@ -55,6 +58,7 @@ public:
|
|||||||
Q_INVOKABLE QString classToHeaderGuard(const QString &klass, const QString &extension) const;
|
Q_INVOKABLE QString classToHeaderGuard(const QString &klass, const QString &extension) const;
|
||||||
Q_INVOKABLE QString openNamespaces(const QString &klass) const;
|
Q_INVOKABLE QString openNamespaces(const QString &klass) const;
|
||||||
Q_INVOKABLE QString closeNamespaces(const QString &klass) const;
|
Q_INVOKABLE QString closeNamespaces(const QString &klass) const;
|
||||||
|
Q_INVOKABLE bool hasQObjectParent(const QString &klassName) const;
|
||||||
|
|
||||||
// Find header file for class.
|
// Find header file for class.
|
||||||
Q_INVOKABLE QString includeStatement(
|
Q_INVOKABLE QString includeStatement(
|
||||||
@@ -63,6 +67,9 @@ public:
|
|||||||
const QStringList &specialClasses,
|
const QStringList &specialClasses,
|
||||||
const QString &pathOfIncludingFile
|
const QString &pathOfIncludingFile
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CppLocatorData * const m_locatorData;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -33,7 +33,6 @@
|
|||||||
#include "cpptoolsbridge.h"
|
#include "cpptoolsbridge.h"
|
||||||
#include "cpptoolsbridgeqtcreatorimplementation.h"
|
#include "cpptoolsbridgeqtcreatorimplementation.h"
|
||||||
#include "cpptoolsconstants.h"
|
#include "cpptoolsconstants.h"
|
||||||
#include "cpptoolsjsextension.h"
|
|
||||||
#include "cpptoolsreuse.h"
|
#include "cpptoolsreuse.h"
|
||||||
#include "cpptoolssettings.h"
|
#include "cpptoolssettings.h"
|
||||||
#include "projectinfo.h"
|
#include "projectinfo.h"
|
||||||
@@ -46,7 +45,6 @@
|
|||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/idocument.h>
|
#include <coreplugin/idocument.h>
|
||||||
#include <coreplugin/jsexpander.h>
|
|
||||||
#include <coreplugin/vcsmanager.h>
|
#include <coreplugin/vcsmanager.h>
|
||||||
#include <cppeditor/cppeditorconstants.h>
|
#include <cppeditor/cppeditorconstants.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
@@ -167,7 +165,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
|
|||||||
d = new CppToolsPluginPrivate;
|
d = new CppToolsPluginPrivate;
|
||||||
d->initialize();
|
d->initialize();
|
||||||
|
|
||||||
JsExpander::registerGlobalObject<CppToolsJsExtension>("Cpp");
|
CppModelManager::instance()->registerJsExtension();
|
||||||
ExtensionSystem::PluginManager::addObject(&d->m_cppProjectUpdaterFactory);
|
ExtensionSystem::PluginManager::addObject(&d->m_cppProjectUpdaterFactory);
|
||||||
|
|
||||||
// Menus
|
// Menus
|
||||||
|
Reference in New Issue
Block a user