Commit a48adcf9 authored by Erik Verbruggen's avatar Erik Verbruggen Committed by Erik Verbruggen

C++: handle case-insensitive file names in the CPlusPlus::Snapshot

... by keying on Utils::FileName

Task-number: QTCREATORBUG-12390
Change-Id: Ia98afb5a9160a7fd9225a2f9e02539ff3c35ae86
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent a8ece5e9
......@@ -741,17 +741,17 @@ bool Snapshot::isEmpty() const
return _documents.isEmpty();
}
Snapshot::const_iterator Snapshot::find(const QString &fileName) const
Snapshot::const_iterator Snapshot::find(const Utils::FileName &fileName) const
{
return _documents.find(fileName);
}
void Snapshot::remove(const QString &fileName)
void Snapshot::remove(const Utils::FileName &fileName)
{
_documents.remove(fileName);
}
bool Snapshot::contains(const QString &fileName) const
bool Snapshot::contains(const Utils::FileName &fileName) const
{
return _documents.contains(fileName);
}
......@@ -759,15 +759,15 @@ bool Snapshot::contains(const QString &fileName) const
void Snapshot::insert(Document::Ptr doc)
{
if (doc) {
_documents.insert(doc->fileName(), doc);
_documents.insert(Utils::FileName::fromString(doc->fileName()), doc);
m_deps.files.clear(); // Will trigger re-build when accessed.
}
}
Document::Ptr Snapshot::preprocessedDocument(const QByteArray &source,
const QString &fileName) const
const Utils::FileName &fileName) const
{
Document::Ptr newDoc = Document::create(fileName);
Document::Ptr newDoc = Document::create(fileName.toString());
if (Document::Ptr thisDocument = document(fileName)) {
newDoc->_revision = thisDocument->_revision;
newDoc->_editorRevision = thisDocument->_editorRevision;
......@@ -821,7 +821,7 @@ QList<Snapshot::IncludeLocation> Snapshot::includeLocationsOfDocument(const QStr
return result;
}
QStringList Snapshot::filesDependingOn(const QString &fileName) const
Utils::FileNameList Snapshot::filesDependingOn(const Utils::FileName &fileName) const
{
updateDependencyTable();
return m_deps.filesDependingOn(fileName);
......@@ -850,7 +850,7 @@ void Snapshot::allIncludesForDocument_helper(const QString &fileName, QSet<QStri
}
}
Document::Ptr Snapshot::document(const QString &fileName) const
Document::Ptr Snapshot::document(const Utils::FileName &fileName) const
{
return _documents.value(fileName);
}
......
......@@ -37,6 +37,8 @@
#include <cplusplus/PreprocessorClient.h>
#include <cplusplus/DependencyTable.h>
#include <utils/fileutils.h>
#include <QSharedPointer>
#include <QDateTime>
#include <QHash>
......@@ -395,7 +397,7 @@ private:
class CPLUSPLUS_EXPORT Snapshot
{
typedef QHash<QString, Document::Ptr> Base;
typedef QHash<Utils::FileName, Document::Ptr> Base;
public:
Snapshot();
......@@ -409,20 +411,32 @@ public:
bool isEmpty() const;
void insert(Document::Ptr doc); // ### remove
void remove(const QString &fileName); // ### remove
void remove(const Utils::FileName &fileName); // ### remove
void remove(const QString &fileName)
{ remove(Utils::FileName::fromString(fileName)); }
const_iterator begin() const { return _documents.begin(); }
const_iterator end() const { return _documents.end(); }
bool contains(const QString &fileName) const;
Document::Ptr document(const QString &fileName) const;
bool contains(const Utils::FileName &fileName) const;
bool contains(const QString &fileName) const
{ return contains(Utils::FileName::fromString(fileName)); }
Document::Ptr document(const Utils::FileName &fileName) const;
Document::Ptr document(const QString &fileName) const
{ return document(Utils::FileName::fromString(fileName)); }
const_iterator find(const QString &fileName) const;
const_iterator find(const Utils::FileName &fileName) const;
const_iterator find(const QString &fileName) const
{ return find(Utils::FileName::fromString(fileName)); }
Snapshot simplified(Document::Ptr doc) const;
Document::Ptr preprocessedDocument(const QByteArray &source,
const QString &fileName) const;
const Utils::FileName &fileName) const;
Document::Ptr preprocessedDocument(const QByteArray &source,
const QString &fileName) const
{ return preprocessedDocument(source, Utils::FileName::fromString(fileName)); }
Document::Ptr documentFromSource(const QByteArray &preprocessedDocument,
const QString &fileName) const;
......@@ -430,7 +444,9 @@ public:
QSet<QString> allIncludesForDocument(const QString &fileName) const;
QList<IncludeLocation> includeLocationsOfDocument(const QString &fileName) const;
QStringList filesDependingOn(const QString &fileName) const;
Utils::FileNameList filesDependingOn(const Utils::FileName &fileName) const;
Utils::FileNameList filesDependingOn(const QString &fileName) const
{ return filesDependingOn(Utils::FileName::fromString(fileName)); }
void updateDependencyTable() const;
bool operator==(const Snapshot &other) const;
......
......@@ -34,13 +34,14 @@
using namespace CPlusPlus;
QStringList DependencyTable::filesDependingOn(const QString &fileName) const
Utils::FileNameList DependencyTable::filesDependingOn(const Utils::FileName &fileName) const
{
Utils::FileNameList deps;
int index = fileIndex.value(fileName, -1);
if (index == -1)
return QStringList();
return deps;
QStringList deps;
for (int i = 0; i < files.size(); ++i) {
const QBitArray &bits = includeMap.at(i);
......@@ -53,7 +54,6 @@ QStringList DependencyTable::filesDependingOn(const QString &fileName) const
void DependencyTable::build(const Snapshot &snapshot)
{
includesPerFile.clear();
files.clear();
fileIndex.clear();
includes.clear();
......@@ -71,15 +71,14 @@ void DependencyTable::build(const Snapshot &snapshot)
}
for (int i = 0; i < files.size(); ++i) {
const QString fileName = files.at(i);
if (Document::Ptr doc = snapshot.document(files.at(i))) {
const Utils::FileName &fileName = files.at(i);
if (Document::Ptr doc = snapshot.document(fileName)) {
QBitArray bitmap(files.size());
QList<int> directIncludes;
const QStringList documentIncludes = doc->includedFiles();
includesPerFile.insert(fileName, documentIncludes);
foreach (const QString &includedFile, documentIncludes) {
int index = fileIndex.value(includedFile);
int index = fileIndex.value(Utils::FileName::fromString(includedFile));
if (index == -1)
continue;
......
......@@ -33,6 +33,8 @@
#include <cplusplus/CPlusPlusForwardDeclarations.h>
#include <utils/fileutils.h>
#include <QBitArray>
#include <QHash>
#include <QString>
......@@ -48,11 +50,10 @@ class CPLUSPLUS_EXPORT DependencyTable
private:
friend class Snapshot;
void build(const Snapshot &snapshot);
QStringList filesDependingOn(const QString &fileName) const;
Utils::FileNameList filesDependingOn(const Utils::FileName &fileName) const;
QHash<QString, QStringList> includesPerFile;
QVector<QString> files;
QHash<QString, int> fileIndex;
QVector<Utils::FileName> files;
QHash<Utils::FileName, int> fileIndex;
QHash<int, QList<int> > includes;
QVector<QBitArray> includeMap;
};
......
......@@ -53,8 +53,8 @@ QByteArray FastPreprocessor::run(Document::Ptr newDoc, const QByteArray &source)
_merged.insert(fileName);
for (Snapshot::const_iterator i = _snapshot.begin(), ei = _snapshot.end(); i != ei; ++i) {
if (isInjectedFile(i.key()))
mergeEnvironment(i.key());
if (isInjectedFile(i.key().toString()))
mergeEnvironment(i.key().toString());
}
foreach (const Document::Include &i, doc->resolvedIncludes())
......
......@@ -624,6 +624,13 @@ FileName FileName::fromUserInput(const QString &filename)
return FileName(clean);
}
/// Constructs a FileName from \a fileName, which is encoded as UTF-8.
/// \a fileName is not checked for validity.
FileName FileName::fromUtf8(const char *filename, int filenameSize)
{
return FileName(QString::fromUtf8(filename, filenameSize));
}
FileName::FileName(const QString &string)
: QString(string)
{
......@@ -726,6 +733,25 @@ QTextStream &operator<<(QTextStream &s, const FileName &fn)
return s << fn.toString();
}
int FileNameList::removeDuplicates()
{
QSet<FileName> seen;
int removed = 0;
for (int i = 0; i < size(); ) {
const FileName &fn = at(i);
if (seen.contains(fn)) {
removeAt(i);
++removed;
} else {
seen.insert(fn);
++i;
}
}
return removed;
}
static bool isFileDrop(const QMimeData *d, QList<FileDropSupport::FileSpec> *files = 0)
{
// internal drop
......
......@@ -70,6 +70,7 @@ public:
static FileName fromString(const QString &filename, const QString &defaultExtension);
static FileName fromLatin1(const QByteArray &filename);
static FileName fromUserInput(const QString &filename);
static FileName fromUtf8(const char *filename, int filenameSize = -1);
QString toString() const;
QString toUserOutput() const;
bool exists() const;
......@@ -104,6 +105,17 @@ private:
QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FileName &fn);
class QTCREATOR_UTILS_EXPORT FileNameList : public QList<FileName>
{
public:
inline FileNameList() { }
inline explicit FileNameList(const FileName &i) { append(i); }
inline FileNameList(const FileNameList &l) : QList<FileName>(l) { }
inline FileNameList(const QList<FileName> &l) : QList<FileName>(l) { }
int removeDuplicates();
};
class QTCREATOR_UTILS_EXPORT FileUtils {
public:
static bool removeRecursively(const FileName &filePath, QString *error = 0);
......
......@@ -641,7 +641,7 @@ void Parser::resetData(const CPlusPlus::Snapshot &snapshot)
CPlusPlus::Snapshot::const_iterator cur = snapshot.begin();
CPlusPlus::Snapshot::const_iterator end = snapshot.end();
for (; cur != end; ++cur)
d->documentList[cur.key()] = cur.value();
d->documentList[cur.key().toString()] = cur.value();
d->docLocker.unlock();
......
......@@ -341,7 +341,7 @@ void CppIncludeHierarchyModel::buildHierarchyIncludedBy_helper(const QString &fi
cyclic->insert(filePath);
Snapshot::const_iterator citEnd = snapshot.end();
for (Snapshot::const_iterator cit = snapshot.begin(); cit != citEnd; ++cit) {
const QString filePathFromSnapshot = cit.key();
const QString filePathFromSnapshot = cit.key().toString();
Document::Ptr doc = cit.value();
foreach (const Document::Include &includeFile, doc->resolvedIncludes()) {
const QString includedFilePath = includeFile.resolvedFileName();
......
......@@ -1907,12 +1907,13 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa
Snapshot localForwardHeaders = forwardHeaders;
localForwardHeaders.insert(interface.snapshot().document(info->fileName()));
QStringList headerAndItsForwardingHeaders;
headerAndItsForwardingHeaders << info->fileName();
Utils::FileNameList headerAndItsForwardingHeaders;
headerAndItsForwardingHeaders << Utils::FileName::fromString(info->fileName());
headerAndItsForwardingHeaders += localForwardHeaders.filesDependingOn(info->fileName());
foreach (const QString &header, headerAndItsForwardingHeaders) {
const QString include = findShortestInclude(currentDocumentFilePath, header,
foreach (const Utils::FileName &header, headerAndItsForwardingHeaders) {
const QString include = findShortestInclude(currentDocumentFilePath,
header.toString(),
headerPaths);
if (include.size() > 2) {
const QString headerFileName = QFileInfo(info->fileName()).fileName();
......
......@@ -116,9 +116,9 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy)
m_snapshot = Snapshot();
} else {
// Remove changed files from the snapshot
QSet<QString> toRemove;
QSet<Utils::FileName> toRemove;
foreach (const Document::Ptr &doc, m_snapshot) {
QString fileName = doc->fileName();
const Utils::FileName fileName = Utils::FileName::fromString(doc->fileName());
if (workingCopy.contains(fileName)) {
if (workingCopy.get(fileName).second != doc->editorRevision())
addFileAndDependencies(&toRemove, fileName);
......@@ -131,7 +131,7 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy)
if (!toRemove.isEmpty()) {
invalidateSnapshot = true;
foreach (const QString &fileName, toRemove)
foreach (const Utils::FileName &fileName, toRemove)
m_snapshot.remove(fileName);
}
}
......@@ -183,7 +183,7 @@ void BuiltinEditorDocumentParser::update(WorkingCopy workingCopy)
m_snapshot = sourceProcessor.snapshot();
Snapshot newSnapshot = m_snapshot.simplified(document());
for (Snapshot::const_iterator i = m_snapshot.begin(), ei = m_snapshot.end(); i != ei; ++i) {
if (Client::isInjectedFile(i.key()))
if (Client::isInjectedFile(i.key().toString()))
newSnapshot.insert(i.value());
}
m_snapshot = newSnapshot;
......@@ -231,12 +231,12 @@ BuiltinEditorDocumentParser *BuiltinEditorDocumentParser::get(const QString &fil
return 0;
}
void BuiltinEditorDocumentParser::addFileAndDependencies(QSet<QString> *toRemove,
const QString &fileName) const
void BuiltinEditorDocumentParser::addFileAndDependencies(QSet<Utils::FileName> *toRemove,
const Utils::FileName &fileName) const
{
toRemove->insert(fileName);
if (fileName != filePath()) {
QStringList deps = m_snapshot.filesDependingOn(fileName);
toRemove->unite(QSet<QString>::fromList(deps));
if (fileName != Utils::FileName::fromString(filePath())) {
Utils::FileNameList deps = m_snapshot.filesDependingOn(fileName);
toRemove->unite(QSet<Utils::FileName>::fromList(deps));
}
}
......@@ -65,7 +65,7 @@ public:
static BuiltinEditorDocumentParser *get(const QString &filePath);
private:
void addFileAndDependencies(QSet<QString> *toRemove, const QString &fileName) const;
void addFileAndDependencies(QSet<Utils::FileName> *toRemove, const Utils::FileName &fileName) const;
private:
QByteArray m_configFile;
......
......@@ -55,7 +55,7 @@ using namespace CppTools::Internal;
using namespace CppTools;
using namespace CPlusPlus;
static QByteArray getSource(const QString &fileName,
static QByteArray getSource(const Utils::FileName &fileName,
const WorkingCopy &workingCopy)
{
if (workingCopy.contains(fileName)) {
......@@ -66,7 +66,7 @@ static QByteArray getSource(const QString &fileName,
QString error;
QTextCodec *defaultCodec = EditorManager::defaultTextCodec();
Utils::TextFileFormat::ReadResult result = Utils::TextFileFormat::readFile(
fileName, defaultCodec, &fileContents, &format, &error);
fileName.toString(), defaultCodec, &fileContents, &format, &error);
if (result != Utils::TextFileFormat::ReadSuccess)
qWarning() << "Could not read " << fileName << ". Error: " << error;
......@@ -188,7 +188,7 @@ public:
future(future)
{ }
QList<Usage> operator()(const QString &fileName)
QList<Usage> operator()(const Utils::FileName &fileName)
{
QList<Usage> usages;
if (future->isPaused())
......@@ -205,7 +205,7 @@ public:
Document::Ptr doc;
const QByteArray unpreprocessedSource = getSource(fileName, workingCopy);
if (symbolDocument && fileName == symbolDocument->fileName()) {
if (symbolDocument && fileName == Utils::FileName::fromString(symbolDocument->fileName())) {
doc = symbolDocument;
} else {
doc = snapshot.preprocessedDocument(unpreprocessedSource, fileName);
......@@ -278,22 +278,24 @@ static void find_helper(QFutureInterface<Usage> &future,
const Snapshot snapshot = context.snapshot();
const QString sourceFile = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
QStringList files(sourceFile);
const Utils::FileName sourceFile = Utils::FileName::fromUtf8(symbol->fileName(),
symbol->fileNameLength());
Utils::FileNameList files(sourceFile);
if (symbol->isClass()
|| symbol->isForwardClassDeclaration()
|| (symbol->enclosingScope()
&& !symbol->isStatic()
&& symbol->enclosingScope()->isNamespace())) {
foreach (const Document::Ptr &doc, context.snapshot()) {
if (doc->fileName() == sourceFile)
const Snapshot snapshotFromContext = context.snapshot();
for (auto i = snapshotFromContext.begin(), ei = snapshotFromContext.end(); i != ei; ++i) {
if (i.key() == sourceFile)
continue;
Control *control = doc->control();
const Control *control = i.value()->control();
if (control->findIdentifier(symbolId->chars(), symbolId->size()))
files.append(doc->fileName());
files.append(i.key());
}
} else {
files += snapshot.filesDependingOn(sourceFile);
......@@ -452,7 +454,8 @@ CPlusPlus::Symbol *CppFindReferences::findSymbol(const CppFindReferencesParamete
Document::Ptr newSymbolDocument = snapshot.document(symbolFile);
// document is not parsed and has no bindings yet, do it
QByteArray source = getSource(newSymbolDocument->fileName(), m_modelManager->workingCopy());
QByteArray source = getSource(Utils::FileName::fromString(newSymbolDocument->fileName()),
m_modelManager->workingCopy());
Document::Ptr doc =
snapshot.preprocessedDocument(source, newSymbolDocument->fileName());
doc->check();
......@@ -543,7 +546,7 @@ public:
: workingCopy(workingCopy), snapshot(snapshot), macro(macro), future(future)
{ }
QList<Usage> operator()(const QString &fileName)
QList<Usage> operator()(const Utils::FileName &fileName)
{
QList<Usage> usages;
Document::Ptr doc = snapshot.document(fileName);
......@@ -573,7 +576,7 @@ restart_search:
if (macro.name() == useMacro.name()) {
unsigned column;
const QString &lineSource = matchingLine(use.bytesBegin(), source, &column);
usages.append(Usage(fileName, lineSource, use.beginLine(), column,
usages.append(Usage(fileName.toString(), lineSource, use.beginLine(), column,
useMacro.nameToQString().size()));
}
}
......@@ -614,8 +617,8 @@ static void findMacroUses_helper(QFutureInterface<Usage> &future,
const Snapshot snapshot,
const Macro macro)
{
const QString& sourceFile = macro.fileName();
QStringList files(sourceFile);
const Utils::FileName sourceFile = Utils::FileName::fromString(macro.fileName());
Utils::FileNameList files(sourceFile);
files += snapshot.filesDependingOn(sourceFile);
files.removeDuplicates();
......@@ -662,7 +665,8 @@ void CppFindReferences::findMacroUses(const Macro &macro, const QString &replace
// add the macro definition itself
{
const QByteArray &source = getSource(macro.fileName(), workingCopy);
const QByteArray &source = getSource(Utils::FileName::fromString(macro.fileName()),
workingCopy);
unsigned column;
const QString line = FindMacroUsesInFile::matchingLine(macro.bytesOffset(), source,
&column);
......
......@@ -814,12 +814,12 @@ QList<ProjectPart::Ptr> CppModelManager::projectPart(const QString &fileName) co
QList<ProjectPart::Ptr> CppModelManager::projectPartFromDependencies(const QString &fileName) const
{
QSet<ProjectPart::Ptr> parts;
const QStringList deps = snapshot().filesDependingOn(fileName);
const Utils::FileNameList deps = snapshot().filesDependingOn(fileName);
{
QMutexLocker locker(&d->m_projectMutex);
foreach (const QString &dep, deps)
parts.unite(QSet<ProjectPart::Ptr>::fromList(d->m_fileToProjectParts.value(dep)));
QMutexLocker locker(&d->m_projectMutex);
foreach (const Utils::FileName &dep, deps) {
parts.unite(QSet<ProjectPart::Ptr>::fromList(
d->m_fileToProjectParts.value(dep.toString())));
}
return parts.values();
......@@ -963,7 +963,7 @@ void CppModelManager::GC()
}
Snapshot currentSnapshot = snapshot();
QSet<QString> reachableFiles;
QSet<Utils::FileName> reachableFiles;
// The configuration file is part of the project files, which is just fine.
// If single files are open, without any project, then there is no need to
// keep the configuration file around.
......@@ -974,9 +974,10 @@ void CppModelManager::GC()
const QString file = todo.last();
todo.removeLast();
if (reachableFiles.contains(file))
const Utils::FileName fileName = Utils::FileName::fromString(file);
if (reachableFiles.contains(fileName))
continue;
reachableFiles.insert(file);
reachableFiles.insert(fileName);
if (Document::Ptr doc = currentSnapshot.document(file))
todo += doc->includedFiles();
......@@ -986,12 +987,12 @@ void CppModelManager::GC()
QStringList notReachableFiles;
Snapshot newSnapshot;
for (Snapshot::const_iterator it = currentSnapshot.begin(); it != currentSnapshot.end(); ++it) {
const QString fileName = it.key();
const Utils::FileName &fileName = it.key();
if (reachableFiles.contains(fileName))
newSnapshot.insert(it.value());
else
notReachableFiles.append(fileName);
notReachableFiles.append(fileName.toString());
}
// Announce removing files and replace the snapshot
......
......@@ -195,9 +195,13 @@ void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
QStringList TypeHierarchyBuilder::filesDependingOn(CPlusPlus::Symbol *symbol) const
{
QStringList deps;
if (!symbol)
return QStringList();
return deps;
const QString file = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
return QStringList() << file << _snapshot.filesDependingOn(file);
Utils::FileName file = Utils::FileName::fromUtf8(symbol->fileName(), symbol->fileNameLength());
deps << file.toString();
foreach (const Utils::FileName &fileName, _snapshot.filesDependingOn(file))
deps.append(fileName.toString());
return deps;
}
......@@ -528,11 +528,10 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName,
Snapshot newDocTable;
const Project *uiProject = SessionManager::projectForFile(currentUiFile);
if (uiProject) {
Snapshot::const_iterator end = docTable.end();
for (Snapshot::iterator it = docTable.begin(); it != end; ++it) {
const Project *project = SessionManager::projectForFile(it.key());
for (Snapshot::const_iterator i = docTable.begin(), ei = docTable.end(); i != ei; ++i) {
const Project *project = SessionManager::projectForFile(i.key().toString());
if (project == uiProject)
newDocTable.insert(it.value());
newDocTable.insert(i.value());
}
} else {
const CppTools::WorkingCopy workingCopy =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment