forked from qt-creator/qt-creator
Clang: Prepare for multi-threading
* Make the necessary data implicitly shared since it might get accessed/modified from two different threads with follow-up changes. This applies for UnsavedFiles/UnsavedFile and ProjectPart::arguments(). * Avoid returning references. Change-Id: I98842c1cb90ae0d344a15c63b72cbc89568722d3 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -35,7 +35,8 @@ HEADERS += $$PWD/clangcodemodelserver.h \
|
||||
$$PWD/highlightingmarks.h \
|
||||
$$PWD/highlightingmarksiterator.h \
|
||||
$$PWD/utf8positionfromlinecolumn.h \
|
||||
$$PWD/clangfilepath.h
|
||||
$$PWD/clangfilepath.h \
|
||||
$$PWD/clangunsavedfilesshallowarguments.h
|
||||
|
||||
SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||
$$PWD/codecompleter.cpp \
|
||||
@@ -70,4 +71,5 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||
$$PWD/highlightingmark.cpp \
|
||||
$$PWD/highlightingmarks.cpp \
|
||||
$$PWD/utf8positionfromlinecolumn.cpp \
|
||||
$$PWD/clangfilepath.cpp
|
||||
$$PWD/clangfilepath.cpp \
|
||||
$$PWD/clangunsavedfilesshallowarguments.cpp
|
||||
|
||||
@@ -240,7 +240,8 @@ void ClangCodeModelServer::completeCode(const ClangBackEnd::CompleteCodeMessage
|
||||
TIME_SCOPE_DURATION("ClangCodeModelServer::completeCode");
|
||||
|
||||
try {
|
||||
CodeCompleter codeCompleter(translationUnits.translationUnit(message.filePath(), message.projectPartId()));
|
||||
CodeCompleter codeCompleter(translationUnits.translationUnit(message.filePath(), message.projectPartId()),
|
||||
unsavedFiles);
|
||||
|
||||
const auto codeCompletions = codeCompleter.complete(message.line(), message.column());
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "cursor.h"
|
||||
#include "clangfilepath.h"
|
||||
#include "clangstring.h"
|
||||
#include "clangunsavedfilesshallowarguments.h"
|
||||
#include "codecompleter.h"
|
||||
#include "commandlinearguments.h"
|
||||
#include "diagnosticcontainer.h"
|
||||
@@ -43,6 +44,7 @@
|
||||
#include "translationunitreparseerrorexception.h"
|
||||
#include "translationunits.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "unsavedfile.h"
|
||||
|
||||
#include <utf8string.h>
|
||||
|
||||
@@ -199,19 +201,26 @@ CXTranslationUnit TranslationUnit::cxTranslationUnitWithoutReparsing() const
|
||||
return d->translationUnit;
|
||||
}
|
||||
|
||||
UnsavedFile &TranslationUnit::unsavedFile() const
|
||||
UnsavedFile TranslationUnit::unsavedFile() const
|
||||
{
|
||||
return unsavedFiles().unsavedFile(filePath());
|
||||
}
|
||||
|
||||
const Utf8String &TranslationUnit::filePath() const
|
||||
Utf8String TranslationUnit::filePath() const
|
||||
{
|
||||
checkIfNull();
|
||||
|
||||
return d->filePath;
|
||||
}
|
||||
|
||||
const Utf8String &TranslationUnit::projectPartId() const
|
||||
Utf8StringVector TranslationUnit::fileArguments() const
|
||||
{
|
||||
checkIfNull();
|
||||
|
||||
return d->fileArguments;
|
||||
}
|
||||
|
||||
Utf8String TranslationUnit::projectPartId() const
|
||||
{
|
||||
checkIfNull();
|
||||
|
||||
@@ -410,12 +419,14 @@ void TranslationUnit::createTranslationUnitIfNeeded() const
|
||||
if (isVerboseModeEnabled())
|
||||
args.print();
|
||||
|
||||
UnsavedFilesShallowArguments unsaved = unsavedFiles().shallowArguments();
|
||||
|
||||
d->parseErrorCode = clang_parseTranslationUnit2(index(),
|
||||
NULL,
|
||||
args.data(),
|
||||
args.count(),
|
||||
unsavedFiles().cxUnsavedFiles(),
|
||||
unsavedFiles().count(),
|
||||
unsaved.data(),
|
||||
unsaved.count(),
|
||||
defaultOptions(),
|
||||
&d->translationUnit);
|
||||
|
||||
@@ -447,10 +458,12 @@ void TranslationUnit::checkReparseErrorCode() const
|
||||
|
||||
void TranslationUnit::reparseTranslationUnit() const
|
||||
{
|
||||
UnsavedFilesShallowArguments unsaved = unsavedFiles().shallowArguments();
|
||||
|
||||
d->reparseErrorCode = clang_reparseTranslationUnit(
|
||||
d->translationUnit,
|
||||
unsavedFiles().count(),
|
||||
unsavedFiles().cxUnsavedFiles(),
|
||||
unsaved.count(),
|
||||
unsaved.data(),
|
||||
clang_defaultReparseOptions(d->translationUnit));
|
||||
|
||||
checkReparseErrorCode();
|
||||
@@ -480,7 +493,7 @@ void TranslationUnit::includeCallback(CXFile included_file,
|
||||
translationUnit->d->dependedFilePaths.insert(normalizedFilePath);
|
||||
}
|
||||
|
||||
UnsavedFiles &TranslationUnit::unsavedFiles() const
|
||||
UnsavedFiles TranslationUnit::unsavedFiles() const
|
||||
{
|
||||
return d->translationUnits.unsavedFiles();
|
||||
}
|
||||
@@ -539,11 +552,6 @@ uint TranslationUnit::unsavedFilesCount() const
|
||||
return unsavedFiles().count();
|
||||
}
|
||||
|
||||
CXUnsavedFile *TranslationUnit::cxUnsavedFiles() const
|
||||
{
|
||||
return unsavedFiles().cxUnsavedFiles();
|
||||
}
|
||||
|
||||
TranslationUnit::~TranslationUnit() = default;
|
||||
|
||||
TranslationUnit::TranslationUnit(const TranslationUnit &) = default;
|
||||
|
||||
@@ -96,13 +96,14 @@ public:
|
||||
CXTranslationUnit cxTranslationUnit() const;
|
||||
CXTranslationUnit cxTranslationUnitWithoutReparsing() const;
|
||||
|
||||
UnsavedFile &unsavedFile() const;
|
||||
CXUnsavedFile * cxUnsavedFiles() const;
|
||||
UnsavedFile unsavedFile() const;
|
||||
UnsavedFiles unsavedFiles() const;
|
||||
|
||||
uint unsavedFilesCount() const;
|
||||
|
||||
const Utf8String &filePath() const;
|
||||
const Utf8String &projectPartId() const;
|
||||
Utf8String filePath() const;
|
||||
Utf8StringVector fileArguments() const;
|
||||
Utf8String projectPartId() const;
|
||||
FileContainer fileContainer() const;
|
||||
const ProjectPart &projectPart() const;
|
||||
|
||||
@@ -163,7 +164,6 @@ private:
|
||||
CXSourceLocation * /*inclusion_stack*/,
|
||||
unsigned /*include_len*/,
|
||||
CXClientData clientData);
|
||||
UnsavedFiles &unsavedFiles() const;
|
||||
|
||||
private:
|
||||
mutable std::shared_ptr<TranslationUnitData> d;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangunsavedfilesshallowarguments.h"
|
||||
#include "clangfilepath.h"
|
||||
|
||||
#include "unsavedfile.h"
|
||||
#include "unsavedfiles.h"
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
UnsavedFilesShallowArguments::UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles)
|
||||
{
|
||||
const int unsavedFilesCount = int(unsavedFiles.count());
|
||||
m_cxUnsavedFiles.resize(unsavedFilesCount);
|
||||
|
||||
for (int i = 0, total = unsavedFilesCount; i < total; ++i) {
|
||||
const UnsavedFile &unsavedFile = unsavedFiles.at(i);
|
||||
m_cxUnsavedFiles[i].Filename = unsavedFile.nativeFilePath().constData();
|
||||
m_cxUnsavedFiles[i].Contents = unsavedFile.fileContent().constData();
|
||||
m_cxUnsavedFiles[i].Length = uint(unsavedFile.fileContent().byteSize());
|
||||
}
|
||||
}
|
||||
|
||||
uint UnsavedFilesShallowArguments::count() const
|
||||
{
|
||||
return uint(m_cxUnsavedFiles.count());
|
||||
}
|
||||
|
||||
CXUnsavedFile *UnsavedFilesShallowArguments::data()
|
||||
{
|
||||
return m_cxUnsavedFiles.data();
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
@@ -0,0 +1,48 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class UnsavedFile;
|
||||
class UnsavedFiles;
|
||||
|
||||
class UnsavedFilesShallowArguments {
|
||||
public:
|
||||
UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles);
|
||||
|
||||
uint count() const;
|
||||
CXUnsavedFile *data();
|
||||
|
||||
private:
|
||||
QVector<CXUnsavedFile> m_cxUnsavedFiles;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
@@ -33,8 +33,10 @@
|
||||
#include "codecompletionsextractor.h"
|
||||
#include "sourcelocation.h"
|
||||
#include "unsavedfile.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "clangtranslationunit.h"
|
||||
#include "sourcerange.h"
|
||||
#include "clangunsavedfilesshallowarguments.h"
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
@@ -55,8 +57,10 @@ CodeCompletions toCodeCompletions(const ClangCodeCompleteResults &results)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CodeCompleter::CodeCompleter(TranslationUnit translationUnit)
|
||||
CodeCompleter::CodeCompleter(TranslationUnit translationUnit,
|
||||
const UnsavedFiles &unsavedFiles)
|
||||
: translationUnit(std::move(translationUnit))
|
||||
, unsavedFiles(unsavedFiles)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -64,10 +68,7 @@ CodeCompletions CodeCompleter::complete(uint line, uint column)
|
||||
{
|
||||
neededCorrection_ = CompletionCorrection::NoCorrection;
|
||||
|
||||
ClangCodeCompleteResults results = complete(line,
|
||||
column,
|
||||
translationUnit.cxUnsavedFiles(),
|
||||
translationUnit.unsavedFilesCount());
|
||||
ClangCodeCompleteResults results = completeHelper(line, column);
|
||||
|
||||
tryDotArrowCorrectionIfNoResults(results, line, column);
|
||||
|
||||
@@ -79,19 +80,17 @@ CompletionCorrection CodeCompleter::neededCorrection() const
|
||||
return neededCorrection_;
|
||||
}
|
||||
|
||||
ClangCodeCompleteResults CodeCompleter::complete(uint line,
|
||||
uint column,
|
||||
CXUnsavedFile *unsavedFiles,
|
||||
unsigned unsavedFileCount)
|
||||
ClangCodeCompleteResults CodeCompleter::completeHelper(uint line, uint column)
|
||||
{
|
||||
const Utf8String nativeFilePath = FilePath::toNativeSeparators(translationUnit.filePath());
|
||||
UnsavedFilesShallowArguments unsaved = unsavedFiles.shallowArguments();
|
||||
|
||||
return clang_codeCompleteAt(translationUnit.cxTranslationUnitWithoutReparsing(),
|
||||
nativeFilePath.constData(),
|
||||
line,
|
||||
column,
|
||||
unsavedFiles,
|
||||
unsavedFileCount,
|
||||
unsaved.data(),
|
||||
unsaved.count(),
|
||||
defaultOptions());
|
||||
}
|
||||
|
||||
@@ -106,6 +105,11 @@ uint CodeCompleter::defaultOptions() const
|
||||
return options;
|
||||
}
|
||||
|
||||
UnsavedFile &CodeCompleter::unsavedFile()
|
||||
{
|
||||
return unsavedFiles.unsavedFile(translationUnit.filePath());
|
||||
}
|
||||
|
||||
void CodeCompleter::tryDotArrowCorrectionIfNoResults(ClangCodeCompleteResults &results,
|
||||
uint line,
|
||||
uint column)
|
||||
@@ -124,16 +128,12 @@ ClangCodeCompleteResults CodeCompleter::completeWithArrowInsteadOfDot(uint line,
|
||||
uint dotPosition)
|
||||
{
|
||||
ClangCodeCompleteResults results;
|
||||
const bool replaced = translationUnit.unsavedFile().replaceAt(dotPosition,
|
||||
1,
|
||||
Utf8StringLiteral("->"));
|
||||
const bool replaced = unsavedFile().replaceAt(dotPosition,
|
||||
1,
|
||||
Utf8StringLiteral("->"));
|
||||
|
||||
if (replaced) {
|
||||
results = complete(line,
|
||||
column + 1,
|
||||
translationUnit.cxUnsavedFiles(),
|
||||
translationUnit.unsavedFilesCount());
|
||||
|
||||
results = completeHelper(line, column + 1);
|
||||
if (results.hasResults())
|
||||
neededCorrection_ = CompletionCorrection::DotToArrowCorrection;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "clangtranslationunit.h"
|
||||
#include "unsavedfiles.h"
|
||||
|
||||
#include <codecompletion.h>
|
||||
|
||||
@@ -39,7 +40,8 @@ class CodeCompleter
|
||||
{
|
||||
public:
|
||||
CodeCompleter() = default;
|
||||
CodeCompleter(TranslationUnit translationUnit);
|
||||
CodeCompleter(TranslationUnit translationUnit,
|
||||
const UnsavedFiles &unsavedFiles);
|
||||
|
||||
CodeCompletions complete(uint line, uint column);
|
||||
|
||||
@@ -47,15 +49,13 @@ public:
|
||||
|
||||
private:
|
||||
uint defaultOptions() const;
|
||||
UnsavedFile &unsavedFile();
|
||||
|
||||
void tryDotArrowCorrectionIfNoResults(ClangCodeCompleteResults &results,
|
||||
uint line,
|
||||
uint column);
|
||||
|
||||
ClangCodeCompleteResults complete(uint line,
|
||||
uint column,
|
||||
CXUnsavedFile *unsavedFiles,
|
||||
unsigned unsavedFileCount);
|
||||
ClangCodeCompleteResults completeHelper(uint line, uint column);
|
||||
ClangCodeCompleteResults completeWithArrowInsteadOfDot(uint line,
|
||||
uint column,
|
||||
uint dotPosition);
|
||||
@@ -65,6 +65,7 @@ private:
|
||||
|
||||
private:
|
||||
TranslationUnit translationUnit;
|
||||
UnsavedFiles unsavedFiles;
|
||||
CompletionCorrection neededCorrection_ = CompletionCorrection::NoCorrection;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
namespace ClangBackEnd {
|
||||
|
||||
CommandLineArguments::CommandLineArguments(const char *filePath,
|
||||
const std::vector<const char *> &projectPartArguments,
|
||||
const Utf8StringVector &projectPartArguments,
|
||||
const Utf8StringVector &fileArguments,
|
||||
bool addVerboseOption)
|
||||
{
|
||||
@@ -46,7 +46,8 @@ CommandLineArguments::CommandLineArguments(const char *filePath,
|
||||
+ (addVerboseOption ? 1 : 0);
|
||||
m_arguments.reserve(elementsToReserve);
|
||||
|
||||
m_arguments = projectPartArguments;
|
||||
for (const auto &argument : projectPartArguments)
|
||||
m_arguments.push_back(argument.constData());
|
||||
for (const auto &argument : fileArguments)
|
||||
m_arguments.push_back(argument.constData());
|
||||
if (addVerboseOption)
|
||||
|
||||
@@ -35,7 +35,7 @@ class CommandLineArguments
|
||||
{
|
||||
public:
|
||||
CommandLineArguments(const char *filePath,
|
||||
const std::vector<const char *> &projectPartArguments,
|
||||
const Utf8StringVector &projectPartArguments,
|
||||
const Utf8StringVector &fileArguments,
|
||||
bool addVerboseOption);
|
||||
|
||||
|
||||
@@ -38,23 +38,12 @@ public:
|
||||
ProjectPartData(const Utf8String &projectPartId);
|
||||
~ProjectPartData();
|
||||
|
||||
public:
|
||||
void clearArguments();
|
||||
|
||||
public:
|
||||
time_point lastChangeTimePoint;
|
||||
std::vector<const char*> arguments;
|
||||
Utf8StringVector arguments;
|
||||
Utf8String projectPartId;
|
||||
};
|
||||
|
||||
void ProjectPartData::clearArguments()
|
||||
{
|
||||
for (auto argument : arguments)
|
||||
delete [] argument;
|
||||
|
||||
arguments.clear();
|
||||
}
|
||||
|
||||
ProjectPartData::ProjectPartData(const Utf8String &projectPartId)
|
||||
: lastChangeTimePoint(std::chrono::steady_clock::now()),
|
||||
projectPartId(projectPartId)
|
||||
@@ -63,7 +52,6 @@ ProjectPartData::ProjectPartData(const Utf8String &projectPartId)
|
||||
|
||||
ProjectPartData::~ProjectPartData()
|
||||
{
|
||||
clearArguments();
|
||||
}
|
||||
|
||||
ProjectPart::ProjectPart(const Utf8String &projectPartId)
|
||||
@@ -103,46 +91,26 @@ ProjectPart &ProjectPart::operator=(ProjectPart &&other)
|
||||
void ProjectPart::clear()
|
||||
{
|
||||
d->projectPartId.clear();
|
||||
d->clearArguments();
|
||||
d->arguments.clear();
|
||||
updateLastChangeTimePoint();
|
||||
}
|
||||
|
||||
const Utf8String &ProjectPart::projectPartId() const
|
||||
Utf8String ProjectPart::projectPartId() const
|
||||
{
|
||||
return d->projectPartId;
|
||||
}
|
||||
|
||||
static const char *strdup(const Utf8String &utf8String)
|
||||
{
|
||||
char *cxArgument = new char[utf8String.byteSize() + 1];
|
||||
std::memcpy(cxArgument, utf8String.constData(), utf8String.byteSize() + 1);
|
||||
|
||||
return cxArgument;
|
||||
}
|
||||
|
||||
void ProjectPart::setArguments(const Utf8StringVector &arguments)
|
||||
{
|
||||
d->clearArguments();
|
||||
d->arguments.resize(arguments.size());
|
||||
std::transform(arguments.cbegin(), arguments.cend(), d->arguments.begin(), strdup);
|
||||
d->arguments = arguments;
|
||||
updateLastChangeTimePoint();
|
||||
}
|
||||
|
||||
const std::vector<const char*> &ProjectPart::arguments() const
|
||||
const Utf8StringVector ProjectPart::arguments() const
|
||||
{
|
||||
return d->arguments;
|
||||
}
|
||||
|
||||
int ProjectPart::argumentCount() const
|
||||
{
|
||||
return d->arguments.size();
|
||||
}
|
||||
|
||||
const char * const *ProjectPart::cxArguments() const
|
||||
{
|
||||
return arguments().data();
|
||||
}
|
||||
|
||||
const time_point &ProjectPart::lastChangeTimePoint() const
|
||||
{
|
||||
return d->lastChangeTimePoint;
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class Utf8StringVector;
|
||||
|
||||
@@ -57,14 +56,10 @@ public:
|
||||
|
||||
void clear();
|
||||
|
||||
const Utf8String &projectPartId() const;
|
||||
Utf8String projectPartId() const;
|
||||
|
||||
void setArguments(const Utf8StringVector &arguments_);
|
||||
|
||||
const std::vector<const char*> &arguments() const;
|
||||
|
||||
int argumentCount() const;
|
||||
const char *const *cxArguments() const;
|
||||
const Utf8StringVector arguments() const;
|
||||
|
||||
const time_point &lastChangeTimePoint() const;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <skippedsourceranges.h>
|
||||
#include <translationunitalreadyexistsexception.h>
|
||||
#include <translationunitdoesnotexistexception.h>
|
||||
#include <unsavedfiles.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
@@ -142,7 +143,7 @@ const std::vector<TranslationUnit> &TranslationUnits::translationUnits() const
|
||||
return translationUnits_;
|
||||
}
|
||||
|
||||
UnsavedFiles &TranslationUnits::unsavedFiles() const
|
||||
UnsavedFiles TranslationUnits::unsavedFiles() const
|
||||
{
|
||||
return unsavedFiles_;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
|
||||
const std::vector<TranslationUnit> &translationUnits() const;
|
||||
|
||||
UnsavedFiles &unsavedFiles() const;
|
||||
UnsavedFiles unsavedFiles() const;
|
||||
|
||||
void addWatchedFiles(QSet<Utf8String> &filePaths);
|
||||
|
||||
|
||||
@@ -26,64 +26,42 @@
|
||||
#include "unsavedfile.h"
|
||||
|
||||
#include "clangfilepath.h"
|
||||
#include "utf8string.h"
|
||||
#include "utf8positionfromlinecolumn.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <ostream>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
UnsavedFile::UnsavedFile()
|
||||
: cxUnsavedFile(CXUnsavedFile{nullptr, nullptr, 0UL})
|
||||
{
|
||||
}
|
||||
|
||||
UnsavedFile::UnsavedFile(const Utf8String &filePath, const Utf8String &fileContent)
|
||||
UnsavedFile::UnsavedFile(const Utf8String &filePath,
|
||||
const Utf8String &fileContent)
|
||||
: m_filePath(filePath)
|
||||
, m_nativeFilePath(FilePath::toNativeSeparators(filePath))
|
||||
, m_fileContent(fileContent)
|
||||
{
|
||||
const Utf8String nativeFilePath = FilePath::toNativeSeparators(filePath);
|
||||
|
||||
char *cxUnsavedFilePath = new char[nativeFilePath.byteSize() + 1];
|
||||
char *cxUnsavedFileContent = new char[fileContent.byteSize() + 1];
|
||||
|
||||
std::memcpy(cxUnsavedFilePath, nativeFilePath.constData(), nativeFilePath.byteSize() + 1);
|
||||
std::memcpy(cxUnsavedFileContent, fileContent.constData(), fileContent.byteSize() + 1);
|
||||
|
||||
cxUnsavedFile = CXUnsavedFile{cxUnsavedFilePath,
|
||||
cxUnsavedFileContent,
|
||||
ulong(fileContent.byteSize())};
|
||||
}
|
||||
|
||||
UnsavedFile::UnsavedFile(UnsavedFile &&other) Q_DECL_NOEXCEPT
|
||||
: cxUnsavedFile(other.cxUnsavedFile)
|
||||
Utf8String UnsavedFile::nativeFilePath() const
|
||||
{
|
||||
other.cxUnsavedFile = { nullptr, nullptr, 0UL };
|
||||
}
|
||||
|
||||
UnsavedFile &UnsavedFile::operator=(UnsavedFile &&other) Q_DECL_NOEXCEPT
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(this->cxUnsavedFile, other.cxUnsavedFile);
|
||||
|
||||
return *this;
|
||||
return m_nativeFilePath;
|
||||
}
|
||||
|
||||
Utf8String UnsavedFile::filePath() const
|
||||
{
|
||||
const Utf8String nativeFilePathAsUtf8String = Utf8String::fromUtf8(nativeFilePath());
|
||||
|
||||
return FilePath::fromNativeSeparators(nativeFilePathAsUtf8String);
|
||||
return m_filePath;
|
||||
}
|
||||
|
||||
const char *UnsavedFile::nativeFilePath() const
|
||||
Utf8String UnsavedFile::fileContent() const
|
||||
{
|
||||
return cxUnsavedFile.Filename;
|
||||
return m_fileContent;
|
||||
}
|
||||
|
||||
uint UnsavedFile::toUtf8Position(uint line, uint column, bool *ok) const
|
||||
{
|
||||
Utf8PositionFromLineColumn converter(cxUnsavedFile.Contents);
|
||||
Utf8PositionFromLineColumn converter(m_fileContent.constData());
|
||||
if (converter.find(line, column)) {
|
||||
*ok = true;
|
||||
return converter.position();
|
||||
@@ -103,51 +81,28 @@ bool UnsavedFile::hasCharacterAt(uint line, uint column, char character) const
|
||||
|
||||
bool UnsavedFile::hasCharacterAt(uint position, char character) const
|
||||
{
|
||||
if (position < cxUnsavedFile.Length)
|
||||
return cxUnsavedFile.Contents[position] == character;
|
||||
if (position < uint(m_fileContent.byteSize()))
|
||||
return m_fileContent.constData()[position] == character;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UnsavedFile::replaceAt(uint position, uint length, const Utf8String &replacement)
|
||||
{
|
||||
if (position < cxUnsavedFile.Length) {
|
||||
Utf8String modifiedContent(cxUnsavedFile.Contents, cxUnsavedFile.Length);
|
||||
modifiedContent.replace(int(position), int(length), replacement);
|
||||
|
||||
*this = UnsavedFile(Utf8String::fromUtf8(nativeFilePath()), modifiedContent);
|
||||
|
||||
if (position < uint(m_fileContent.byteSize())) {
|
||||
m_fileContent.replace(int(position), int(length), replacement);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CXUnsavedFile *UnsavedFile::data()
|
||||
{
|
||||
return &cxUnsavedFile;
|
||||
}
|
||||
|
||||
UnsavedFile::~UnsavedFile()
|
||||
{
|
||||
delete [] cxUnsavedFile.Contents;
|
||||
delete [] cxUnsavedFile.Filename;
|
||||
cxUnsavedFile.Contents = nullptr;
|
||||
cxUnsavedFile.Filename = nullptr;
|
||||
cxUnsavedFile.Length = 0;
|
||||
}
|
||||
|
||||
static const char *printCString(const char *str)
|
||||
{
|
||||
return str ? str : "nullptr";
|
||||
}
|
||||
|
||||
void PrintTo(const UnsavedFile &unsavedFile, std::ostream *os)
|
||||
{
|
||||
*os << "UnsavedFile("
|
||||
<< printCString(unsavedFile.cxUnsavedFile.Filename) << ", "
|
||||
<< printCString(unsavedFile.cxUnsavedFile.Contents) << ", "
|
||||
<< unsavedFile.cxUnsavedFile.Length << ")";
|
||||
<< unsavedFile.m_filePath.constData() << ", "
|
||||
<< unsavedFile.m_fileContent.constData() << ", "
|
||||
<< unsavedFile.m_fileContent.byteSize() << ")";
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -25,13 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
class Utf8String;
|
||||
#include "utf8string.h"
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
@@ -44,27 +38,23 @@ public:
|
||||
|
||||
UnsavedFile();
|
||||
UnsavedFile(const Utf8String &filePath, const Utf8String &fileContent);
|
||||
~UnsavedFile();
|
||||
|
||||
UnsavedFile(const UnsavedFile &other) = delete;
|
||||
bool operator=(const UnsavedFile &other) = delete;
|
||||
|
||||
UnsavedFile(UnsavedFile &&other) Q_DECL_NOEXCEPT;
|
||||
UnsavedFile &operator=(UnsavedFile &&other) Q_DECL_NOEXCEPT;
|
||||
|
||||
Utf8String filePath() const;
|
||||
const char *nativeFilePath() const;
|
||||
Utf8String nativeFilePath() const;
|
||||
Utf8String fileContent() const;
|
||||
|
||||
// 1-based line and column
|
||||
uint toUtf8Position(uint line, uint column, bool *ok) const;
|
||||
bool hasCharacterAt(uint line, uint column, char character) const;
|
||||
|
||||
// 0-based position
|
||||
bool hasCharacterAt(uint position, char character) const;
|
||||
bool replaceAt(uint position, uint length, const Utf8String &replacement);
|
||||
|
||||
CXUnsavedFile *data();
|
||||
|
||||
public: // for tests
|
||||
CXUnsavedFile cxUnsavedFile;
|
||||
private:
|
||||
Utf8String m_filePath;
|
||||
Utf8String m_nativeFilePath;
|
||||
Utf8String m_fileContent;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -25,20 +25,23 @@
|
||||
|
||||
#include "unsavedfiles.h"
|
||||
|
||||
#include "clangunsavedfilesshallowarguments.h"
|
||||
#include "unsavedfile.h"
|
||||
|
||||
#include <QSharedData>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class UnsavedFilesData
|
||||
class UnsavedFilesData : public QSharedData
|
||||
{
|
||||
public:
|
||||
UnsavedFilesData();
|
||||
|
||||
public:
|
||||
time_point lastChangeTimePoint;
|
||||
std::vector<UnsavedFile> unsavedFiles;
|
||||
QVector<UnsavedFile> unsavedFiles;
|
||||
};
|
||||
|
||||
UnsavedFilesData::UnsavedFilesData()
|
||||
@@ -47,24 +50,22 @@ UnsavedFilesData::UnsavedFilesData()
|
||||
}
|
||||
|
||||
UnsavedFiles::UnsavedFiles()
|
||||
: d(std::make_shared<UnsavedFilesData>())
|
||||
: d(new UnsavedFilesData)
|
||||
{
|
||||
}
|
||||
|
||||
UnsavedFiles::~UnsavedFiles() = default;
|
||||
|
||||
UnsavedFiles::UnsavedFiles(const UnsavedFiles &) = default;
|
||||
UnsavedFiles &UnsavedFiles::operator=(const UnsavedFiles &) = default;
|
||||
|
||||
UnsavedFiles::UnsavedFiles(UnsavedFiles &&other)
|
||||
: d(std::move(other.d))
|
||||
UnsavedFiles::~UnsavedFiles()
|
||||
{
|
||||
}
|
||||
|
||||
UnsavedFiles &UnsavedFiles::operator=(UnsavedFiles &&other)
|
||||
UnsavedFiles::UnsavedFiles(const UnsavedFiles &other)
|
||||
: d(other.d)
|
||||
{
|
||||
d = std::move(other.d);
|
||||
}
|
||||
|
||||
UnsavedFiles &UnsavedFiles::operator=(const UnsavedFiles &other)
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -105,12 +106,17 @@ uint UnsavedFiles::count() const
|
||||
return uint(d->unsavedFiles.size());
|
||||
}
|
||||
|
||||
CXUnsavedFile *UnsavedFiles::cxUnsavedFiles() const
|
||||
const UnsavedFile &UnsavedFiles::at(int index) const
|
||||
{
|
||||
return d->unsavedFiles.data()->data();
|
||||
return d->unsavedFiles.at(index);
|
||||
}
|
||||
|
||||
const time_point &UnsavedFiles::lastChangeTimePoint() const
|
||||
UnsavedFilesShallowArguments UnsavedFiles::shallowArguments() const
|
||||
{
|
||||
return UnsavedFilesShallowArguments(*this);
|
||||
}
|
||||
|
||||
const time_point UnsavedFiles::lastChangeTimePoint() const
|
||||
{
|
||||
return d->lastChangeTimePoint;
|
||||
}
|
||||
@@ -141,7 +147,7 @@ void UnsavedFiles::addOrUpdateUnsavedFile(const FileContainer &fileContainer)
|
||||
|
||||
auto unsavedFileIterator = std::find_if(d->unsavedFiles.begin(), d->unsavedFiles.end(), isSameFile);
|
||||
if (unsavedFileIterator == d->unsavedFiles.end())
|
||||
d->unsavedFiles.emplace_back(filePath, fileContent);
|
||||
d->unsavedFiles.append(UnsavedFile(filePath, fileContent));
|
||||
else
|
||||
*unsavedFileIterator = UnsavedFile(filePath, fileContent);
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
#include <filecontainer.h>
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <QVector>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
@@ -40,29 +40,28 @@ using time_point = std::chrono::steady_clock::time_point;
|
||||
|
||||
class UnsavedFile;
|
||||
class UnsavedFilesData;
|
||||
class UnsavedFilesShallowArguments;
|
||||
|
||||
class UnsavedFiles
|
||||
{
|
||||
friend class UnsavedFilesData;
|
||||
public:
|
||||
UnsavedFiles();
|
||||
~UnsavedFiles();
|
||||
|
||||
UnsavedFiles(const UnsavedFiles &unsavedFiles);
|
||||
UnsavedFiles &operator=(const UnsavedFiles &unsavedFiles);
|
||||
|
||||
UnsavedFiles(UnsavedFiles &&unsavedFiles);
|
||||
UnsavedFiles &operator=(UnsavedFiles &&unsavedFiles);
|
||||
UnsavedFiles(const UnsavedFiles &other);
|
||||
UnsavedFiles &operator=(const UnsavedFiles &other);
|
||||
|
||||
void createOrUpdate(const QVector<FileContainer> &fileContainers);
|
||||
void remove(const QVector<FileContainer> &fileContainers);
|
||||
|
||||
uint count() const;
|
||||
const UnsavedFile &at(int index) const;
|
||||
|
||||
UnsavedFile &unsavedFile(const Utf8String &filePath);
|
||||
|
||||
uint count() const;
|
||||
CXUnsavedFile *cxUnsavedFiles() const;
|
||||
UnsavedFilesShallowArguments shallowArguments() const;
|
||||
|
||||
const time_point &lastChangeTimePoint() const;
|
||||
const time_point lastChangeTimePoint() const;
|
||||
|
||||
private:
|
||||
void updateUnsavedFileWithFileContainer(const FileContainer &fileContainer);
|
||||
@@ -71,7 +70,7 @@ private:
|
||||
void updateLastChangeTimePoint();
|
||||
|
||||
private:
|
||||
mutable std::shared_ptr<UnsavedFilesData> d;
|
||||
QSharedDataPointer<UnsavedFilesData> d;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <projectpart.h>
|
||||
#include <projects.h>
|
||||
#include <clangtranslationunit.h>
|
||||
#include <clangunsavedfilesshallowarguments.h>
|
||||
#include <translationunits.h>
|
||||
#include <unsavedfiles.h>
|
||||
#include <utf8stringvector.h>
|
||||
@@ -49,6 +50,7 @@ using ClangBackEnd::FilePath;
|
||||
using ClangBackEnd::TranslationUnit;
|
||||
using ClangBackEnd::CodeCompletion;
|
||||
using ClangBackEnd::UnsavedFiles;
|
||||
using ClangBackEnd::UnsavedFilesShallowArguments;
|
||||
using ClangBackEnd::CodeCompletionChunk;
|
||||
using ClangBackEnd::CodeCompletionChunks;
|
||||
|
||||
@@ -139,21 +141,13 @@ const ClangBackEnd::FileContainer unsavedDataFileContainer(const char *filePath,
|
||||
true);
|
||||
}
|
||||
|
||||
ClangCodeCompleteResults getResults(const TranslationUnit &translationUnit, uint line, uint column = 1)
|
||||
{
|
||||
Utf8String nativeFilePath = FilePath::toNativeSeparators(translationUnit.filePath());
|
||||
|
||||
return ClangCodeCompleteResults(clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
|
||||
nativeFilePath.constData(),
|
||||
line,
|
||||
column,
|
||||
translationUnit.cxUnsavedFiles(),
|
||||
translationUnit.unsavedFilesCount(),
|
||||
CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns));
|
||||
}
|
||||
|
||||
class CodeCompletionsExtractor : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
ClangCodeCompleteResults getResults(const TranslationUnit &translationUnit,
|
||||
uint line,
|
||||
uint column = 1);
|
||||
|
||||
protected:
|
||||
ClangBackEnd::ProjectPart project{Utf8StringLiteral("/path/to/projectfile")};
|
||||
ClangBackEnd::ProjectParts projects;
|
||||
@@ -686,5 +680,18 @@ TEST_F(CodeCompletionsExtractor, BriefComment)
|
||||
ASSERT_THAT(extractor, HasBriefComment(Utf8StringLiteral("BriefComment"), Utf8StringLiteral("A brief comment")));
|
||||
}
|
||||
|
||||
ClangCodeCompleteResults CodeCompletionsExtractor::getResults(const TranslationUnit &translationUnit, uint line, uint column)
|
||||
{
|
||||
const Utf8String nativeFilePath = FilePath::toNativeSeparators(translationUnit.filePath());
|
||||
UnsavedFilesShallowArguments unsaved = unsavedFiles.shallowArguments();
|
||||
|
||||
return ClangCodeCompleteResults(clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
|
||||
nativeFilePath.constData(),
|
||||
line,
|
||||
column,
|
||||
unsaved.data(),
|
||||
unsaved.count(),
|
||||
CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ void CodeCompleter::SetUp()
|
||||
projects.createOrUpdate({projectPart});
|
||||
translationUnits.create({mainFileContainer});
|
||||
translationUnit = translationUnits.translationUnit(mainFileContainer);
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit);
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
copyTargetHeaderToTemporaryIncludeDirecory();
|
||||
|
||||
@@ -224,6 +224,7 @@ TEST_F(CodeCompleter, FunctionInUnsavedFile)
|
||||
{
|
||||
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
|
||||
translationUnits.update({unsavedMainFileContainer});
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
ASSERT_THAT(completer.complete(27, 1),
|
||||
AllOf(Contains(IsCodeCompletion(Utf8StringLiteral("FunctionWithArguments"),
|
||||
@@ -242,6 +243,7 @@ TEST_F(CodeCompleter, VariableInUnsavedFile)
|
||||
{
|
||||
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
|
||||
translationUnits.update({unsavedMainFileContainer});
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
ASSERT_THAT(completer.complete(27, 1),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("VariableInUnsavedFile"),
|
||||
@@ -252,6 +254,7 @@ TEST_F(CodeCompleter, GlobalVariableInUnsavedFile)
|
||||
{
|
||||
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
|
||||
translationUnits.update({unsavedMainFileContainer});
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
ASSERT_THAT(completer.complete(27, 1),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("GlobalVariableInUnsavedFile"),
|
||||
@@ -262,6 +265,7 @@ TEST_F(CodeCompleter, Macro)
|
||||
{
|
||||
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
|
||||
translationUnits.update({unsavedMainFileContainer});
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
ASSERT_THAT(completer.complete(27, 1),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("Macro"),
|
||||
@@ -286,6 +290,7 @@ TEST_F(CodeCompleter, FunctionInUnsavedIncludedHeader)
|
||||
{
|
||||
unsavedFiles.createOrUpdate({unsavedTargetHeaderFileContainer});
|
||||
translationUnits.create({unsavedTargetHeaderFileContainer});
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
ASSERT_THAT(completer.complete(27, 1),
|
||||
Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeaderUnsaved"),
|
||||
@@ -305,6 +310,7 @@ TEST_F(CodeCompleter, DISABLED_FunctionInChangedIncludedHeaderWithUnsavedContent
|
||||
{
|
||||
unsavedFiles.createOrUpdate({unsavedMainFileContainer});
|
||||
translationUnits.update({unsavedMainFileContainer});
|
||||
completer = ClangBackEnd::CodeCompleter(translationUnit, unsavedFiles);
|
||||
|
||||
copyChangedTargetHeaderToTemporaryIncludeDirecory();
|
||||
|
||||
@@ -342,11 +348,14 @@ TEST_F(CodeCompleter, DotToArrowCompletionForPointer)
|
||||
TEST_F(CodeCompleter, DotToArrowCompletionForPointerInOutdatedTranslationUnit)
|
||||
{
|
||||
auto fileContainerBeforeTyping = dotArrowCorrectionForPointerFileContainerBeforeTyping;
|
||||
auto myCompleter = setupCompleter(fileContainerBeforeTyping);
|
||||
translationUnits.create({fileContainerBeforeTyping});
|
||||
unsavedFiles.createOrUpdate({fileContainerBeforeTyping});
|
||||
auto translationUnit = translationUnits.translationUnit(fileContainerBeforeTyping.filePath(),
|
||||
fileContainerBeforeTyping.projectPartId());
|
||||
translationUnit.cxTranslationUnit(); // Parse
|
||||
unsavedFiles.createOrUpdate({dotArrowCorrectionForPointerFileContainerAfterTyping});
|
||||
ClangBackEnd::CodeCompleter myCompleter(translationUnits.translationUnit(dotArrowCorrectionForPointerFileContainerAfterTyping),
|
||||
unsavedFiles);
|
||||
|
||||
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 9);
|
||||
|
||||
@@ -437,7 +446,8 @@ ClangBackEnd::CodeCompleter CodeCompleter::setupCompleter(
|
||||
translationUnits.create({fileContainer});
|
||||
unsavedFiles.createOrUpdate({fileContainer});
|
||||
|
||||
return ClangBackEnd::CodeCompleter(translationUnits.translationUnit(fileContainer));
|
||||
return ClangBackEnd::CodeCompleter(translationUnits.translationUnit(fileContainer),
|
||||
unsavedFiles);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include <thread>
|
||||
|
||||
using testing::ElementsAre;
|
||||
using testing::StrEq;
|
||||
using testing::Pointwise;
|
||||
using testing::Contains;
|
||||
using testing::Gt;
|
||||
@@ -61,7 +60,7 @@ TEST(ProjectPart, CreateProjectPartWithProjectPartContainer)
|
||||
ClangBackEnd::ProjectPart project(projectContainer);
|
||||
|
||||
ASSERT_THAT(project.projectPartId(), Utf8StringLiteral("pathToProjectPart.pro"));
|
||||
ASSERT_THAT(project.arguments(), Contains(StrEq("-O")));
|
||||
ASSERT_THAT(project.arguments(), Contains(Utf8StringLiteral("-O")));
|
||||
}
|
||||
|
||||
TEST(ProjectPart, SetArguments)
|
||||
@@ -70,7 +69,7 @@ TEST(ProjectPart, SetArguments)
|
||||
|
||||
project.setArguments(Utf8StringVector({Utf8StringLiteral("-O"), Utf8StringLiteral("-fast")}));
|
||||
|
||||
ASSERT_THAT(project.arguments(), ElementsAre(StrEq("-O"), StrEq("-fast")));
|
||||
ASSERT_THAT(project.arguments(), ElementsAre(Utf8StringLiteral("-O"), Utf8StringLiteral("-fast")));
|
||||
}
|
||||
|
||||
TEST(ProjectPart, ArgumentCount)
|
||||
@@ -79,7 +78,7 @@ TEST(ProjectPart, ArgumentCount)
|
||||
|
||||
project.setArguments(Utf8StringVector({Utf8StringLiteral("-O"), Utf8StringLiteral("-fast")}));
|
||||
|
||||
ASSERT_THAT(project.argumentCount(), 2);
|
||||
ASSERT_THAT(project.arguments().count(), 2);
|
||||
}
|
||||
|
||||
TEST(ProjectPart, TimeStampIsUpdatedAsArgumentChanged)
|
||||
@@ -109,7 +108,7 @@ TEST(ProjectPart, AddProjectParts)
|
||||
projects.createOrUpdate({projectContainer});
|
||||
|
||||
ASSERT_THAT(projects.project(projectContainer.projectPartId()), ClangBackEnd::ProjectPart(projectContainer));
|
||||
ASSERT_THAT(projects.project(projectContainer.projectPartId()).arguments(), ElementsAre(StrEq("-O")));
|
||||
ASSERT_THAT(projects.project(projectContainer.projectPartId()).arguments(), ElementsAre(Utf8StringLiteral("-O")));
|
||||
}
|
||||
|
||||
TEST(ProjectPart, UpdateProjectParts)
|
||||
@@ -122,7 +121,7 @@ TEST(ProjectPart, UpdateProjectParts)
|
||||
projects.createOrUpdate({projectContainerWithNewArguments});
|
||||
|
||||
ASSERT_THAT(projects.project(projectContainer.projectPartId()), ClangBackEnd::ProjectPart(projectContainer));
|
||||
ASSERT_THAT(projects.project(projectContainer.projectPartId()).arguments(), ElementsAre(StrEq("-fast")));
|
||||
ASSERT_THAT(projects.project(projectContainer.projectPartId()).arguments(), ElementsAre(Utf8StringLiteral("-fast")));
|
||||
}
|
||||
|
||||
TEST(ProjectPart, ThrowExceptionForAccesingRemovedProjectParts)
|
||||
@@ -172,7 +171,7 @@ TEST(ProjectPart, ProjectPartIsClearedAfterRemove)
|
||||
projects.remove({projectContainer.projectPartId()});
|
||||
|
||||
ASSERT_THAT(project.projectPartId(), Utf8String());
|
||||
ASSERT_THAT(project.argumentCount(), 0);
|
||||
ASSERT_THAT(project.arguments().count(), 0);
|
||||
ASSERT_THAT(project.lastChangeTimePoint(), Gt(lastChangeTimePoint));
|
||||
}
|
||||
|
||||
|
||||
@@ -38,24 +38,27 @@ using ClangBackEnd::UnsavedFile;
|
||||
using ClangBackEnd::UnsavedFiles;
|
||||
using ClangBackEnd::FileContainer;
|
||||
|
||||
using ::testing::Eq;
|
||||
using ::testing::Gt;
|
||||
using ::testing::IsNull;
|
||||
using ::testing::Ne;
|
||||
using ::testing::NotNull;
|
||||
using ::testing::PrintToString;
|
||||
|
||||
namespace {
|
||||
|
||||
bool operator==(const ClangBackEnd::FileContainer &fileContainer, const CXUnsavedFile &cxUnsavedFile)
|
||||
bool operator==(const ClangBackEnd::FileContainer &fileContainer, const UnsavedFile &unsavedFile)
|
||||
{
|
||||
return fileContainer.filePath() == Utf8String::fromUtf8(cxUnsavedFile.Filename)
|
||||
&& fileContainer.unsavedFileContent() == Utf8String(cxUnsavedFile.Contents, cxUnsavedFile.Length);
|
||||
return fileContainer.filePath() == unsavedFile.filePath()
|
||||
&& fileContainer.unsavedFileContent() == unsavedFile.fileContent();
|
||||
}
|
||||
|
||||
bool fileContainersContainsItemMatchingToCxUnsavedFile(const QVector<FileContainer> &fileContainers, const CXUnsavedFile &cxUnsavedFile)
|
||||
bool fileContainersContainsItemMatchingToCxUnsavedFile(const QVector<FileContainer> &fileContainers, const UnsavedFile &unsavedFile)
|
||||
{
|
||||
for (const FileContainer &fileContainer : fileContainers)
|
||||
if (fileContainer == cxUnsavedFile)
|
||||
for (const FileContainer &fileContainer : fileContainers) {
|
||||
if (fileContainer == unsavedFile)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -69,8 +72,8 @@ MATCHER_P(HasUnsavedFiles, fileContainers, "")
|
||||
}
|
||||
|
||||
for (uint i = 0, to = unsavedFiles.count(); i < to; ++i) {
|
||||
CXUnsavedFile *cxUnsavedFile = unsavedFiles.cxUnsavedFiles() + i;
|
||||
if (!fileContainersContainsItemMatchingToCxUnsavedFile(fileContainers, *cxUnsavedFile))
|
||||
UnsavedFile unsavedFile = unsavedFiles.at(i);
|
||||
if (!fileContainersContainsItemMatchingToCxUnsavedFile(fileContainers, unsavedFile))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -83,11 +86,9 @@ MATCHER_P3(IsUnsavedFile, fileName, contents, contentsLength,
|
||||
+ ", contents " + PrintToString(contents)
|
||||
+ ", contents length " + PrintToString(contentsLength))
|
||||
{
|
||||
CXUnsavedFile unsavedFile = arg.cxUnsavedFile;
|
||||
|
||||
return fileName == unsavedFile.Filename
|
||||
&& contents == unsavedFile.Contents
|
||||
&& size_t(contentsLength) == unsavedFile.Length;
|
||||
return fileName == arg.filePath()
|
||||
&& contents == arg.fileContent()
|
||||
&& int(contentsLength) == arg.fileContent().byteSize();
|
||||
}
|
||||
|
||||
class UnsavedFiles : public ::testing::Test
|
||||
@@ -101,6 +102,19 @@ protected:
|
||||
Utf8String unsavedContent2{Utf8StringLiteral("bar")};
|
||||
};
|
||||
|
||||
TEST_F(UnsavedFiles, ModifiedCopyIsDifferent)
|
||||
{
|
||||
QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId, unsavedContent1, true)});
|
||||
unsavedFiles.createOrUpdate(fileContainers);
|
||||
|
||||
::UnsavedFiles copy = unsavedFiles;
|
||||
QVector<FileContainer> updatedFileContainers({FileContainer(filePath, projectPartId, unsavedContent2, true)});
|
||||
copy.createOrUpdate(updatedFileContainers);
|
||||
|
||||
ASSERT_THAT(copy.at(0).fileContent(), Ne(unsavedFiles.at(0).fileContent()));
|
||||
ASSERT_THAT(copy.lastChangeTimePoint(), Gt(unsavedFiles.lastChangeTimePoint()));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFiles, DoNothingForUpdateIfFileHasNoUnsavedContent)
|
||||
{
|
||||
QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId)});
|
||||
|
||||
@@ -47,11 +47,9 @@ MATCHER_P3(IsUnsavedFile, fileName, contents, contentsLength,
|
||||
+ ", contents " + PrintToString(contents)
|
||||
+ ", contents length " + PrintToString(contentsLength))
|
||||
{
|
||||
CXUnsavedFile unsavedFile = arg.cxUnsavedFile;
|
||||
|
||||
return fileName == unsavedFile.Filename
|
||||
&& contents == unsavedFile.Contents
|
||||
&& size_t(contentsLength) == unsavedFile.Length;
|
||||
return fileName == arg.filePath()
|
||||
&& contents == arg.fileContent()
|
||||
&& int(contentsLength) == arg.fileContent().byteSize();
|
||||
}
|
||||
|
||||
class UnsavedFile : public ::testing::Test
|
||||
@@ -78,56 +76,15 @@ TEST_F(UnsavedFile, Create)
|
||||
fileContent.byteSize()));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, Destruct)
|
||||
TEST_F(UnsavedFile, CopyConstruct)
|
||||
{
|
||||
auto *unsavedFile = new ::UnsavedFile(filePath, fileContent);
|
||||
unsavedFile->~UnsavedFile();
|
||||
::UnsavedFile copyFrom(filePath, fileContent);
|
||||
|
||||
ASSERT_THAT(*unsavedFile, IsUnsavedFile(nullptr, nullptr, 0UL));
|
||||
}
|
||||
::UnsavedFile copyTo = copyFrom;
|
||||
|
||||
TEST_F(UnsavedFile, ConstructMoveToIsValid)
|
||||
{
|
||||
::UnsavedFile movedFrom(filePath, fileContent);
|
||||
|
||||
::UnsavedFile movedTo = std::move(movedFrom);
|
||||
|
||||
ASSERT_THAT(movedTo, IsUnsavedFile(filePath,
|
||||
fileContent,
|
||||
fileContent.byteSize()));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, ConstructMoveFromIsNull)
|
||||
{
|
||||
::UnsavedFile movedFrom(filePath, fileContent);
|
||||
|
||||
::UnsavedFile movedTo = std::move(movedFrom);
|
||||
|
||||
ASSERT_THAT(movedFrom, IsUnsavedFile(nullptr, nullptr, 0UL));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, AssignMoveToIsValid)
|
||||
{
|
||||
::UnsavedFile movedFrom(filePath, fileContent);
|
||||
::UnsavedFile movedTo(otherFilePath, otherFileContent);
|
||||
|
||||
movedTo = std::move(movedFrom);
|
||||
|
||||
ASSERT_THAT(movedTo, IsUnsavedFile(filePath,
|
||||
fileContent,
|
||||
fileContent.byteSize()));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, AssignMoveFromIsSwapped)
|
||||
{
|
||||
::UnsavedFile movedFrom(filePath, fileContent);
|
||||
::UnsavedFile movedTo(otherFilePath, otherFileContent);
|
||||
|
||||
movedTo = std::move(movedFrom);
|
||||
|
||||
ASSERT_THAT(movedFrom, IsUnsavedFile(otherFilePath,
|
||||
otherFileContent,
|
||||
otherFileContent.byteSize()));
|
||||
ASSERT_THAT(copyTo, IsUnsavedFile(filePath,
|
||||
fileContent,
|
||||
fileContent.byteSize()));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, FilePath)
|
||||
@@ -208,6 +165,19 @@ TEST_F(UnsavedFile, HasNoCharacterForDefaultConstructedUnsavedFile)
|
||||
ASSERT_FALSE(unsavedFile.hasCharacterAt(0, 'x'));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, ReplacingInCopyDoesNotModifyOriginal)
|
||||
{
|
||||
const Utf8String originalContent = Utf8StringLiteral("foo");
|
||||
::UnsavedFile original(filePath, originalContent);
|
||||
::UnsavedFile copy = original;
|
||||
|
||||
const bool hasReplaced = copy.replaceAt(0, 3, aReplacement);
|
||||
|
||||
ASSERT_TRUE(hasReplaced);
|
||||
ASSERT_THAT(original, IsUnsavedFile(filePath, originalContent, originalContent.byteSize()));
|
||||
ASSERT_THAT(copy, IsUnsavedFile(filePath, aReplacement, aReplacement.byteSize()));
|
||||
}
|
||||
|
||||
TEST_F(UnsavedFile, HasNoCharacterForTooBigOffset)
|
||||
{
|
||||
::UnsavedFile unsavedFile(filePath, fileContent);
|
||||
|
||||
Reference in New Issue
Block a user