"New Class" wizard: Try to find a base class header

If the project has a header file whose name suggests that it might
declare the base class, then add an include statement for it.
While we cannot guarantee that the include statement is resolvable as-
is, it's at least a basis for the user to adapt accordingly, while
without any include statement the class will definitely not compile.

Fixes: QTCREATORBUG-3855
Change-Id: I55ec43d58a9a13b9b59a5bbe6415a457b974b654
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Christian Kandeler
2020-02-07 16:58:37 +01:00
parent 0585ad0f64
commit bcc2b5e08d
3 changed files with 78 additions and 0 deletions

View File

@@ -6,6 +6,7 @@
#define %{GUARD}
@endif
%{JS: Cpp.includeStatement('%{Base}', Util.preferredSuffix('text/x-c++hdr'), ['QObject', 'QWidget', 'QMainWindow', 'QQuickItem', 'QSharedData'], '%{TargetPath}')}\
%{JS: QtSupport.qtIncludes([ ( '%{IncludeQObject}' ) ? 'QtCore/%{IncludeQObject}' : '',
( '%{IncludeQWidget}' ) ? 'QtGui/%{IncludeQWidget}' : '',
( '%{IncludeQMainWindow}' ) ? 'QtGui/%{IncludeQMainWindow}' : '',

View File

@@ -29,10 +29,15 @@
#include <coreplugin/icore.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/session.h>
#include <utils/codegeneration.h>
#include <utils/fileutils.h>
#include <QFileInfo>
#include <QStringList>
#include <QTextStream>
namespace CppTools {
@@ -113,5 +118,69 @@ QString CppToolsJsExtension::closeNamespaces(const QString &klass) const
return result;
}
QString CppToolsJsExtension::includeStatement(
const QString &fullyQualifiedClassName,
const QString &suffix,
const QString &specialClasses,
const QString &pathOfIncludingFile
)
{
if (fullyQualifiedClassName.isEmpty())
return {};
const QString className = parts(fullyQualifiedClassName).last();
if (className.isEmpty() || specialClasses.contains(className))
return {};
if (className.startsWith('Q') && className.length() > 2 && className.at(1).isUpper())
return "#include <" + className + ">\n";
const auto withUnderScores = [&className] {
QString baseName = className;
baseName[0] = baseName[0].toLower();
for (int i = 1; i < baseName.length(); ++i) {
if (baseName[i].isUpper()) {
baseName.insert(i, '_');
baseName[i + 1] = baseName[i + 1].toLower();
++i;
}
}
return baseName;
};
QStringList candidates{className + '.' + suffix};
bool hasUpperCase = false;
bool hasLowerCase = false;
for (int i = 0; i < className.length() && (!hasUpperCase || !hasLowerCase); ++i) {
if (className.at(i).isUpper())
hasUpperCase = true;
if (className.at(i).isLower())
hasLowerCase = true;
}
if (hasUpperCase)
candidates << className.toLower() + '.' + suffix;
if (hasUpperCase && hasLowerCase)
candidates << withUnderScores() + '.' + suffix;
candidates.removeDuplicates();
using namespace ProjectExplorer;
const auto nodeMatchesFileName = [&candidates](Node *n) {
if (const FileNode * const fileNode = n->asFileNode()) {
if (fileNode->fileType() == FileType::Header
&& candidates.contains(fileNode->filePath().fileName())) {
return true;
}
}
return false;
};
for (const Project * const p : SessionManager::projects()) {
const Node *theNode = p->rootProjectNode()->findNode(nodeMatchesFileName);
if (theNode) {
const bool sameDir = pathOfIncludingFile == theNode->filePath().toFileInfo().path();
return QString("#include ")
.append(sameDir ? '"' : '<')
.append(theNode->filePath().fileName())
.append(sameDir ? '"' : '>')
.append('\n');
}
}
return {};
}
} // namespace Internal
} // namespace CppTools

View File

@@ -55,6 +55,14 @@ public:
Q_INVOKABLE QString classToHeaderGuard(const QString &klass, const QString &extension) const;
Q_INVOKABLE QString openNamespaces(const QString &klass) const;
Q_INVOKABLE QString closeNamespaces(const QString &klass) const;
// Find header file for class.
Q_INVOKABLE QString includeStatement(
const QString &fullyQualifiedClassName,
const QString &suffix,
const QString &specialClasses,
const QString &pathOfIncludingFile
);
};
} // namespace Internal