forked from qt-creator/qt-creator
CppEditor: Move CppHeaderSource implementation and test to same files
... and remove the now-empty cppeditorplugin.h Change-Id: Ia28b180c280ba7b10ce0f2826f2ac69d128a453c Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -40,7 +40,7 @@ add_qtc_plugin(CppEditor
|
||||
cppeditorconstants.h
|
||||
cppeditordocument.cpp cppeditordocument.h
|
||||
cppeditoroutline.cpp cppeditoroutline.h
|
||||
cppeditorplugin.cpp cppeditorplugin.h
|
||||
cppeditorplugin.cpp
|
||||
cppeditorwidget.cpp cppeditorwidget.h
|
||||
cppelementevaluator.cpp cppelementevaluator.h
|
||||
cppfileiterationorder.cpp cppfileiterationorder.h
|
||||
@@ -49,6 +49,7 @@ add_qtc_plugin(CppEditor
|
||||
cppfollowsymbolundercursor.cpp cppfollowsymbolundercursor.h
|
||||
cppfunctiondecldeflink.cpp cppfunctiondecldeflink.h
|
||||
cppfunctionparamrenaminghandler.cpp cppfunctionparamrenaminghandler.h
|
||||
cppheadersource.cpp cppheadersource.h
|
||||
cpphighlighter.cpp cpphighlighter.h
|
||||
cppincludehierarchy.cpp cppincludehierarchy.h
|
||||
cppincludesfilter.cpp cppincludesfilter.h
|
||||
@@ -121,7 +122,6 @@ extend_qtc_plugin(CppEditor
|
||||
cppcodegen_test.cpp cppcodegen_test.h
|
||||
cppcompletion_test.cpp cppcompletion_test.h
|
||||
cppdoxygen_test.cpp cppdoxygen_test.h
|
||||
cppheadersource_test.cpp cppheadersource_test.h
|
||||
cppincludehierarchy_test.cpp cppincludehierarchy_test.h
|
||||
cpplocalsymbols_test.cpp cpplocalsymbols_test.h
|
||||
cpplocatorfilter_test.cpp cpplocatorfilter_test.h
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "cppchecksymbols.h"
|
||||
#include "cppcodemodelsettings.h"
|
||||
#include "cppeditordocument.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "cppworkingcopy.h"
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#include "cppeditorconstants.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditorwidget.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
@@ -95,7 +95,6 @@ QtcPlugin {
|
||||
"cppeditoroutline.cpp",
|
||||
"cppeditoroutline.h",
|
||||
"cppeditorplugin.cpp",
|
||||
"cppeditorplugin.h",
|
||||
"cppelementevaluator.cpp",
|
||||
"cppelementevaluator.h",
|
||||
"cppfileiterationorder.cpp",
|
||||
@@ -110,6 +109,8 @@ QtcPlugin {
|
||||
"cppfunctiondecldeflink.h",
|
||||
"cppfunctionparamrenaminghandler.cpp",
|
||||
"cppfunctionparamrenaminghandler.h",
|
||||
"cppheadersource.cpp",
|
||||
"cppheadersource.h",
|
||||
"cpphighlighter.cpp",
|
||||
"cpphighlighter.h",
|
||||
"cppincludehierarchy.cpp",
|
||||
@@ -252,8 +253,6 @@ QtcPlugin {
|
||||
"cppcompletion_test.h",
|
||||
"cppdoxygen_test.cpp",
|
||||
"cppdoxygen_test.h",
|
||||
"cppheadersource_test.cpp",
|
||||
"cppheadersource_test.h",
|
||||
"cppincludehierarchy_test.cpp",
|
||||
"cppincludehierarchy_test.h",
|
||||
"cpplocalsymbols_test.cpp",
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
#include "baseeditordocumentparser.h"
|
||||
#include "cppcodeformatter.h"
|
||||
#include "cppeditorconstants.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortr.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cppeditorconstants.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortr.h"
|
||||
#include "cpphighlighter.h"
|
||||
#include "cppquickfixassistant.h"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cppeditorplugin.h"
|
||||
|
||||
#include "cppautocompleter.h"
|
||||
#include "cppcodemodelinspectordialog.h"
|
||||
#include "cppcodemodelsettings.h"
|
||||
@@ -14,9 +12,9 @@
|
||||
#include "cppeditorwidget.h"
|
||||
#include "cppfilesettingspage.h"
|
||||
#include "cppincludehierarchy.h"
|
||||
#include "cppheadersource.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cppoutline.h"
|
||||
#include "cppprojectfile.h"
|
||||
#include "cppprojectupdater.h"
|
||||
#include "cppquickfixes.h"
|
||||
#include "cppquickfixprojectsettingswidget.h"
|
||||
@@ -24,7 +22,6 @@
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "cpptoolssettings.h"
|
||||
#include "cpptypehierarchy.h"
|
||||
#include "projectinfo.h"
|
||||
#include "resourcepreviewhoverhandler.h"
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
@@ -32,7 +29,6 @@
|
||||
#include "cppcodegen_test.h"
|
||||
#include "cppcompletion_test.h"
|
||||
#include "cppdoxygen_test.h"
|
||||
#include "cppheadersource_test.h"
|
||||
#include "cpphighlighter.h"
|
||||
#include "cppincludehierarchy_test.h"
|
||||
#include "cppinsertvirtualmethods.h"
|
||||
@@ -89,7 +85,6 @@
|
||||
#include <utils/mimeconstants.h>
|
||||
#include <utils/mimeutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/stringtable.h>
|
||||
#include <utils/theme/theme.h>
|
||||
|
||||
#include <QAction>
|
||||
@@ -106,11 +101,7 @@ using namespace ProjectExplorer;
|
||||
using namespace TextEditor;
|
||||
using namespace Utils;
|
||||
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
|
||||
enum { QUICKFIX_INTERVAL = 20 };
|
||||
enum { debug = 0 };
|
||||
namespace CppEditor::Internal {
|
||||
|
||||
static CppEditorWidget *currentCppEditorWidget()
|
||||
{
|
||||
@@ -183,8 +174,6 @@ public:
|
||||
CppProjectUpdaterFactory m_cppProjectUpdaterFactory;
|
||||
};
|
||||
|
||||
static QHash<FilePath, FilePath> m_headerSourceMapping;
|
||||
|
||||
class CppEditorPlugin final : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -498,7 +487,7 @@ void CppEditorPlugin::registerTests()
|
||||
addTest<CppHighlighterTest>();
|
||||
addTest<FunctionUtilsTest>();
|
||||
addTest<HeaderPathFilterTest>();
|
||||
addTest<HeaderSourceTest>();
|
||||
addTestCreator(createCppHeaderSourceTest);
|
||||
addTest<IncludeGroupsTest>();
|
||||
addTest<LocalSymbolsTest>();
|
||||
addTest<LocatorFilterTest>();
|
||||
@@ -551,239 +540,6 @@ void CppEditorPluginPrivate::inspectCppCodeModel()
|
||||
}
|
||||
}
|
||||
|
||||
void clearHeaderSourceCache()
|
||||
{
|
||||
m_headerSourceMapping.clear();
|
||||
}
|
||||
|
||||
static FilePaths findFilesInProject(const QStringList &names, const Project *project,
|
||||
FileType fileType)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << names << project;
|
||||
|
||||
if (!project)
|
||||
return {};
|
||||
|
||||
const auto filter = [&](const Node *n) {
|
||||
const auto fn = n->asFileNode();
|
||||
return fn && fn->fileType() == fileType && names.contains(fn->filePath().fileName());
|
||||
};
|
||||
return project->files(filter);
|
||||
}
|
||||
|
||||
// Return the suffixes that should be checked when trying to find a
|
||||
// source belonging to a header and vice versa
|
||||
static QStringList matchingCandidateSuffixes(ProjectFile::Kind kind)
|
||||
{
|
||||
using namespace Utils::Constants;
|
||||
switch (kind) {
|
||||
case ProjectFile::AmbiguousHeader:
|
||||
case ProjectFile::CHeader:
|
||||
case ProjectFile::CXXHeader:
|
||||
case ProjectFile::ObjCHeader:
|
||||
case ProjectFile::ObjCXXHeader:
|
||||
return mimeTypeForName(C_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(CPP_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(OBJECTIVE_C_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(OBJECTIVE_CPP_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(CUDA_SOURCE_MIMETYPE).suffixes();
|
||||
case ProjectFile::CSource:
|
||||
case ProjectFile::ObjCSource:
|
||||
return mimeTypeForName(C_HEADER_MIMETYPE).suffixes();
|
||||
case ProjectFile::CXXSource:
|
||||
case ProjectFile::ObjCXXSource:
|
||||
case ProjectFile::CudaSource:
|
||||
case ProjectFile::OpenCLSource:
|
||||
return mimeTypeForName(CPP_HEADER_MIMETYPE).suffixes();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static QStringList baseNameWithAllSuffixes(const QString &baseName, const QStringList &suffixes)
|
||||
{
|
||||
QStringList result;
|
||||
const QChar dot = QLatin1Char('.');
|
||||
for (const QString &suffix : suffixes) {
|
||||
QString fileName = baseName;
|
||||
fileName += dot;
|
||||
fileName += suffix;
|
||||
result += fileName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QStringList baseNamesWithAllPrefixes(const CppFileSettings &settings,
|
||||
const QStringList &baseNames, bool isHeader)
|
||||
{
|
||||
QStringList result;
|
||||
const QStringList &sourcePrefixes = settings.sourcePrefixes;
|
||||
const QStringList &headerPrefixes = settings.headerPrefixes;
|
||||
|
||||
for (const QString &name : baseNames) {
|
||||
for (const QString &prefix : isHeader ? headerPrefixes : sourcePrefixes) {
|
||||
if (name.startsWith(prefix)) {
|
||||
QString nameWithoutPrefix = name.mid(prefix.size());
|
||||
result += nameWithoutPrefix;
|
||||
for (const QString &prefix : isHeader ? sourcePrefixes : headerPrefixes)
|
||||
result += prefix + nameWithoutPrefix;
|
||||
}
|
||||
}
|
||||
for (const QString &prefix : isHeader ? sourcePrefixes : headerPrefixes)
|
||||
result += prefix + name;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QStringList baseDirWithAllDirectories(const QDir &baseDir, const QStringList &directories)
|
||||
{
|
||||
QStringList result;
|
||||
for (const QString &dir : directories)
|
||||
result << QDir::cleanPath(baseDir.absoluteFilePath(dir));
|
||||
return result;
|
||||
}
|
||||
|
||||
static int commonFilePathLength(const QString &s1, const QString &s2)
|
||||
{
|
||||
int length = qMin(s1.length(), s2.length());
|
||||
for (int i = 0; i < length; ++i)
|
||||
if (HostOsInfo::fileNameCaseSensitivity() == Qt::CaseSensitive) {
|
||||
if (s1[i] != s2[i])
|
||||
return i;
|
||||
} else {
|
||||
if (s1[i].toLower() != s2[i].toLower())
|
||||
return i;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static FilePath correspondingHeaderOrSourceInProject(const FilePath &filePath,
|
||||
const QStringList &candidateFileNames,
|
||||
const Project *project,
|
||||
FileType fileType,
|
||||
CacheUsage cacheUsage)
|
||||
{
|
||||
const FilePaths projectFiles = findFilesInProject(candidateFileNames, project, fileType);
|
||||
|
||||
// Find the file having the most common path with fileName
|
||||
FilePath bestFilePath;
|
||||
int compareValue = 0;
|
||||
for (const FilePath &projectFile : projectFiles) {
|
||||
int value = commonFilePathLength(filePath.toString(), projectFile.toString());
|
||||
if (value > compareValue) {
|
||||
compareValue = value;
|
||||
bestFilePath = projectFile;
|
||||
}
|
||||
}
|
||||
if (!bestFilePath.isEmpty()) {
|
||||
QTC_ASSERT(bestFilePath.isFile(), return {});
|
||||
if (cacheUsage == CacheUsage::ReadWrite) {
|
||||
m_headerSourceMapping[filePath] = bestFilePath;
|
||||
m_headerSourceMapping[bestFilePath] = filePath;
|
||||
}
|
||||
return bestFilePath;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
FilePath correspondingHeaderOrSource(const FilePath &filePath, bool *wasHeader, CacheUsage cacheUsage)
|
||||
{
|
||||
ProjectFile::Kind kind = ProjectFile::classify(filePath.fileName());
|
||||
const bool isHeader = ProjectFile::isHeader(kind);
|
||||
if (wasHeader)
|
||||
*wasHeader = isHeader;
|
||||
if (const auto it = m_headerSourceMapping.constFind(filePath);
|
||||
it != m_headerSourceMapping.constEnd()) {
|
||||
return it.value();
|
||||
}
|
||||
|
||||
Project * const projectForFile = ProjectManager::projectForFile(filePath);
|
||||
const CppFileSettings settings = cppFileSettingsForProject(projectForFile);
|
||||
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << filePath.fileName() << kind;
|
||||
|
||||
if (kind == ProjectFile::Unsupported)
|
||||
return {};
|
||||
|
||||
const QString baseName = filePath.completeBaseName();
|
||||
const QString privateHeaderSuffix = QLatin1String("_p");
|
||||
const QStringList suffixes = matchingCandidateSuffixes(kind);
|
||||
|
||||
QStringList candidateFileNames = baseNameWithAllSuffixes(baseName, suffixes);
|
||||
if (isHeader) {
|
||||
if (baseName.endsWith(privateHeaderSuffix)) {
|
||||
QString sourceBaseName = baseName;
|
||||
sourceBaseName.truncate(sourceBaseName.size() - privateHeaderSuffix.size());
|
||||
candidateFileNames += baseNameWithAllSuffixes(sourceBaseName, suffixes);
|
||||
}
|
||||
} else {
|
||||
QString privateHeaderBaseName = baseName;
|
||||
privateHeaderBaseName.append(privateHeaderSuffix);
|
||||
candidateFileNames += baseNameWithAllSuffixes(privateHeaderBaseName, suffixes);
|
||||
}
|
||||
|
||||
const QDir absoluteDir = filePath.toFileInfo().absoluteDir();
|
||||
QStringList candidateDirs(absoluteDir.absolutePath());
|
||||
// If directory is not root, try matching against its siblings
|
||||
const QStringList searchPaths = isHeader ? settings.sourceSearchPaths
|
||||
: settings.headerSearchPaths;
|
||||
candidateDirs += baseDirWithAllDirectories(absoluteDir, searchPaths);
|
||||
|
||||
candidateFileNames += baseNamesWithAllPrefixes(settings, candidateFileNames, isHeader);
|
||||
|
||||
// Try to find a file in the same or sibling directories first
|
||||
for (const QString &candidateDir : std::as_const(candidateDirs)) {
|
||||
for (const QString &candidateFileName : std::as_const(candidateFileNames)) {
|
||||
const FilePath candidateFilePath
|
||||
= FilePath::fromString(candidateDir + '/' + candidateFileName).normalizedPathName();
|
||||
if (candidateFilePath.isFile()) {
|
||||
if (cacheUsage == CacheUsage::ReadWrite) {
|
||||
m_headerSourceMapping[filePath] = candidateFilePath;
|
||||
if (!isHeader || !baseName.endsWith(privateHeaderSuffix))
|
||||
m_headerSourceMapping[candidateFilePath] = filePath;
|
||||
}
|
||||
return candidateFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find files in the current project
|
||||
Project *currentProject = projectForFile;
|
||||
if (!projectForFile)
|
||||
currentProject = ProjectTree::currentProject();
|
||||
const FileType requestedFileType = isHeader ? FileType::Source : FileType::Header;
|
||||
if (currentProject) {
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(
|
||||
filePath, candidateFileNames, currentProject, requestedFileType, cacheUsage);
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
|
||||
// Find files in other projects
|
||||
} else {
|
||||
const QList<ProjectInfo::ConstPtr> projectInfos = CppModelManager::projectInfos();
|
||||
for (const ProjectInfo::ConstPtr &projectInfo : projectInfos) {
|
||||
const Project *project = projectForProjectInfo(*projectInfo);
|
||||
if (project == currentProject)
|
||||
continue; // We have already checked the current project.
|
||||
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(
|
||||
filePath, candidateFileNames, project, requestedFileType, cacheUsage);
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace CppEditor
|
||||
} // CppEditor::Internal
|
||||
|
||||
#include "cppeditorplugin.moc"
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "cppeditorconstants.h"
|
||||
#include "cppeditordocument.h"
|
||||
#include "cppeditoroutline.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortr.h"
|
||||
#include "cppfunctiondecldeflink.h"
|
||||
#include "cppfunctionparamrenaminghandler.h"
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include "cppfilesettingspage.h"
|
||||
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortr.h"
|
||||
#include "cppheadersource.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
368
src/plugins/cppeditor/cppheadersource.cpp
Normal file
368
src/plugins/cppeditor/cppheadersource.cpp
Normal file
@@ -0,0 +1,368 @@
|
||||
// Copyright (C) 2016 Orgad Shaneh <orgads@gmail.com>.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cppheadersource.h"
|
||||
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "cpptoolstestcase.h"
|
||||
#include "cppfilesettingspage.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cppfilesettingspage.h"
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <projectexplorer/projecttree.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/mimeconstants.h>
|
||||
#include <utils/mimeutils.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#include <QtTest>
|
||||
#endif
|
||||
|
||||
using namespace CppEditor::Internal;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace CppEditor {
|
||||
|
||||
enum { debug = 0 };
|
||||
|
||||
static QHash<FilePath, FilePath> m_headerSourceMapping;
|
||||
|
||||
void Internal::clearHeaderSourceCache()
|
||||
{
|
||||
m_headerSourceMapping.clear();
|
||||
}
|
||||
|
||||
static inline QString _(const QByteArray &ba) { return QString::fromLatin1(ba, ba.size()); }
|
||||
|
||||
static void createTempFile(const FilePath &filePath)
|
||||
{
|
||||
QString fileName = filePath.toString();
|
||||
QFile file(fileName);
|
||||
QDir(QFileInfo(fileName).absolutePath()).mkpath(_("."));
|
||||
file.open(QFile::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
|
||||
static QString baseTestDir()
|
||||
{
|
||||
return Utils::TemporaryDirectory::masterDirectoryPath() + "/qtc_cppheadersource/";
|
||||
}
|
||||
|
||||
static FilePaths findFilesInProject(const QStringList &names, const Project *project,
|
||||
FileType fileType)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << names << project;
|
||||
|
||||
if (!project)
|
||||
return {};
|
||||
|
||||
const auto filter = [&](const Node *n) {
|
||||
const auto fn = n->asFileNode();
|
||||
return fn && fn->fileType() == fileType && names.contains(fn->filePath().fileName());
|
||||
};
|
||||
return project->files(filter);
|
||||
}
|
||||
|
||||
// Return the suffixes that should be checked when trying to find a
|
||||
// source belonging to a header and vice versa
|
||||
static QStringList matchingCandidateSuffixes(ProjectFile::Kind kind)
|
||||
{
|
||||
using namespace Utils::Constants;
|
||||
switch (kind) {
|
||||
case ProjectFile::AmbiguousHeader:
|
||||
case ProjectFile::CHeader:
|
||||
case ProjectFile::CXXHeader:
|
||||
case ProjectFile::ObjCHeader:
|
||||
case ProjectFile::ObjCXXHeader:
|
||||
return mimeTypeForName(C_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(CPP_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(OBJECTIVE_C_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(OBJECTIVE_CPP_SOURCE_MIMETYPE).suffixes()
|
||||
+ mimeTypeForName(CUDA_SOURCE_MIMETYPE).suffixes();
|
||||
case ProjectFile::CSource:
|
||||
case ProjectFile::ObjCSource:
|
||||
return mimeTypeForName(C_HEADER_MIMETYPE).suffixes();
|
||||
case ProjectFile::CXXSource:
|
||||
case ProjectFile::ObjCXXSource:
|
||||
case ProjectFile::CudaSource:
|
||||
case ProjectFile::OpenCLSource:
|
||||
return mimeTypeForName(CPP_HEADER_MIMETYPE).suffixes();
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static QStringList baseNameWithAllSuffixes(const QString &baseName, const QStringList &suffixes)
|
||||
{
|
||||
QStringList result;
|
||||
const QChar dot = QLatin1Char('.');
|
||||
for (const QString &suffix : suffixes) {
|
||||
QString fileName = baseName;
|
||||
fileName += dot;
|
||||
fileName += suffix;
|
||||
result += fileName;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QStringList baseNamesWithAllPrefixes(const CppFileSettings &settings,
|
||||
const QStringList &baseNames, bool isHeader)
|
||||
{
|
||||
QStringList result;
|
||||
const QStringList &sourcePrefixes = settings.sourcePrefixes;
|
||||
const QStringList &headerPrefixes = settings.headerPrefixes;
|
||||
|
||||
for (const QString &name : baseNames) {
|
||||
for (const QString &prefix : isHeader ? headerPrefixes : sourcePrefixes) {
|
||||
if (name.startsWith(prefix)) {
|
||||
QString nameWithoutPrefix = name.mid(prefix.size());
|
||||
result += nameWithoutPrefix;
|
||||
for (const QString &prefix : isHeader ? sourcePrefixes : headerPrefixes)
|
||||
result += prefix + nameWithoutPrefix;
|
||||
}
|
||||
}
|
||||
for (const QString &prefix : isHeader ? sourcePrefixes : headerPrefixes)
|
||||
result += prefix + name;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QStringList baseDirWithAllDirectories(const QDir &baseDir, const QStringList &directories)
|
||||
{
|
||||
QStringList result;
|
||||
for (const QString &dir : directories)
|
||||
result << QDir::cleanPath(baseDir.absoluteFilePath(dir));
|
||||
return result;
|
||||
}
|
||||
|
||||
static int commonFilePathLength(const QString &s1, const QString &s2)
|
||||
{
|
||||
int length = qMin(s1.length(), s2.length());
|
||||
for (int i = 0; i < length; ++i)
|
||||
if (HostOsInfo::fileNameCaseSensitivity() == Qt::CaseSensitive) {
|
||||
if (s1[i] != s2[i])
|
||||
return i;
|
||||
} else {
|
||||
if (s1[i].toLower() != s2[i].toLower())
|
||||
return i;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static FilePath correspondingHeaderOrSourceInProject(const FilePath &filePath,
|
||||
const QStringList &candidateFileNames,
|
||||
const Project *project,
|
||||
FileType fileType,
|
||||
CacheUsage cacheUsage)
|
||||
{
|
||||
const FilePaths projectFiles = findFilesInProject(candidateFileNames, project, fileType);
|
||||
|
||||
// Find the file having the most common path with fileName
|
||||
FilePath bestFilePath;
|
||||
int compareValue = 0;
|
||||
for (const FilePath &projectFile : projectFiles) {
|
||||
int value = commonFilePathLength(filePath.toString(), projectFile.toString());
|
||||
if (value > compareValue) {
|
||||
compareValue = value;
|
||||
bestFilePath = projectFile;
|
||||
}
|
||||
}
|
||||
if (!bestFilePath.isEmpty()) {
|
||||
QTC_ASSERT(bestFilePath.isFile(), return {});
|
||||
if (cacheUsage == CacheUsage::ReadWrite) {
|
||||
m_headerSourceMapping[filePath] = bestFilePath;
|
||||
m_headerSourceMapping[bestFilePath] = filePath;
|
||||
}
|
||||
return bestFilePath;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
FilePath correspondingHeaderOrSource(const FilePath &filePath, bool *wasHeader, CacheUsage cacheUsage)
|
||||
{
|
||||
ProjectFile::Kind kind = ProjectFile::classify(filePath.fileName());
|
||||
const bool isHeader = ProjectFile::isHeader(kind);
|
||||
if (wasHeader)
|
||||
*wasHeader = isHeader;
|
||||
if (const auto it = m_headerSourceMapping.constFind(filePath);
|
||||
it != m_headerSourceMapping.constEnd()) {
|
||||
return it.value();
|
||||
}
|
||||
|
||||
Project * const projectForFile = ProjectManager::projectForFile(filePath);
|
||||
const CppFileSettings settings = cppFileSettingsForProject(projectForFile);
|
||||
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << filePath.fileName() << kind;
|
||||
|
||||
if (kind == ProjectFile::Unsupported)
|
||||
return {};
|
||||
|
||||
const QString baseName = filePath.completeBaseName();
|
||||
const QString privateHeaderSuffix = QLatin1String("_p");
|
||||
const QStringList suffixes = matchingCandidateSuffixes(kind);
|
||||
|
||||
QStringList candidateFileNames = baseNameWithAllSuffixes(baseName, suffixes);
|
||||
if (isHeader) {
|
||||
if (baseName.endsWith(privateHeaderSuffix)) {
|
||||
QString sourceBaseName = baseName;
|
||||
sourceBaseName.truncate(sourceBaseName.size() - privateHeaderSuffix.size());
|
||||
candidateFileNames += baseNameWithAllSuffixes(sourceBaseName, suffixes);
|
||||
}
|
||||
} else {
|
||||
QString privateHeaderBaseName = baseName;
|
||||
privateHeaderBaseName.append(privateHeaderSuffix);
|
||||
candidateFileNames += baseNameWithAllSuffixes(privateHeaderBaseName, suffixes);
|
||||
}
|
||||
|
||||
const QDir absoluteDir = filePath.toFileInfo().absoluteDir();
|
||||
QStringList candidateDirs(absoluteDir.absolutePath());
|
||||
// If directory is not root, try matching against its siblings
|
||||
const QStringList searchPaths = isHeader ? settings.sourceSearchPaths
|
||||
: settings.headerSearchPaths;
|
||||
candidateDirs += baseDirWithAllDirectories(absoluteDir, searchPaths);
|
||||
|
||||
candidateFileNames += baseNamesWithAllPrefixes(settings, candidateFileNames, isHeader);
|
||||
|
||||
// Try to find a file in the same or sibling directories first
|
||||
for (const QString &candidateDir : std::as_const(candidateDirs)) {
|
||||
for (const QString &candidateFileName : std::as_const(candidateFileNames)) {
|
||||
const FilePath candidateFilePath
|
||||
= FilePath::fromString(candidateDir + '/' + candidateFileName).normalizedPathName();
|
||||
if (candidateFilePath.isFile()) {
|
||||
if (cacheUsage == CacheUsage::ReadWrite) {
|
||||
m_headerSourceMapping[filePath] = candidateFilePath;
|
||||
if (!isHeader || !baseName.endsWith(privateHeaderSuffix))
|
||||
m_headerSourceMapping[candidateFilePath] = filePath;
|
||||
}
|
||||
return candidateFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find files in the current project
|
||||
Project *currentProject = projectForFile;
|
||||
if (!projectForFile)
|
||||
currentProject = ProjectTree::currentProject();
|
||||
const FileType requestedFileType = isHeader ? FileType::Source : FileType::Header;
|
||||
if (currentProject) {
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(
|
||||
filePath, candidateFileNames, currentProject, requestedFileType, cacheUsage);
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
|
||||
// Find files in other projects
|
||||
} else {
|
||||
const QList<ProjectInfo::ConstPtr> projectInfos = CppModelManager::projectInfos();
|
||||
for (const ProjectInfo::ConstPtr &projectInfo : projectInfos) {
|
||||
const Project *project = projectForProjectInfo(*projectInfo);
|
||||
if (project == currentProject)
|
||||
continue; // We have already checked the current project.
|
||||
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(
|
||||
filePath, candidateFileNames, project, requestedFileType, cacheUsage);
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // CppEditor
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
|
||||
namespace CppEditor::Internal {
|
||||
|
||||
class HeaderSourceTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
void test_data();
|
||||
void test();
|
||||
};
|
||||
|
||||
void HeaderSourceTest::test()
|
||||
{
|
||||
QFETCH(QString, sourceFileName);
|
||||
QFETCH(QString, headerFileName);
|
||||
|
||||
CppEditor::Tests::TemporaryDir temporaryDir;
|
||||
QVERIFY(temporaryDir.isValid());
|
||||
|
||||
const QDir path = QDir(temporaryDir.path() + QLatin1Char('/') + _(QTest::currentDataTag()));
|
||||
const FilePath sourcePath = FilePath::fromString(path.absoluteFilePath(sourceFileName));
|
||||
const FilePath headerPath = FilePath::fromString(path.absoluteFilePath(headerFileName));
|
||||
createTempFile(sourcePath);
|
||||
createTempFile(headerPath);
|
||||
|
||||
bool wasHeader;
|
||||
clearHeaderSourceCache();
|
||||
QCOMPARE(correspondingHeaderOrSource(sourcePath, &wasHeader, CacheUsage::ReadWrite), headerPath);
|
||||
QVERIFY(!wasHeader);
|
||||
clearHeaderSourceCache();
|
||||
QCOMPARE(correspondingHeaderOrSource(headerPath, &wasHeader, CacheUsage::ReadWrite), sourcePath);
|
||||
QVERIFY(wasHeader);
|
||||
}
|
||||
|
||||
void HeaderSourceTest::test_data()
|
||||
{
|
||||
QTest::addColumn<QString>("sourceFileName");
|
||||
QTest::addColumn<QString>("headerFileName");
|
||||
QTest::newRow("samedir") << _("foo.cpp") << _("foo.h");
|
||||
QTest::newRow("includesub") << _("foo.cpp") << _("include/foo.h");
|
||||
QTest::newRow("headerprefix") << _("foo.cpp") << _("testh_foo.h");
|
||||
QTest::newRow("sourceprefixwsub") << _("testc_foo.cpp") << _("include/foo.h");
|
||||
QTest::newRow("sourceAndHeaderPrefixWithBothsub") << _("src/testc_foo.cpp") << _("include/testh_foo.h");
|
||||
}
|
||||
|
||||
void HeaderSourceTest::initTestCase()
|
||||
{
|
||||
QDir(baseTestDir()).mkpath(_("."));
|
||||
CppFileSettings &fs = globalCppFileSettings();
|
||||
fs.headerSearchPaths.append(QLatin1String("include"));
|
||||
fs.headerSearchPaths.append(QLatin1String("../include"));
|
||||
fs.sourceSearchPaths.append(QLatin1String("src"));
|
||||
fs.sourceSearchPaths.append(QLatin1String("../src"));
|
||||
fs.headerPrefixes.append(QLatin1String("testh_"));
|
||||
fs.sourcePrefixes.append(QLatin1String("testc_"));
|
||||
}
|
||||
|
||||
void HeaderSourceTest::cleanupTestCase()
|
||||
{
|
||||
Utils::FilePath::fromString(baseTestDir()).removeRecursively();
|
||||
CppFileSettings &fs = globalCppFileSettings();
|
||||
fs.headerSearchPaths.removeLast();
|
||||
fs.headerSearchPaths.removeLast();
|
||||
fs.sourceSearchPaths.removeLast();
|
||||
fs.sourceSearchPaths.removeLast();
|
||||
fs.headerPrefixes.removeLast();
|
||||
fs.sourcePrefixes.removeLast();
|
||||
}
|
||||
|
||||
QObject *createCppHeaderSourceTest()
|
||||
{
|
||||
return new HeaderSourceTest;
|
||||
}
|
||||
|
||||
} // namespace CppEditor::Internal
|
||||
|
||||
#include "cppheadersource.moc"
|
||||
|
||||
#endif // WITH_TESTS
|
||||
@@ -1,10 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace CppEditor::Internal {
|
||||
|
||||
void clearHeaderSourceCache();
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
QObject *createCppHeaderSourceTest();
|
||||
#endif
|
||||
|
||||
} // CppEditor::Internal
|
||||
@@ -1,95 +0,0 @@
|
||||
// Copyright (C) 2016 Orgad Shaneh <orgads@gmail.com>.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cppheadersource_test.h"
|
||||
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "cpptoolstestcase.h"
|
||||
#include "cppfilesettingspage.h"
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QtTest>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
static inline QString _(const QByteArray &ba) { return QString::fromLatin1(ba, ba.size()); }
|
||||
|
||||
static void createTempFile(const FilePath &filePath)
|
||||
{
|
||||
QString fileName = filePath.toString();
|
||||
QFile file(fileName);
|
||||
QDir(QFileInfo(fileName).absolutePath()).mkpath(_("."));
|
||||
file.open(QFile::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
|
||||
static QString baseTestDir()
|
||||
{
|
||||
return Utils::TemporaryDirectory::masterDirectoryPath() + "/qtc_cppheadersource/";
|
||||
}
|
||||
|
||||
namespace CppEditor::Internal {
|
||||
|
||||
void HeaderSourceTest::test()
|
||||
{
|
||||
QFETCH(QString, sourceFileName);
|
||||
QFETCH(QString, headerFileName);
|
||||
|
||||
CppEditor::Tests::TemporaryDir temporaryDir;
|
||||
QVERIFY(temporaryDir.isValid());
|
||||
|
||||
const QDir path = QDir(temporaryDir.path() + QLatin1Char('/') + _(QTest::currentDataTag()));
|
||||
const FilePath sourcePath = FilePath::fromString(path.absoluteFilePath(sourceFileName));
|
||||
const FilePath headerPath = FilePath::fromString(path.absoluteFilePath(headerFileName));
|
||||
createTempFile(sourcePath);
|
||||
createTempFile(headerPath);
|
||||
|
||||
bool wasHeader;
|
||||
clearHeaderSourceCache();
|
||||
QCOMPARE(correspondingHeaderOrSource(sourcePath, &wasHeader), headerPath);
|
||||
QVERIFY(!wasHeader);
|
||||
clearHeaderSourceCache();
|
||||
QCOMPARE(correspondingHeaderOrSource(headerPath, &wasHeader), sourcePath);
|
||||
QVERIFY(wasHeader);
|
||||
}
|
||||
|
||||
void HeaderSourceTest::test_data()
|
||||
{
|
||||
QTest::addColumn<QString>("sourceFileName");
|
||||
QTest::addColumn<QString>("headerFileName");
|
||||
QTest::newRow("samedir") << _("foo.cpp") << _("foo.h");
|
||||
QTest::newRow("includesub") << _("foo.cpp") << _("include/foo.h");
|
||||
QTest::newRow("headerprefix") << _("foo.cpp") << _("testh_foo.h");
|
||||
QTest::newRow("sourceprefixwsub") << _("testc_foo.cpp") << _("include/foo.h");
|
||||
QTest::newRow("sourceAndHeaderPrefixWithBothsub") << _("src/testc_foo.cpp") << _("include/testh_foo.h");
|
||||
}
|
||||
|
||||
void HeaderSourceTest::initTestCase()
|
||||
{
|
||||
QDir(baseTestDir()).mkpath(_("."));
|
||||
CppFileSettings &fs = globalCppFileSettings();
|
||||
fs.headerSearchPaths.append(QLatin1String("include"));
|
||||
fs.headerSearchPaths.append(QLatin1String("../include"));
|
||||
fs.sourceSearchPaths.append(QLatin1String("src"));
|
||||
fs.sourceSearchPaths.append(QLatin1String("../src"));
|
||||
fs.headerPrefixes.append(QLatin1String("testh_"));
|
||||
fs.sourcePrefixes.append(QLatin1String("testc_"));
|
||||
}
|
||||
|
||||
void HeaderSourceTest::cleanupTestCase()
|
||||
{
|
||||
Utils::FilePath::fromString(baseTestDir()).removeRecursively();
|
||||
CppFileSettings &fs = globalCppFileSettings();
|
||||
fs.headerSearchPaths.removeLast();
|
||||
fs.headerSearchPaths.removeLast();
|
||||
fs.sourceSearchPaths.removeLast();
|
||||
fs.sourceSearchPaths.removeLast();
|
||||
fs.headerPrefixes.removeLast();
|
||||
fs.sourcePrefixes.removeLast();
|
||||
}
|
||||
|
||||
} // namespace CppEditor::Internal
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace CppEditor::Internal {
|
||||
|
||||
class HeaderSourceTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
void test_data();
|
||||
void test();
|
||||
};
|
||||
|
||||
} // namespace CppEditor::Internal
|
||||
@@ -40,7 +40,6 @@
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppquickfix_test.h"
|
||||
#include <QtTest>
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "cpplocatorfilter.h"
|
||||
|
||||
#include "cppeditorconstants.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortr.h"
|
||||
#include "cpplocatordata.h"
|
||||
#include "cppmodelmanager.h"
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "cppquickfix_test.h"
|
||||
|
||||
#include "cppcodestylepreferences.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditorwidget.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cppquickfixassistant.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "cpptoolsjsextension.h"
|
||||
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppfilesettingspage.h"
|
||||
#include "cpplocatordata.h"
|
||||
#include "cppworkingcopy.h"
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
|
||||
#include "fileandtokenactions_test.h"
|
||||
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditorwidget.h"
|
||||
#include "cppquickfix.h"
|
||||
#include "cppquickfixassistant.h"
|
||||
#include "cppquickfixes.h"
|
||||
#include "cppinsertvirtualmethods.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "cpptoolstestcase.h"
|
||||
#include "cpptypehierarchy.h"
|
||||
#include "cppworkingcopy.h"
|
||||
|
||||
@@ -4,12 +4,9 @@
|
||||
#include "followsymbol_switchmethoddecldef_test.h"
|
||||
|
||||
#include "cppcodemodelsettings.h"
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditorwidget.h"
|
||||
#include "cppelementevaluator.h"
|
||||
#include "cppfollowsymbolundercursor.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "cpptoolstestcase.h"
|
||||
#include "cppvirtualfunctionassistprovider.h"
|
||||
#include "cppvirtualfunctionproposalitem.h"
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <designer/cpp/formclasswizardpage.h>
|
||||
|
||||
#include <cppeditor/cppeditorconstants.h>
|
||||
#include <cppeditor/cppeditorplugin.h>
|
||||
#include <cppeditor/cppeditorwidget.h>
|
||||
#include <cppeditor/cppmodelmanager.h>
|
||||
#include <cppeditor/cppsemanticinfo.h>
|
||||
|
||||
Reference in New Issue
Block a user