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:
Marco Bubke
2018-11-19 19:56:58 +01:00
parent 64a3a130ac
commit 2a65be107b
9 changed files with 174 additions and 22 deletions

View File

@@ -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 &macroNameToken,
const clang::MacroDefinition &macroDefinition) 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

View File

@@ -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,

View File

@@ -0,0 +1,3 @@
#pragma once
#include "indirect_missinginclude3.h"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "indirect_missinginclude4.h"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "indirect_missinginclude4.h"

View File

@@ -0,0 +1,5 @@
#pragma once
#include "indirect_missinginclude3.h"
#include "not_found"

View File

@@ -0,0 +1,4 @@
#include "missinginclude2.h"
#include "missinginclude3.h"
#include "header1.h"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "indirect_missinginclude.h"

View File

@@ -0,0 +1,3 @@
#pragma once
#include "indirect_missinginclude2.h"