forked from qt-creator/qt-creator
ClangPchManager: Filter missing includes recursively
Missing includes prevent the creation of PCHs. So removing includes which directly or indirectly point to missing includes is a requirement for working PCHs. Task-number: QTCREATORBUG-21529 Change-Id: Id55be164df590149fe1ab55c2a3a90b8b5e3bfa7 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
@@ -95,7 +95,7 @@ public:
|
||||
const clang::Module * /*imported*/,
|
||||
clang::SrcMgr::CharacteristicKind fileType) override
|
||||
{
|
||||
if (!m_skipInclude && file) {
|
||||
if (file) {
|
||||
addSourceDependency(file, hashLocation);
|
||||
auto fileUID = file->getUID();
|
||||
auto sourceFileUID = m_sourceManager
|
||||
@@ -124,24 +124,12 @@ public:
|
||||
addInclude({includeId, sourceType, lastModified});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto sourceFileId = filePathId(hashLocation);
|
||||
m_containsMissingIncludes.emplace_back(sourceFileId);
|
||||
}
|
||||
|
||||
m_skipInclude = false;
|
||||
}
|
||||
|
||||
bool FileNotFound(clang::StringRef /*fileNameRef*/,
|
||||
clang::SmallVectorImpl<char> &recoveryPath) override
|
||||
{
|
||||
auto dummyPath = llvm::StringRef("/dummyPath");
|
||||
|
||||
recoveryPath.append(std::cbegin(dummyPath), std::cend(dummyPath));
|
||||
|
||||
m_skipInclude = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Ifndef(clang::SourceLocation,
|
||||
const clang::Token ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition) override
|
||||
@@ -176,6 +164,128 @@ public:
|
||||
filterOutHeaderGuards();
|
||||
mergeUsedMacros();
|
||||
m_sourcesManager.updateModifiedTimeStamps();
|
||||
filterOutIncludesWithMissingIncludes();
|
||||
}
|
||||
|
||||
static
|
||||
void sortAndMakeUnique(FilePathIds &filePathIds)
|
||||
{
|
||||
std::sort(filePathIds.begin(), filePathIds.end());
|
||||
auto newEnd = std::unique(filePathIds.begin(),
|
||||
filePathIds.end());
|
||||
filePathIds.erase(newEnd, filePathIds.end());
|
||||
}
|
||||
|
||||
void appendContainsMissingIncludes(const FilePathIds &dependentSourceFilesWithMissingIncludes)
|
||||
{
|
||||
auto split = m_containsMissingIncludes
|
||||
.insert(m_containsMissingIncludes.end(),
|
||||
dependentSourceFilesWithMissingIncludes.begin(),
|
||||
dependentSourceFilesWithMissingIncludes.end());
|
||||
std::inplace_merge(m_containsMissingIncludes.begin(),
|
||||
split,
|
||||
m_containsMissingIncludes.end());
|
||||
}
|
||||
|
||||
void removeAlreadyFoundSourcesWithMissingIncludes(FilePathIds &dependentSourceFilesWithMissingIncludes) const
|
||||
{
|
||||
FilePathIds filteredDependentSourceFilesWithMissingIncludes;
|
||||
filteredDependentSourceFilesWithMissingIncludes.reserve(dependentSourceFilesWithMissingIncludes.size());
|
||||
std::set_difference(dependentSourceFilesWithMissingIncludes.begin(),
|
||||
dependentSourceFilesWithMissingIncludes.end(),
|
||||
m_containsMissingIncludes.begin(),
|
||||
m_containsMissingIncludes.end(),
|
||||
std::back_inserter(filteredDependentSourceFilesWithMissingIncludes));
|
||||
dependentSourceFilesWithMissingIncludes = filteredDependentSourceFilesWithMissingIncludes;
|
||||
}
|
||||
|
||||
void collectSourceWithMissingIncludes(FilePathIds containsMissingIncludes,
|
||||
const SourceDependencies &sourceDependencies)
|
||||
{
|
||||
if (containsMissingIncludes.empty())
|
||||
return;
|
||||
|
||||
class Compare
|
||||
{
|
||||
public:
|
||||
bool operator()(SourceDependency sourceDependency, FilePathId filePathId)
|
||||
{
|
||||
return sourceDependency.dependencyFilePathId < filePathId;
|
||||
}
|
||||
bool operator()(FilePathId filePathId, SourceDependency sourceDependency)
|
||||
{
|
||||
return filePathId < sourceDependency.dependencyFilePathId;
|
||||
}
|
||||
};
|
||||
|
||||
FilePathIds dependentSourceFilesWithMissingIncludes;
|
||||
auto begin = sourceDependencies.begin();
|
||||
for (FilePathId sourceWithMissingInclude : containsMissingIncludes) {
|
||||
auto range = std::equal_range(begin,
|
||||
sourceDependencies.end(),
|
||||
sourceWithMissingInclude,
|
||||
Compare{});
|
||||
std::for_each(range.first, range.second, [&](auto entry) {
|
||||
dependentSourceFilesWithMissingIncludes.emplace_back(entry.filePathId);
|
||||
});
|
||||
|
||||
begin = range.second;
|
||||
}
|
||||
|
||||
sortAndMakeUnique(dependentSourceFilesWithMissingIncludes);
|
||||
removeAlreadyFoundSourcesWithMissingIncludes(dependentSourceFilesWithMissingIncludes);
|
||||
appendContainsMissingIncludes(dependentSourceFilesWithMissingIncludes);
|
||||
collectSourceWithMissingIncludes(dependentSourceFilesWithMissingIncludes,
|
||||
sourceDependencies);
|
||||
}
|
||||
|
||||
void removeSourceWithMissingIncludesFromIncludes()
|
||||
{
|
||||
class Compare
|
||||
{
|
||||
public:
|
||||
bool operator()(SourceEntry entry, FilePathId filePathId)
|
||||
{
|
||||
return entry.sourceId < filePathId;
|
||||
}
|
||||
bool operator()(FilePathId filePathId, SourceEntry entry)
|
||||
{
|
||||
return filePathId < entry.sourceId;
|
||||
}
|
||||
};
|
||||
|
||||
auto &includes = m_buildDependency.includes;
|
||||
SourceEntries newIncludes;
|
||||
newIncludes.reserve(includes.size());
|
||||
std::set_difference(includes.begin(),
|
||||
includes.end(),
|
||||
m_containsMissingIncludes.begin(),
|
||||
m_containsMissingIncludes.end(),
|
||||
std::back_inserter(newIncludes),
|
||||
Compare{});
|
||||
|
||||
m_buildDependency.includes = newIncludes;
|
||||
}
|
||||
|
||||
SourceDependencies sourceDependenciesSortedByDependendFilePathId() const
|
||||
{
|
||||
auto sourceDependencies = m_buildDependency.sourceDependencies;
|
||||
std::sort(sourceDependencies.begin(), sourceDependencies.end(), [](auto first, auto second) {
|
||||
return std::tie(first.dependencyFilePathId, first.filePathId)
|
||||
< std::tie(second.dependencyFilePathId, second.filePathId);
|
||||
});
|
||||
|
||||
return sourceDependencies;
|
||||
}
|
||||
|
||||
void filterOutIncludesWithMissingIncludes()
|
||||
{
|
||||
sortAndMakeUnique(m_containsMissingIncludes);;
|
||||
|
||||
collectSourceWithMissingIncludes(m_containsMissingIncludes,
|
||||
sourceDependenciesSortedByDependendFilePathId());
|
||||
|
||||
removeSourceWithMissingIncludesFromIncludes();
|
||||
}
|
||||
|
||||
void ensureDirectory(const QString &directory, const QString &fileName)
|
||||
@@ -230,7 +340,6 @@ private:
|
||||
BuildDependency &m_buildDependency;
|
||||
const std::vector<uint> &m_excludedIncludeUID;
|
||||
std::vector<uint> &m_alreadyIncludedFileUIDs;
|
||||
bool m_skipInclude = false;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -494,6 +494,25 @@ TEST_F(BuildDependencyCollector, CollectSourceDependencies)
|
||||
SourceDependency(header1FileId, header2FileId)));
|
||||
}
|
||||
|
||||
TEST_F(BuildDependencyCollector, MissingInclude)
|
||||
{
|
||||
emptyCollector.addFile(id(TESTDATA_DIR "/builddependencycollector/project/main5.cpp"),
|
||||
{"cc",
|
||||
"-I",
|
||||
TESTDATA_DIR "/builddependencycollector/external",
|
||||
"-I",
|
||||
TESTDATA_DIR "/builddependencycollector/project",
|
||||
"-isystem",
|
||||
TESTDATA_DIR "/builddependencycollector/system"});
|
||||
|
||||
emptyCollector.collect();
|
||||
|
||||
ASSERT_THAT(emptyCollector.includeIds(),
|
||||
ElementsAre(
|
||||
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
|
||||
SourceType::UserInclude)));
|
||||
}
|
||||
|
||||
TEST_F(BuildDependencyCollector, Create)
|
||||
{
|
||||
ClangBackEnd::BuildDependencyCollector collector{filePathCache};
|
||||
@@ -508,10 +527,12 @@ TEST_F(BuildDependencyCollector, Create)
|
||||
TESTDATA_DIR "/builddependencycollector/system"},
|
||||
{},
|
||||
{},
|
||||
{id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
|
||||
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
|
||||
{
|
||||
id(TESTDATA_DIR "/builddependencycollector/project/header1.h"),
|
||||
id(TESTDATA_DIR "/builddependencycollector/project/header2.h"),
|
||||
id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"),
|
||||
id(TESTDATA_DIR "/builddependencycollector/project/macros.h"),},
|
||||
id(TESTDATA_DIR "/builddependencycollector/project/macros.h"),
|
||||
},
|
||||
{id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp")}};
|
||||
|
||||
auto buildDependency = collector.create(projectPart);
|
||||
@@ -562,8 +583,6 @@ TEST_F(BuildDependencyCollector, Create)
|
||||
HasInclude(id(TESTDATA_DIR
|
||||
"/builddependencycollector/system/indirect_system2.h"),
|
||||
SourceType::SystemInclude),
|
||||
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"),
|
||||
SourceType::UserInclude),
|
||||
HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/macros.h"),
|
||||
SourceType::UserInclude))),
|
||||
Field(&BuildDependency::usedMacros,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "indirect_missinginclude3.h"
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "indirect_missinginclude4.h"
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "indirect_missinginclude4.h"
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "indirect_missinginclude3.h"
|
||||
|
||||
#include "not_found"
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "missinginclude2.h"
|
||||
#include "missinginclude3.h"
|
||||
|
||||
#include "header1.h"
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "indirect_missinginclude.h"
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "indirect_missinginclude2.h"
|
||||
Reference in New Issue
Block a user