de-duplicate resolution of exact sources

rather than resolving them once in bulk (for the code model) and once
per pri file (for the project view), resolve them only in bulk, but
"tag" them. then do a cheap filtering pass for the project view.

as a side effect, this fixes the problem that sources that are listed by
a file that is not shown in the project tree (as is the case for qrc
files synthesized by resources.prf) would not be shown at all. instead,
these sources now appear belonging directly to the pro file.

Task-number: QTCREATORBUG-3670
Change-Id: I1a1756d95bd90db4da1274eebcc4dad2a854f43d
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Oswald Buddenhagen
2016-10-25 20:04:29 +02:00
parent 0afcbaa9c8
commit e19fa27601
4 changed files with 100 additions and 124 deletions

View File

@@ -636,12 +636,33 @@ QSet<FileName> QmakePriFileNode::recursiveEnumerate(const QString &folder)
return result; return result;
} }
PriFileEvalResult QmakePriFileNode::extractValues(const EvalInput &input, QStringList QmakeProFileNode::fileListForVar(
ProFile *proFile, bool haveExact, const QHash<QString, QVector<ProFileEvaluator::SourceFile> > &sourceFiles,
const QList<QList<VariableAndVPathInformation>> &variableAndVPathInformation) const QString &varName)
{ {
PriFileEvalResult result; const QVector<ProFileEvaluator::SourceFile> &sources = sourceFiles[varName];
QStringList result;
result.reserve(sources.size());
foreach (const ProFileEvaluator::SourceFile &sf, sources)
result << sf.fileName;
return result;
}
void QmakePriFileNode::extractSources(
QHash<const ProFile *, PriFileEvalResult *> proToResult, PriFileEvalResult *fallback,
QVector<ProFileEvaluator::SourceFile> sourceFiles, FileType type)
{
foreach (const ProFileEvaluator::SourceFile &source, sourceFiles) {
PriFileEvalResult *result = proToResult.value(source.proFile);
if (!result)
result = fallback;
result->foundFiles[type].insert(FileName::fromString(source.fileName));
}
}
void QmakePriFileNode::extractValues(
const EvalInput &input, ProFile *proFile, PriFileEvalResult &result)
{
// Figure out DEPLOYMENT and INSTALL folders. // Figure out DEPLOYMENT and INSTALL folders.
// Ignore stuff from cumulative parse, as we are recursively enumerating // Ignore stuff from cumulative parse, as we are recursively enumerating
// all the files from those folders and add watchers for them. That's too // all the files from those folders and add watchers for them. That's too
@@ -682,40 +703,14 @@ PriFileEvalResult QmakePriFileNode::extractValues(const EvalInput &input,
result.recursiveEnumerateFiles += recursiveEnumerate(folder); result.recursiveEnumerateFiles += recursiveEnumerate(folder);
const QVector<QmakeNodeStaticData::FileTypeData> &fileTypes = qmakeNodeStaticData()->fileTypeData; const QVector<QmakeNodeStaticData::FileTypeData> &fileTypes = qmakeNodeStaticData()->fileTypeData;
// update files
for (int i = 0; i < fileTypes.size(); ++i) { for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i).type; FileType type = fileTypes.at(i).type;
const QList<VariableAndVPathInformation> &qmakeVariables = variableAndVPathInformation.at(i); QSet<FileName> &foundFiles = result.foundFiles[type];
QSet<FileName> newFilePaths; result.recursiveEnumerateFiles.subtract(foundFiles);
foreach (const VariableAndVPathInformation &qmakeVariable, qmakeVariables) { QSet<FileName> newFilePaths = filterFilesProVariables(type, foundFiles);
if (haveExact) {
QStringList tmp = input.readerExact->absoluteFileValues(
qmakeVariable.variable, input.projectDir, qmakeVariable.vPathsExact, proFile);
foreach (const QString &t, tmp)
newFilePaths += FileName::fromString(t);
}
{
QStringList tmp = input.readerCumulative->absoluteFileValues(
qmakeVariable.variable, input.projectDir, qmakeVariable.vPathsCumulative, proFile);
foreach (const QString &t, tmp)
newFilePaths += FileName::fromString(t);
}
}
result.foundFiles[type] = newFilePaths;
result.recursiveEnumerateFiles.subtract(newFilePaths);
}
for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i).type;
QSet<FileName> newFilePaths = filterFilesProVariables(type, result.foundFiles[type]);
newFilePaths += filterFilesRecursiveEnumerata(type, result.recursiveEnumerateFiles); newFilePaths += filterFilesRecursiveEnumerata(type, result.recursiveEnumerateFiles);
result.foundFiles[type] = newFilePaths; foundFiles = newFilePaths;
} }
return result;
} }
void QmakePriFileNode::update(const Internal::PriFileEvalResult &result) void QmakePriFileNode::update(const Internal::PriFileEvalResult &result)
@@ -1850,6 +1845,8 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input)
result->includedFiles.proFile = pro; result->includedFiles.proFile = pro;
result->includedFiles.name = input.projectFilePath; result->includedFiles.name = input.projectFilePath;
QHash<const ProFile *, PriFileEvalResult *> proToResult;
result->projectType = proFileTemplateTypeToProjectType( result->projectType = proFileTemplateTypeToProjectType(
(result->state == EvalResult::EvalOk ? input.readerExact (result->state == EvalResult::EvalOk ? input.readerExact
: input.readerCumulative)->templateType()); : input.readerCumulative)->templateType());
@@ -1883,6 +1880,7 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input)
childTree->proFile = child; childTree->proFile = child;
childTree->name = childName; childTree->name = childName;
current->children.insert(childName, childTree); current->children.insert(childName, childTree);
proToResult[child] = &childTree->result;
} }
} }
toBuild.append(current->children.values()); toBuild.append(current->children.values());
@@ -1916,6 +1914,7 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input)
childTree->proFile = child; childTree->proFile = child;
childTree->name = childName; childTree->name = childName;
current->children.insert(childName, childTree); current->children.insert(childName, childTree);
proToResult[child] = &childTree->result;
} }
} }
toBuild.append(current->children.values()); toBuild.append(current->children.values());
@@ -1924,6 +1923,34 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input)
auto exactReader = exactBuildPassReader ? exactBuildPassReader : input.readerExact; auto exactReader = exactBuildPassReader ? exactBuildPassReader : input.readerExact;
auto cumulativeReader = cumulativeBuildPassReader ? cumulativeBuildPassReader : input.readerCumulative; auto cumulativeReader = cumulativeBuildPassReader ? cumulativeBuildPassReader : input.readerCumulative;
QHash<QString, QVector<ProFileEvaluator::SourceFile> > exactSourceFiles;
QHash<QString, QVector<ProFileEvaluator::SourceFile> > cumulativeSourceFiles;
QStringList baseVPathsExact = baseVPaths(exactReader, input.projectDir, input.buildDirectory);
QStringList baseVPathsCumulative = baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory);
const QVector<QmakeNodeStaticData::FileTypeData> &fileTypes = qmakeNodeStaticData()->fileTypeData;
for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i).type;
QStringList qmakeVariables = varNames(type, exactReader);
foreach (const QString &qmakeVariable, qmakeVariables) {
if (result->state == EvalResult::EvalOk) {
QStringList vPathsExact = fullVPaths(
baseVPathsExact, exactReader, qmakeVariable, input.projectDir);
auto sourceFiles = exactReader->absoluteFileValues(
qmakeVariable, input.projectDir, vPathsExact);
exactSourceFiles[qmakeVariable] = sourceFiles;
extractSources(proToResult, &result->includedFiles.result, sourceFiles, type);
}
QStringList vPathsCumulative = fullVPaths(
baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir);
auto sourceFiles = cumulativeReader->absoluteFileValues(
qmakeVariable, input.projectDir, vPathsCumulative);
cumulativeSourceFiles[qmakeVariable] = sourceFiles;
extractSources(proToResult, &result->includedFiles.result, sourceFiles, type);
}
}
if (result->state == EvalResult::EvalOk) { if (result->state == EvalResult::EvalOk) {
result->targetInformation = targetInformation(input.readerExact, exactBuildPassReader, result->targetInformation = targetInformation(input.readerExact, exactBuildPassReader,
input.buildDirectory, input.projectFilePath.toString()); input.buildDirectory, input.projectFilePath.toString());
@@ -1935,21 +1962,21 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input)
result->newVarValues[IncludePathVar] = includePaths(exactReader, input.sysroot, result->newVarValues[IncludePathVar] = includePaths(exactReader, input.sysroot,
input.buildDirectory, input.projectDir); input.buildDirectory, input.projectDir);
result->newVarValues[CppFlagsVar] = exactReader->values(QLatin1String("QMAKE_CXXFLAGS")); result->newVarValues[CppFlagsVar] = exactReader->values(QLatin1String("QMAKE_CXXFLAGS"));
result->newVarValues[SourceVar] = QStringList allSources =
fileListForVar(exactReader, cumulativeReader, fileListForVar(exactSourceFiles, QLatin1String("SOURCES")) +
QLatin1String("SOURCES"), input.projectDir, input.buildDirectory) + fileListForVar(cumulativeSourceFiles, QLatin1String("SOURCES")) +
fileListForVar(exactReader, cumulativeReader, fileListForVar(exactSourceFiles, QLatin1String("HEADERS")) +
QLatin1String("HEADERS"), input.projectDir, input.buildDirectory) + fileListForVar(cumulativeSourceFiles, QLatin1String("HEADERS")) +
fileListForVar(exactReader, cumulativeReader, fileListForVar(exactSourceFiles, QLatin1String("OBJECTIVE_HEADERS")) +
QLatin1String("OBJECTIVE_HEADERS"), input.projectDir, input.buildDirectory); fileListForVar(cumulativeSourceFiles, QLatin1String("OBJECTIVE_HEADERS"));
allSources.removeDuplicates();
result->newVarValues[SourceVar] = allSources;
result->newVarValues[UiDirVar] = QStringList() << uiDirPath(exactReader, input.buildDirectory); result->newVarValues[UiDirVar] = QStringList() << uiDirPath(exactReader, input.buildDirectory);
result->newVarValues[HeaderExtensionVar] = QStringList() << exactReader->value(QLatin1String("QMAKE_EXT_H")); result->newVarValues[HeaderExtensionVar] = QStringList() << exactReader->value(QLatin1String("QMAKE_EXT_H"));
result->newVarValues[CppExtensionVar] = QStringList() << exactReader->value(QLatin1String("QMAKE_EXT_CPP")); result->newVarValues[CppExtensionVar] = QStringList() << exactReader->value(QLatin1String("QMAKE_EXT_CPP"));
result->newVarValues[MocDirVar] = QStringList() << mocDirPath(exactReader, input.buildDirectory); result->newVarValues[MocDirVar] = QStringList() << mocDirPath(exactReader, input.buildDirectory);
result->newVarValues[ExactResourceVar] = fileListForVar(exactReader, 0, result->newVarValues[ExactResourceVar] = fileListForVar(exactSourceFiles, QLatin1String("RESOURCES"));
QLatin1String("RESOURCES"), input.projectDir, input.buildDirectory); result->newVarValues[CumulativeResourceVar] = fileListForVar(cumulativeSourceFiles, QLatin1String("RESOURCES"));
result->newVarValues[CumulativeResourceVar] = fileListForVar(cumulativeReader, 0,
QLatin1String("RESOURCES"), input.projectDir, input.buildDirectory);
result->newVarValues[PkgConfigVar] = exactReader->values(QLatin1String("PKGCONFIG")); result->newVarValues[PkgConfigVar] = exactReader->values(QLatin1String("PKGCONFIG"));
result->newVarValues[PrecompiledHeaderVar] = exactReader->fixifiedValues( result->newVarValues[PrecompiledHeaderVar] = exactReader->fixifiedValues(
QLatin1String("PRECOMPILED_HEADER"), input.projectDir, input.buildDirectory); QLatin1String("PRECOMPILED_HEADER"), input.projectDir, input.buildDirectory);
@@ -1981,37 +2008,11 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input)
if (result->state == EvalResult::EvalOk || result->state == EvalResult::EvalPartial) { if (result->state == EvalResult::EvalOk || result->state == EvalResult::EvalPartial) {
QList<QList<VariableAndVPathInformation>> variableAndVPathInformation;
{ // Collect information on VPATHS and qmake variables
QStringList baseVPathsExact = baseVPaths(exactReader, input.projectDir, input.buildDirectory);
QStringList baseVPathsCumulative = baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory);
const QVector<QmakeNodeStaticData::FileTypeData> &fileTypes = qmakeNodeStaticData()->fileTypeData;
variableAndVPathInformation.reserve(fileTypes.size());
for (int i = 0; i < fileTypes.size(); ++i) {
FileType type = fileTypes.at(i).type;
QList<VariableAndVPathInformation> list;
QStringList qmakeVariables = varNames(type, exactReader);
list.reserve(qmakeVariables.size());
foreach (const QString &qmakeVariable, qmakeVariables) {
VariableAndVPathInformation info;
info.variable = qmakeVariable;
info.vPathsExact = fullVPaths(baseVPathsExact, exactReader, qmakeVariable, input.projectDir);
info.vPathsCumulative = fullVPaths(baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir);
list.append(info);
}
variableAndVPathInformation.append(list);
}
}
// extract values for each .pri file and add it to IncludedPriFiles structure // extract values for each .pri file and add it to IncludedPriFiles structure
QList<IncludedPriFile *> toExtract = { &result->includedFiles }; QList<IncludedPriFile *> toExtract = { &result->includedFiles };
while (!toExtract.isEmpty()) { while (!toExtract.isEmpty()) {
IncludedPriFile *current = toExtract.takeFirst(); IncludedPriFile *current = toExtract.takeFirst();
current->result = extractValues(input, current->proFile, (result->state == EvalResult::EvalOk), extractValues(input, current->proFile, current->result);
variableAndVPathInformation);
toExtract.append(current->children.values()); toExtract.append(current->children.values());
} }
} }
@@ -2254,29 +2255,6 @@ void QmakeProFileNode::cleanupProFileReaders()
m_readerCumulative = nullptr; m_readerCumulative = nullptr;
} }
QStringList QmakeProFileNode::fileListForVar(QtSupport::ProFileReader *readerExact, QtSupport::ProFileReader *readerCumulative,
const QString &varName, const QString &projectDir, const QString &buildDir)
{
QStringList baseVPathsExact = baseVPaths(readerExact, projectDir, buildDir);
QStringList vPathsExact = fullVPaths(baseVPathsExact, readerExact, varName, projectDir);
QStringList result;
result = readerExact->absoluteFileValues(varName,
projectDir,
vPathsExact,
0);
if (readerCumulative) {
QStringList baseVPathsCumulative = baseVPaths(readerCumulative, projectDir, buildDir);
QStringList vPathsCumulative = fullVPaths(baseVPathsCumulative, readerCumulative, varName, projectDir);
result += readerCumulative->absoluteFileValues(varName,
projectDir,
vPathsCumulative,
0);
}
result.removeDuplicates();
return result;
}
QString QmakeProFileNode::uiDirPath(QtSupport::ProFileReader *reader, const QString &buildDir) QString QmakeProFileNode::uiDirPath(QtSupport::ProFileReader *reader, const QString &buildDir)
{ {
QString path = reader->value(QLatin1String("UI_DIR")); QString path = reader->value(QLatin1String("UI_DIR"));

View File

@@ -27,6 +27,7 @@
#include "qmakeprojectmanager_global.h" #include "qmakeprojectmanager_global.h"
#include "proparser/prowriter.h" #include "proparser/prowriter.h"
#include "proparser/profileevaluator.h"
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
#include <projectexplorer/projectnodes.h> #include <projectexplorer/projectnodes.h>
@@ -38,11 +39,6 @@
#include <QMap> #include <QMap>
#include <QFutureWatcher> #include <QFutureWatcher>
// defined in proitems.h
QT_BEGIN_NAMESPACE
class ProFile;
QT_END_NAMESPACE
namespace Utils { class FileName; } namespace Utils { class FileName; }
namespace Core { class ICore; } namespace Core { class ICore; }
@@ -117,15 +113,6 @@ struct InternalNode;
class EvalInput; class EvalInput;
class EvalResult; class EvalResult;
class PriFileEvalResult; class PriFileEvalResult;
// TOOD can probably move into the .cpp file
class VariableAndVPathInformation
{
public:
QString variable;
QStringList vPathsExact;
QStringList vPathsCumulative;
};
} }
// Implements ProjectNode for qmake .pri files // Implements ProjectNode for qmake .pri files
@@ -210,8 +197,12 @@ private:
QStringList formResources(const QString &formFile) const; QStringList formResources(const QString &formFile) const;
static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir); static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir);
static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir); static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir);
static Internal::PriFileEvalResult extractValues(const Internal::EvalInput &input, ProFile *proFile, bool haveExact, static void extractSources(
const QList<QList<Internal::VariableAndVPathInformation>> &variableAndVPathInformation); QHash<const ProFile *, Internal::PriFileEvalResult *> proToResult,
Internal::PriFileEvalResult *fallback,
QVector<ProFileEvaluator::SourceFile> sourceFiles, ProjectExplorer::FileType type);
static void extractValues(
const Internal::EvalInput &input, ProFile *proFile, Internal::PriFileEvalResult &result);
void watchFolders(const QSet<QString> &folders); void watchFolders(const QSet<QString> &folders);
QmakeProject *m_project; QmakeProject *m_project;
@@ -387,8 +378,9 @@ private:
void updateGeneratedFiles(const QString &buildDir); void updateGeneratedFiles(const QString &buildDir);
static QStringList fileListForVar(QtSupport::ProFileReader *readerExact, QtSupport::ProFileReader *readerCumulative, static QStringList fileListForVar(
const QString &varName, const QString &projectDir, const QString &buildDir); const QHash<QString, QVector<ProFileEvaluator::SourceFile> > &sourceFiles,
const QString &varName);
static QString uiDirPath(QtSupport::ProFileReader *reader, const QString &buildDir); static QString uiDirPath(QtSupport::ProFileReader *reader, const QString &buildDir);
static QString mocDirPath(QtSupport::ProFileReader *reader, const QString &buildDir); static QString mocDirPath(QtSupport::ProFileReader *reader, const QString &buildDir);
static QString sysrootify(const QString &path, const QString &sysroot, const QString &baseDir, const QString &outputDir); static QString sysrootify(const QString &path, const QString &sysroot, const QString &baseDir, const QString &outputDir);

View File

@@ -119,17 +119,17 @@ QStringList ProFileEvaluator::absolutePathValues(
return result; return result;
} }
QStringList ProFileEvaluator::absoluteFileValues( QVector<ProFileEvaluator::SourceFile> ProFileEvaluator::absoluteFileValues(
const QString &variable, const QString &baseDirectory, const QStringList &searchDirs, const QString &variable, const QString &baseDirectory, const QStringList &searchDirs) const
const ProFile *pro) const
{ {
QMakeVfs::VfsFlags flags = (d->m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact); QMakeVfs::VfsFlags flags = (d->m_cumulative ? QMakeVfs::VfsCumulative : QMakeVfs::VfsExact);
QStringList result; QVector<SourceFile> result;
foreach (const QString &el, pro ? values(variable, pro) : values(variable)) { foreach (const ProString &str, d->values(ProKey(variable))) {
const QString &el = d->m_option->expandEnvVars(str.toQString());
QString absEl; QString absEl;
if (IoUtils::isAbsolutePath(el)) { if (IoUtils::isAbsolutePath(el)) {
if (m_vfs->exists(el, flags)) { if (m_vfs->exists(el, flags)) {
result << el; result << SourceFile{ el, str.sourceFile() };
goto next; goto next;
} }
absEl = el; absEl = el;
@@ -137,7 +137,7 @@ QStringList ProFileEvaluator::absoluteFileValues(
foreach (const QString &dir, searchDirs) { foreach (const QString &dir, searchDirs) {
QString fn = QDir::cleanPath(dir + QLatin1Char('/') + el); QString fn = QDir::cleanPath(dir + QLatin1Char('/') + el);
if (m_vfs->exists(fn, flags)) { if (m_vfs->exists(fn, flags)) {
result << fn; result << SourceFile{ QDir::cleanPath(fn), str.sourceFile() };
goto next; goto next;
} }
} }
@@ -157,7 +157,7 @@ QStringList ProFileEvaluator::absoluteFileValues(
theDir.setFilter(theDir.filter() & ~QDir::AllDirs); theDir.setFilter(theDir.filter() & ~QDir::AllDirs);
foreach (const QString &fn, theDir.entryList(QStringList(wildcard))) foreach (const QString &fn, theDir.entryList(QStringList(wildcard)))
if (fn != QLatin1String(".") && fn != QLatin1String("..")) if (fn != QLatin1String(".") && fn != QLatin1String(".."))
result << absDir + QLatin1Char('/') + fn; result << SourceFile{ absDir + QLatin1Char('/') + fn, str.sourceFile() };
} // else if (acceptMissing) } // else if (acceptMissing)
} }
} }

View File

@@ -53,6 +53,11 @@ public:
TT_Subdirs TT_Subdirs
}; };
struct SourceFile {
QString fileName;
const ProFile *proFile;
};
// Call this from a concurrency-free context // Call this from a concurrency-free context
static void initialize(); static void initialize();
@@ -79,9 +84,8 @@ public:
QStringList fixifiedValues( QStringList fixifiedValues(
const QString &variable, const QString &baseDirectory, const QString &buildDirectory) const; const QString &variable, const QString &baseDirectory, const QString &buildDirectory) const;
QStringList absolutePathValues(const QString &variable, const QString &baseDirectory) const; QStringList absolutePathValues(const QString &variable, const QString &baseDirectory) const;
QStringList absoluteFileValues( QVector<SourceFile> absoluteFileValues(
const QString &variable, const QString &baseDirectory, const QStringList &searchDirs, const QString &variable, const QString &baseDirectory, const QStringList &searchDirs) const;
const ProFile *pro) const;
QString propertyValue(const QString &val) const; QString propertyValue(const QString &val) const;
private: private:
@@ -89,4 +93,6 @@ private:
QMakeVfs *m_vfs; QMakeVfs *m_vfs;
}; };
Q_DECLARE_TYPEINFO(ProFileEvaluator::SourceFile, Q_MOVABLE_TYPE);
QT_END_NAMESPACE QT_END_NAMESPACE