forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.9'
Change-Id: I0d3db14e583628b906d7fdeb800e004d98e52632
This commit is contained in:
@@ -833,6 +833,14 @@ class DumperBase:
|
|||||||
self.putType('int')
|
self.putType('int')
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
|
|
||||||
|
def putEnumItem(self, name, ival, typish):
|
||||||
|
buf = bytearray(struct.pack('i', ival))
|
||||||
|
val = self.Value(self)
|
||||||
|
val.ldata = bytes(buf)
|
||||||
|
val.type = self.createType(typish)
|
||||||
|
with SubItem(self, name):
|
||||||
|
self.putItem(val)
|
||||||
|
|
||||||
def putBoolItem(self, name, value):
|
def putBoolItem(self, name, value):
|
||||||
with SubItem(self, name):
|
with SubItem(self, name):
|
||||||
self.putValue(value)
|
self.putValue(value)
|
||||||
@@ -855,8 +863,7 @@ class DumperBase:
|
|||||||
self.putField('keyencoded', key.encoding)
|
self.putField('keyencoded', key.encoding)
|
||||||
self.putValue(value.value, value.encoding)
|
self.putValue(value.value, value.encoding)
|
||||||
|
|
||||||
def putEnumValue(self, value, vals):
|
def putEnumValue(self, ival, vals):
|
||||||
ival = value.integer()
|
|
||||||
nice = vals.get(ival, None)
|
nice = vals.get(ival, None)
|
||||||
display = ('%d' % ival) if nice is None else ('%s (%d)' % (nice, ival))
|
display = ('%d' % ival) if nice is None else ('%s (%d)' % (nice, ival))
|
||||||
self.putValue(display)
|
self.putValue(display)
|
||||||
|
@@ -194,7 +194,7 @@ def qdump_X_QModelIndex(d, value):
|
|||||||
#gdb.execute('call free($mi)')
|
#gdb.execute('call free($mi)')
|
||||||
|
|
||||||
def qdump__Qt__ItemDataRole(d, value):
|
def qdump__Qt__ItemDataRole(d, value):
|
||||||
d.putEnumValue(value, {
|
d.putEnumValue(value.integer(), {
|
||||||
0 : "Qt::DisplayRole",
|
0 : "Qt::DisplayRole",
|
||||||
1 : "Qt::DecorationRole",
|
1 : "Qt::DecorationRole",
|
||||||
2 : "Qt::EditRole",
|
2 : "Qt::EditRole",
|
||||||
@@ -1412,6 +1412,31 @@ def qdump__QSizeF(d, value):
|
|||||||
d.putPlainChildren(value)
|
d.putPlainChildren(value)
|
||||||
|
|
||||||
|
|
||||||
|
def qdump__QSizePolicy__Policy(d, value):
|
||||||
|
d.putEnumValue(value.integer(), {
|
||||||
|
0 : 'QSizePolicy::Fixed',
|
||||||
|
1 : 'QSizePolicy::GrowFlag',
|
||||||
|
2 : 'QSizePolicy::ExpandFlag',
|
||||||
|
3 : 'QSizePolicy::MinimumExpanding (GrowFlag|ExpandFlag)',
|
||||||
|
4 : 'QSizePolicy::ShrinkFlag',
|
||||||
|
5 : 'QSizePolicy::Preferred (GrowFlag|ShrinkFlag)',
|
||||||
|
7 : 'QSizePolicy::Expanding (GrowFlag|ShrinkFlag|ExpandFlag)',
|
||||||
|
8 : 'QSizePolicy::IgnoreFlag',
|
||||||
|
13 : 'QSizePolicy::Ignored (ShrinkFlag|GrowFlag|IgnoreFlag)',
|
||||||
|
})
|
||||||
|
|
||||||
|
def qdump__QSizePolicy(d, value):
|
||||||
|
bits = value.integer()
|
||||||
|
d.putEmptyValue(-99)
|
||||||
|
d.putNumChild(1)
|
||||||
|
if d.isExpanded():
|
||||||
|
with Children(d):
|
||||||
|
d.putIntItem('horStretch', (bits >> 0) & 0xff)
|
||||||
|
d.putIntItem('verStretch', (bits >> 8) & 0xff)
|
||||||
|
d.putEnumItem('horPolicy', (bits >> 16) & 0xf, "@QSizePolicy::Policy")
|
||||||
|
d.putEnumItem('verPolicy', (bits >> 20) & 0xf, "@QSizePolicy::Policy")
|
||||||
|
|
||||||
|
|
||||||
def qform__QStack():
|
def qform__QStack():
|
||||||
return arrayForms()
|
return arrayForms()
|
||||||
|
|
||||||
|
@@ -165,5 +165,27 @@ int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffe
|
|||||||
return utf8Offset;
|
return utf8Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset)
|
||||||
|
{
|
||||||
|
Utils::LineColumn lineColumn;
|
||||||
|
lineColumn.line = static_cast<int>(
|
||||||
|
std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n'))
|
||||||
|
+ 1;
|
||||||
|
const int startOfLineOffset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
|
||||||
|
lineColumn.column = QString::fromUtf8(
|
||||||
|
utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset))
|
||||||
|
.length()
|
||||||
|
+ 1;
|
||||||
|
return lineColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset)
|
||||||
|
{
|
||||||
|
const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1;
|
||||||
|
const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset);
|
||||||
|
return QString::fromUtf8(
|
||||||
|
utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset));
|
||||||
|
}
|
||||||
|
|
||||||
} // Text
|
} // Text
|
||||||
} // Utils
|
} // Utils
|
||||||
|
@@ -59,5 +59,9 @@ QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument,
|
|||||||
const QByteArray &buffer,
|
const QByteArray &buffer,
|
||||||
int line);
|
int line);
|
||||||
|
|
||||||
|
QTCREATOR_UTILS_EXPORT LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset);
|
||||||
|
QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer,
|
||||||
|
int currentUtf8Offset);
|
||||||
|
|
||||||
} // Text
|
} // Text
|
||||||
} // Utils
|
} // Utils
|
||||||
|
@@ -48,6 +48,7 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
ClangCurrentDocumentFilter::ClangCurrentDocumentFilter()
|
ClangCurrentDocumentFilter::ClangCurrentDocumentFilter()
|
||||||
{
|
{
|
||||||
@@ -108,7 +109,6 @@ QList<Core::LocatorFilterEntry> ClangCurrentDocumentFilter::matchesFor(
|
|||||||
if (!regexp.isValid())
|
if (!regexp.isValid())
|
||||||
return goodEntries;
|
return goodEntries;
|
||||||
|
|
||||||
using Internal::ClangEditorDocumentProcessor;
|
|
||||||
ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(m_currentPath);
|
ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(m_currentPath);
|
||||||
if (!processor)
|
if (!processor)
|
||||||
return goodEntries;
|
return goodEntries;
|
||||||
@@ -170,4 +170,5 @@ void ClangCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *newCurren
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
namespace Core { class IEditor; }
|
namespace Core { class IEditor; }
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class ClangCurrentDocumentFilter : public Core::ILocatorFilter
|
class ClangCurrentDocumentFilter : public Core::ILocatorFilter
|
||||||
{
|
{
|
||||||
@@ -53,4 +54,5 @@ private:
|
|||||||
QString m_currentPath;
|
QString m_currentPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
using namespace ClangCodeModel;
|
using namespace ClangCodeModel;
|
||||||
using Internal::ClangDiagnosticWidget;
|
using Internal::ClangDiagnosticWidget;
|
||||||
|
using Internal::ClangFixItOperation;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ void openEditorAt(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
|||||||
|
|
||||||
void applyFixit(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
void applyFixit(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
{
|
{
|
||||||
ClangCodeModel::ClangFixItOperation operation(Utf8String(), diagnostic.fixIts);
|
ClangFixItOperation operation(Utf8String(), diagnostic.fixIts);
|
||||||
|
|
||||||
operation.perform();
|
operation.perform();
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "clangeditordocumentparser.h"
|
#include "clangeditordocumentparser.h"
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath)
|
ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath)
|
||||||
: BaseEditorDocumentParser(filePath)
|
: BaseEditorDocumentParser(filePath)
|
||||||
@@ -46,4 +47,5 @@ void ClangEditorDocumentParser::updateImpl(const QFutureInterface<void> &,
|
|||||||
setState(state_);
|
setState(state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include <cpptools/baseeditordocumentparser.h>
|
#include <cpptools/baseeditordocumentparser.h>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser
|
class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser
|
||||||
{
|
{
|
||||||
@@ -41,4 +42,5 @@ private:
|
|||||||
const UpdateParams &updateParams) override;
|
const UpdateParams &updateParams) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
using FileToFixits = QMap<QString, QVector<ClangBackEnd::FixItContainer>>;
|
using FileToFixits = QMap<QString, QVector<ClangBackEnd::FixItContainer>>;
|
||||||
using FileToFixitsIterator = QMapIterator<QString, QVector<ClangBackEnd::FixItContainer>>;
|
using FileToFixitsIterator = QMapIterator<QString, QVector<ClangBackEnd::FixItContainer>>;
|
||||||
@@ -50,7 +51,7 @@ int ClangFixItOperation::priority() const
|
|||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ClangCodeModel::ClangFixItOperation::description() const
|
QString ClangFixItOperation::description() const
|
||||||
{
|
{
|
||||||
return QStringLiteral("Apply Fix: ") + fixItText.toString();
|
return QStringLiteral("Apply Fix: ") + fixItText.toString();
|
||||||
}
|
}
|
||||||
@@ -120,5 +121,5 @@ Utils::ChangeSet ClangFixItOperation::toChangeSet(
|
|||||||
return changeSet;
|
return changeSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|
||||||
|
@@ -34,13 +34,13 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
|
||||||
namespace TextEditor
|
namespace TextEditor {
|
||||||
{
|
|
||||||
class RefactoringChanges;
|
class RefactoringChanges;
|
||||||
class RefactoringFile;
|
class RefactoringFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class ClangFixItOperation : public TextEditor::QuickFixOperation
|
class ClangFixItOperation : public TextEditor::QuickFixOperation
|
||||||
{
|
{
|
||||||
@@ -67,4 +67,5 @@ private:
|
|||||||
QVector<ClangBackEnd::FixItContainer> fixItContainers;
|
QVector<ClangBackEnd::FixItContainer> fixItContainers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -72,6 +72,7 @@ bool hasFixItAt(const QVector<ClangBackEnd::FixItContainer> &fixits,
|
|||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
ClangFixItOperationsExtractor::ClangFixItOperationsExtractor(
|
ClangFixItOperationsExtractor::ClangFixItOperationsExtractor(
|
||||||
const QVector<DiagnosticContainer> &diagnosticContainers)
|
const QVector<DiagnosticContainer> &diagnosticContainers)
|
||||||
@@ -114,4 +115,5 @@ void ClangFixItOperationsExtractor::extractFromDiagnostic(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <clangsupport/diagnosticcontainer.h>
|
#include <clangsupport/diagnosticcontainer.h>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class ClangFixItOperationsExtractor
|
class ClangFixItOperationsExtractor
|
||||||
{
|
{
|
||||||
@@ -50,4 +51,5 @@ private:
|
|||||||
TextEditor::QuickFixOperations operations;
|
TextEditor::QuickFixOperations operations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -144,6 +144,7 @@ TextEditor::HighlightingResult toHighlightingResult(
|
|||||||
} // anonymous
|
} // anonymous
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
HighlightingResultReporter::HighlightingResultReporter(
|
HighlightingResultReporter::HighlightingResultReporter(
|
||||||
const QVector<ClangBackEnd::TokenInfoContainer> &tokenInfos)
|
const QVector<ClangBackEnd::TokenInfoContainer> &tokenInfos)
|
||||||
@@ -219,4 +220,5 @@ QFuture<TextEditor::HighlightingResult> HighlightingResultReporter::start()
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#include <clangsupport/tokeninfocontainer.h>
|
#include <clangsupport/tokeninfocontainer.h>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class HighlightingResultReporter:
|
class HighlightingResultReporter:
|
||||||
public QObject,
|
public QObject,
|
||||||
@@ -67,4 +68,5 @@ private:
|
|||||||
unsigned m_flushLine = 0;
|
unsigned m_flushLine = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <cplusplus/Token.h>
|
#include <cplusplus/Token.h>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
bool ClangPreprocessorAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const
|
bool ClangPreprocessorAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const
|
||||||
{
|
{
|
||||||
@@ -156,4 +157,5 @@ bool ClangPreprocessorAssistProposalItem::isInclude() const
|
|||||||
|| m_completionOperator == CPlusPlus::T_ANGLE_STRING_LITERAL;
|
|| m_completionOperator == CPlusPlus::T_ANGLE_STRING_LITERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class ClangPreprocessorAssistProposalItem final : public TextEditor::AssistProposalItemInterface
|
class ClangPreprocessorAssistProposalItem final : public TextEditor::AssistProposalItemInterface
|
||||||
{
|
{
|
||||||
@@ -68,4 +69,5 @@ private:
|
|||||||
mutable QChar m_typedCharacter;
|
mutable QChar m_typedCharacter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -30,12 +30,13 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
|
void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
|
||||||
CppTools::ProjectPart *,
|
CppTools::ProjectPart *,
|
||||||
RenameCallback &&renameSymbolsCallback)
|
RenameCallback &&renameSymbolsCallback)
|
||||||
{
|
{
|
||||||
Internal::ClangEditorDocumentProcessor *processor = Internal::ClangEditorDocumentProcessor::get(
|
ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(
|
||||||
data.filePath().toString());
|
data.filePath().toString());
|
||||||
const int startRevision = data.cursor().document()->revision();
|
const int startRevision = data.cursor().document()->revision();
|
||||||
|
|
||||||
@@ -79,4 +80,5 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
|
|||||||
m_watcher->setFuture(cursorFuture);
|
m_watcher->setFuture(cursorFuture);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Internal
|
||||||
|
} // namespace ClangCodeModel
|
||||||
|
@@ -36,6 +36,7 @@ class RefactoringServerInterface;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class RefactoringEngine : public CppTools::RefactoringEngineInterface
|
class RefactoringEngine : public CppTools::RefactoringEngineInterface
|
||||||
{
|
{
|
||||||
@@ -60,4 +61,5 @@ private:
|
|||||||
std::unique_ptr<FutureCursorWatcher> m_watcher;
|
std::unique_ptr<FutureCursorWatcher> m_watcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangRefactoring
|
} // namespace ClangRefactoring
|
||||||
|
@@ -48,9 +48,12 @@
|
|||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
using namespace CppTools;
|
||||||
|
using namespace ClangCodeModel::Internal;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -75,9 +78,6 @@ static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity)
|
|||||||
|
|
||||||
ProjectExplorer::Project *projectForCurrentEditor()
|
ProjectExplorer::Project *projectForCurrentEditor()
|
||||||
{
|
{
|
||||||
using namespace CppTools;
|
|
||||||
using namespace ClangCodeModel::Internal;
|
|
||||||
|
|
||||||
const QString filePath = Utils::currentCppEditorDocumentFilePath();
|
const QString filePath = Utils::currentCppEditorDocumentFilePath();
|
||||||
if (filePath.isEmpty())
|
if (filePath.isEmpty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -90,35 +90,80 @@ ProjectExplorer::Project *projectForCurrentEditor()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disableDiagnosticInConfig(CppTools::ClangDiagnosticConfig &config,
|
enum class DiagnosticType { Clang, Tidy, Clazy };
|
||||||
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
DiagnosticType diagnosticType(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
|
||||||
{
|
{
|
||||||
// Clang check
|
if (!diagnostic.disableOption.isEmpty())
|
||||||
if (!diagnostic.disableOption.isEmpty()) {
|
return DiagnosticType::Clang;
|
||||||
config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption));
|
|
||||||
return;
|
const Utils::DiagnosticTextInfo textInfo(diagnostic.text);
|
||||||
|
if (Utils::DiagnosticTextInfo::isClazyOption(textInfo.option()))
|
||||||
|
return DiagnosticType::Clazy;
|
||||||
|
return DiagnosticType::Tidy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clazy check
|
void disableDiagnosticInConfig(ClangDiagnosticConfig &config,
|
||||||
|
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
using namespace ClangCodeModel::Utils;
|
using namespace ClangCodeModel::Utils;
|
||||||
DiagnosticTextInfo textInfo(diagnostic.text);
|
|
||||||
if (DiagnosticTextInfo::isClazyOption(textInfo.option())) {
|
switch (diagnosticType(diagnostic)) {
|
||||||
|
case DiagnosticType::Clang:
|
||||||
|
config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption));
|
||||||
|
break;
|
||||||
|
case DiagnosticType::Tidy:
|
||||||
|
config.setClangTidyChecks(config.clangTidyChecks() + QString(",-")
|
||||||
|
+ DiagnosticTextInfo(diagnostic.text).option());
|
||||||
|
break;
|
||||||
|
case DiagnosticType::Clazy: {
|
||||||
|
const DiagnosticTextInfo textInfo(diagnostic.text);
|
||||||
const QString checkName = DiagnosticTextInfo::clazyCheckName(textInfo.option());
|
const QString checkName = DiagnosticTextInfo::clazyCheckName(textInfo.option());
|
||||||
QStringList newChecks = config.clazyChecks().split(',');
|
QStringList newChecks = config.clazyChecks().split(',');
|
||||||
newChecks.removeOne(checkName);
|
newChecks.removeOne(checkName);
|
||||||
config.setClazyChecks(newChecks.join(','));
|
config.setClazyChecks(newChecks.join(','));
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tidy check
|
ClangDiagnosticConfig diagnosticConfig(ClangProjectSettings &projectSettings,
|
||||||
config.setClangTidyChecks(config.clangTidyChecks() + QString(",-") + textInfo.option());
|
CppCodeModelSettings &globalSettings)
|
||||||
|
{
|
||||||
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
||||||
|
QTC_ASSERT(project, return {});
|
||||||
|
|
||||||
|
// Get config id
|
||||||
|
Core::Id currentConfigId = projectSettings.warningConfigId();
|
||||||
|
if (projectSettings.useGlobalConfig())
|
||||||
|
currentConfigId = globalSettings.clangDiagnosticConfigId();
|
||||||
|
|
||||||
|
// Get config
|
||||||
|
ClangDiagnosticConfigsModel configsModel(globalSettings.clangCustomDiagnosticConfigs());
|
||||||
|
QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return {});
|
||||||
|
return configsModel.configWithId(currentConfigId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDiagnosticConfigChangable(ProjectExplorer::Project *project,
|
||||||
|
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
|
{
|
||||||
|
if (!project)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ClangProjectSettings &projectSettings = ClangModelManagerSupport::instance()->projectSettings(
|
||||||
|
project);
|
||||||
|
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
|
||||||
|
const ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings);
|
||||||
|
|
||||||
|
if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::File
|
||||||
|
&& diagnosticType(diagnostic) == DiagnosticType::Tidy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||||
{
|
{
|
||||||
using namespace CppTools;
|
|
||||||
using namespace ClangCodeModel::Internal;
|
|
||||||
|
|
||||||
ProjectExplorer::Project *project = projectForCurrentEditor();
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
||||||
QTC_ASSERT(project, return );
|
QTC_ASSERT(project, return );
|
||||||
|
|
||||||
@@ -127,15 +172,9 @@ void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticConta
|
|||||||
project);
|
project);
|
||||||
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
|
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
|
||||||
|
|
||||||
// Get config id
|
|
||||||
Core::Id currentConfigId = projectSettings.warningConfigId();
|
|
||||||
if (projectSettings.useGlobalConfig())
|
|
||||||
currentConfigId = globalSettings->clangDiagnosticConfigId();
|
|
||||||
|
|
||||||
// Get config
|
// Get config
|
||||||
|
ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings);
|
||||||
ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs());
|
ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs());
|
||||||
QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return );
|
|
||||||
ClangDiagnosticConfig config = configsModel.configWithId(currentConfigId);
|
|
||||||
|
|
||||||
// Create copy if needed
|
// Create copy if needed
|
||||||
if (config.isReadOnly()) {
|
if (config.isReadOnly()) {
|
||||||
@@ -197,7 +236,6 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
|
|||||||
QAction *action = new QAction();
|
QAction *action = new QAction();
|
||||||
action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
|
action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
|
||||||
QObject::connect(action, &QAction::triggered, [diagnostic]() {
|
QObject::connect(action, &QAction::triggered, [diagnostic]() {
|
||||||
using namespace ClangCodeModel::Internal;
|
|
||||||
const QString text = ClangDiagnosticWidget::createText({diagnostic},
|
const QString text = ClangDiagnosticWidget::createText({diagnostic},
|
||||||
ClangDiagnosticWidget::InfoBar);
|
ClangDiagnosticWidget::InfoBar);
|
||||||
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
|
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
|
||||||
@@ -205,7 +243,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
|
|||||||
actions << action;
|
actions << action;
|
||||||
|
|
||||||
// Remove diagnostic warning action
|
// Remove diagnostic warning action
|
||||||
if (projectForCurrentEditor()) {
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
||||||
|
if (project && isDiagnosticConfigChangable(project, diagnostic)) {
|
||||||
action = new QAction();
|
action = new QAction();
|
||||||
action->setIcon(::Utils::Icons::BROKEN.icon());
|
action->setIcon(::Utils::Icons::BROKEN.icon());
|
||||||
QObject::connect(action, &QAction::triggered, [diagnostic]() {
|
QObject::connect(action, &QAction::triggered, [diagnostic]() {
|
||||||
@@ -228,8 +267,6 @@ void ClangTextMark::updateIcon(bool valid)
|
|||||||
|
|
||||||
bool ClangTextMark::addToolTipContent(QLayout *target) const
|
bool ClangTextMark::addToolTipContent(QLayout *target) const
|
||||||
{
|
{
|
||||||
using Internal::ClangDiagnosticWidget;
|
|
||||||
|
|
||||||
QWidget *widget = ClangDiagnosticWidget::createWidget({m_diagnostic},
|
QWidget *widget = ClangDiagnosticWidget::createWidget({m_diagnostic},
|
||||||
ClangDiagnosticWidget::ToolTip);
|
ClangDiagnosticWidget::ToolTip);
|
||||||
target->addWidget(widget);
|
target->addWidget(widget);
|
||||||
@@ -243,5 +280,6 @@ void ClangTextMark::removedFromEditor()
|
|||||||
m_removedFromEditorHandler(this);
|
m_removedFromEditorHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
class ClangTextMark : public TextEditor::TextMark
|
class ClangTextMark : public TextEditor::TextMark
|
||||||
{
|
{
|
||||||
@@ -56,4 +57,5 @@ private:
|
|||||||
RemovedFromEditorHandler m_removedFromEditorHandler;
|
RemovedFromEditorHandler m_removedFromEditorHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
@@ -36,10 +36,11 @@
|
|||||||
|
|
||||||
namespace ClangFormat {
|
namespace ClangFormat {
|
||||||
|
|
||||||
static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
namespace {
|
||||||
|
void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
||||||
ReplacementsToKeep replacementsToKeep)
|
ReplacementsToKeep replacementsToKeep)
|
||||||
{
|
{
|
||||||
style.MaxEmptyLinesToKeep = 2;
|
style.MaxEmptyLinesToKeep = 100;
|
||||||
style.SortIncludes = false;
|
style.SortIncludes = false;
|
||||||
style.SortUsingDeclarations = false;
|
style.SortUsingDeclarations = false;
|
||||||
|
|
||||||
@@ -56,33 +57,31 @@ static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::StringRef clearExtraNewline(llvm::StringRef text)
|
llvm::StringRef clearExtraNewline(llvm::StringRef text)
|
||||||
{
|
{
|
||||||
while (text.startswith("\n\n"))
|
while (text.startswith("\n\n"))
|
||||||
text = text.drop_front();
|
text = text.drop_front();
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
static clang::tooling::Replacements filteredReplacements(
|
clang::tooling::Replacements filteredReplacements(const QByteArray &buffer,
|
||||||
const QByteArray &buffer,
|
|
||||||
const clang::tooling::Replacements &replacements,
|
const clang::tooling::Replacements &replacements,
|
||||||
int utf8Offset,
|
int utf8Offset,
|
||||||
int utf8Length,
|
int utf8Length,
|
||||||
int extraEmptySpaceOffset,
|
|
||||||
ReplacementsToKeep replacementsToKeep)
|
ReplacementsToKeep replacementsToKeep)
|
||||||
{
|
{
|
||||||
clang::tooling::Replacements filtered;
|
clang::tooling::Replacements filtered;
|
||||||
for (const clang::tooling::Replacement &replacement : replacements) {
|
for (const clang::tooling::Replacement &replacement : replacements) {
|
||||||
int replacementOffset = static_cast<int>(replacement.getOffset());
|
int replacementOffset = static_cast<int>(replacement.getOffset());
|
||||||
const bool replacementDoesNotMatchRestriction
|
|
||||||
= replacementOffset >= utf8Offset + utf8Length
|
|
||||||
|| (replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
|
||||||
&& (replacementOffset < utf8Offset - 1 || buffer.at(replacementOffset) != '\n'));
|
|
||||||
if (replacementDoesNotMatchRestriction)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (replacementOffset >= utf8Offset - 1)
|
// Skip everything after.
|
||||||
replacementOffset += extraEmptySpaceOffset;
|
if (replacementOffset >= utf8Offset + utf8Length)
|
||||||
|
return filtered;
|
||||||
|
|
||||||
|
const bool isNotIndentOrInRange = replacementOffset < utf8Offset - 1
|
||||||
|
|| buffer.at(replacementOffset) != '\n';
|
||||||
|
if (isNotIndentOrInRange && replacementsToKeep == ReplacementsToKeep::OnlyIndent)
|
||||||
|
continue;
|
||||||
|
|
||||||
llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
llvm::StringRef text = replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
||||||
? clearExtraNewline(replacement.getReplacementText())
|
? clearExtraNewline(replacement.getReplacementText())
|
||||||
@@ -106,17 +105,10 @@ static clang::tooling::Replacements filteredReplacements(
|
|||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock)
|
void trimRHSWhitespace(const QTextBlock &block)
|
||||||
{
|
{
|
||||||
QTextBlock prevBlock = currentBlock.previous();
|
const QString initialText = block.text();
|
||||||
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty())
|
if (!initialText.rbegin()->isSpace())
|
||||||
prevBlock = prevBlock.previous();
|
|
||||||
|
|
||||||
if (prevBlock.text().trimmed().isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QString initialText = prevBlock.text();
|
|
||||||
if (!initialText.at(initialText.size() - 1).isSpace())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto lastNonSpace = std::find_if_not(initialText.rbegin(),
|
auto lastNonSpace = std::find_if_not(initialText.rbegin(),
|
||||||
@@ -124,7 +116,7 @@ static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock)
|
|||||||
[](const QChar &letter) { return letter.isSpace(); });
|
[](const QChar &letter) { return letter.isSpace(); });
|
||||||
const int extraSpaceCount = static_cast<int>(std::distance(initialText.rbegin(), lastNonSpace));
|
const int extraSpaceCount = static_cast<int>(std::distance(initialText.rbegin(), lastNonSpace));
|
||||||
|
|
||||||
QTextCursor cursor(prevBlock);
|
QTextCursor cursor(block);
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
cursor.movePosition(QTextCursor::Right,
|
cursor.movePosition(QTextCursor::Right,
|
||||||
QTextCursor::MoveAnchor,
|
QTextCursor::MoveAnchor,
|
||||||
@@ -134,31 +126,25 @@ static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock)
|
|||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the total langth of previous lines with pure whitespace.
|
// Add extra text in case of the empty line or the line starting with ')'.
|
||||||
static int previousEmptyLinesLength(const QTextBlock ¤tBlock)
|
// Track such extra pieces of text in isInsideModifiedLine().
|
||||||
{
|
int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry)
|
||||||
int length{0};
|
|
||||||
QTextBlock prevBlock = currentBlock.previous();
|
|
||||||
while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) {
|
|
||||||
length += prevBlock.text().length() + 1;
|
|
||||||
prevBlock = prevBlock.previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void modifyToIndentEmptyLines(
|
|
||||||
QByteArray &buffer, int utf8Offset, const QTextBlock &block, bool secondTry)
|
|
||||||
{
|
{
|
||||||
const QString blockText = block.text();
|
const QString blockText = block.text();
|
||||||
int firstNonWhitespace = Utils::indexOf(blockText,
|
int firstNonWhitespace = Utils::indexOf(blockText,
|
||||||
[](const QChar &ch) { return !ch.isSpace(); });
|
[](const QChar &ch) { return !ch.isSpace(); });
|
||||||
|
int utf8Offset = Utils::Text::utf8NthLineOffset(block.document(),
|
||||||
|
buffer,
|
||||||
|
block.blockNumber() + 1);
|
||||||
if (firstNonWhitespace > 0)
|
if (firstNonWhitespace > 0)
|
||||||
utf8Offset += firstNonWhitespace;
|
utf8Offset += firstNonWhitespace;
|
||||||
|
else
|
||||||
|
utf8Offset += blockText.length();
|
||||||
|
|
||||||
const bool closingParenBlock = firstNonWhitespace >= 0
|
const bool closingParenBlock = firstNonWhitespace >= 0
|
||||||
&& blockText.at(firstNonWhitespace) == ')';
|
&& blockText.at(firstNonWhitespace) == ')';
|
||||||
|
|
||||||
|
int extraLength = 0;
|
||||||
if (firstNonWhitespace < 0 || closingParenBlock) {
|
if (firstNonWhitespace < 0 || closingParenBlock) {
|
||||||
//This extra text works for the most cases.
|
//This extra text works for the most cases.
|
||||||
QByteArray dummyText("a;a;");
|
QByteArray dummyText("a;a;");
|
||||||
@@ -174,6 +160,7 @@ static void modifyToIndentEmptyLines(
|
|||||||
dummyText = "&& a";
|
dummyText = "&& a";
|
||||||
|
|
||||||
buffer.insert(utf8Offset, dummyText);
|
buffer.insert(utf8Offset, dummyText);
|
||||||
|
extraLength += dummyText.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secondTry) {
|
if (secondTry) {
|
||||||
@@ -186,52 +173,45 @@ static void modifyToIndentEmptyLines(
|
|||||||
// unclosed parentheses.
|
// unclosed parentheses.
|
||||||
// TODO: Does it help to add different endings depending on the context?
|
// TODO: Does it help to add different endings depending on the context?
|
||||||
buffer.insert(nextLinePos, ')');
|
buffer.insert(nextLinePos, ')');
|
||||||
}
|
extraLength += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Utils::LineColumn utf16LineColumn(const QTextBlock &block,
|
return extraLength;
|
||||||
int blockOffsetUtf8,
|
}
|
||||||
const QByteArray &utf8Buffer,
|
|
||||||
int utf8Offset)
|
bool isInsideModifiedLine(const QString &originalLine, const QString &modifiedLine, int column)
|
||||||
{
|
{
|
||||||
// If lastIndexOf('\n') returns -1 then we are fine to add 1 and get 0 offset.
|
// Detect the cases when we have inserted extra text into the line to get the indentation.
|
||||||
const int lineStartUtf8Offset = utf8Offset == 0
|
return originalLine.length() < modifiedLine.length() && column != modifiedLine.length() + 1
|
||||||
? 0
|
&& (column > originalLine.length() || originalLine.trimmed().isEmpty()
|
||||||
: utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1;
|
|| !modifiedLine.startsWith(originalLine));
|
||||||
int line = block.blockNumber() + 1; // Init with the line corresponding the block.
|
|
||||||
|
|
||||||
if (utf8Offset < blockOffsetUtf8) {
|
|
||||||
line -= static_cast<int>(std::count(utf8Buffer.begin() + lineStartUtf8Offset,
|
|
||||||
utf8Buffer.begin() + blockOffsetUtf8,
|
|
||||||
'\n'));
|
|
||||||
} else {
|
|
||||||
line += static_cast<int>(std::count(utf8Buffer.begin() + blockOffsetUtf8,
|
|
||||||
utf8Buffer.begin() + lineStartUtf8Offset,
|
|
||||||
'\n'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray lineText = utf8Buffer.mid(lineStartUtf8Offset,
|
TextEditor::Replacements utf16Replacements(const QTextDocument *doc,
|
||||||
utf8Offset - lineStartUtf8Offset);
|
|
||||||
return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static TextEditor::Replacements utf16Replacements(const QTextBlock &block,
|
|
||||||
int blockOffsetUtf8,
|
|
||||||
const QByteArray &utf8Buffer,
|
const QByteArray &utf8Buffer,
|
||||||
const clang::tooling::Replacements &replacements)
|
const clang::tooling::Replacements &replacements)
|
||||||
{
|
{
|
||||||
TextEditor::Replacements convertedReplacements;
|
TextEditor::Replacements convertedReplacements;
|
||||||
convertedReplacements.reserve(replacements.size());
|
convertedReplacements.reserve(replacements.size());
|
||||||
|
|
||||||
for (const clang::tooling::Replacement &replacement : replacements) {
|
for (const clang::tooling::Replacement &replacement : replacements) {
|
||||||
const Utils::LineColumn lineColUtf16 = utf16LineColumn(block,
|
Utils::LineColumn lineColUtf16 = Utils::Text::utf16LineColumn(utf8Buffer,
|
||||||
blockOffsetUtf8,
|
|
||||||
utf8Buffer,
|
|
||||||
static_cast<int>(
|
static_cast<int>(
|
||||||
replacement.getOffset()));
|
replacement.getOffset()));
|
||||||
if (!lineColUtf16.isValid())
|
if (!lineColUtf16.isValid())
|
||||||
continue;
|
continue;
|
||||||
const int utf16Offset = Utils::Text::positionInText(block.document(),
|
|
||||||
|
const QString lineText = doc->findBlockByNumber(lineColUtf16.line - 1).text();
|
||||||
|
const QString bufferLineText
|
||||||
|
= Utils::Text::utf16LineTextInUtf8Buffer(utf8Buffer,
|
||||||
|
static_cast<int>(replacement.getOffset()));
|
||||||
|
if (isInsideModifiedLine(lineText, bufferLineText, lineColUtf16.column))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lineColUtf16.column = std::min(lineColUtf16.column, lineText.length() + 1);
|
||||||
|
|
||||||
|
const int utf16Offset = Utils::Text::positionInText(doc,
|
||||||
lineColUtf16.line,
|
lineColUtf16.line,
|
||||||
lineColUtf16.column);
|
lineColUtf16.column);
|
||||||
const int utf16Length = QString::fromUtf8(
|
const int utf16Length = QString::fromUtf8(
|
||||||
@@ -246,7 +226,7 @@ static TextEditor::Replacements utf16Replacements(const QTextBlock &block,
|
|||||||
return convertedReplacements;
|
return convertedReplacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements)
|
void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements)
|
||||||
{
|
{
|
||||||
if (replacements.empty())
|
if (replacements.empty())
|
||||||
return;
|
return;
|
||||||
@@ -266,33 +246,240 @@ static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString selectedLines(QTextDocument *doc,
|
QString selectedLines(QTextDocument *doc, const QTextBlock &startBlock, const QTextBlock &endBlock)
|
||||||
const QTextBlock &startBlock,
|
|
||||||
const QTextBlock &endBlock)
|
|
||||||
{
|
{
|
||||||
QString text = Utils::Text::textAt(QTextCursor(doc),
|
return Utils::Text::textAt(QTextCursor(doc),
|
||||||
startBlock.position(),
|
startBlock.position(),
|
||||||
std::max(0,
|
std::max(0,
|
||||||
endBlock.position() + endBlock.length()
|
endBlock.position() + endBlock.length()
|
||||||
- startBlock.position() - 1));
|
- startBlock.position() - 1));
|
||||||
while (!text.isEmpty() && text.rbegin()->isSpace())
|
|
||||||
text.chop(1);
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int indentationForBlock(const TextEditor::Replacements &toReplace,
|
||||||
|
const QByteArray &buffer,
|
||||||
|
const QTextBlock ¤tBlock)
|
||||||
|
{
|
||||||
|
const int utf8Offset = Utils::Text::utf8NthLineOffset(currentBlock.document(),
|
||||||
|
buffer,
|
||||||
|
currentBlock.blockNumber() + 1);
|
||||||
|
auto replacementIt = std::find_if(toReplace.begin(),
|
||||||
|
toReplace.end(),
|
||||||
|
[utf8Offset](const TextEditor::Replacement &replacement) {
|
||||||
|
return replacement.offset == utf8Offset - 1;
|
||||||
|
});
|
||||||
|
if (replacementIt == toReplace.end())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int afterLineBreak = replacementIt->text.lastIndexOf('\n');
|
||||||
|
afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1;
|
||||||
|
return static_cast<int>(replacementIt->text.size() - afterLineBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doNotIndentInContext(QTextDocument *doc, int pos)
|
||||||
|
{
|
||||||
|
const QChar character = doc->characterAt(pos);
|
||||||
|
const QTextBlock currentBlock = doc->findBlock(pos);
|
||||||
|
const QString text = currentBlock.text().left(pos - currentBlock.position());
|
||||||
|
// NOTE: check if "<<" and ">>" always work correctly.
|
||||||
|
switch (character.toLatin1()) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
// Do not indent when it's the first ':' and it's not the 'case' line.
|
||||||
|
if (text.contains(QLatin1String("case")) || text.contains(QLatin1String("default"))
|
||||||
|
|| text.contains(QLatin1String("public")) || text.contains(QLatin1String("private"))
|
||||||
|
|| text.contains(QLatin1String("protected")) || text.contains(QLatin1String("signals"))
|
||||||
|
|| text.contains(QLatin1String("Q_SIGNALS"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pos > 0 && doc->characterAt(pos - 1) != ':')
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextBlock reverseFindLastEmptyBlock(QTextBlock start)
|
||||||
|
{
|
||||||
|
if (start.position() > 0) {
|
||||||
|
start = start.previous();
|
||||||
|
while (start.position() > 0 && start.text().trimmed().isEmpty())
|
||||||
|
start = start.previous();
|
||||||
|
if (!start.text().trimmed().isEmpty())
|
||||||
|
start = start.next();
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int formattingRangeStart(const QTextBlock ¤tBlock,
|
||||||
|
const QByteArray &buffer,
|
||||||
|
int documentRevision)
|
||||||
|
{
|
||||||
|
QTextBlock prevBlock = currentBlock.previous();
|
||||||
|
while ((prevBlock.position() > 0 || prevBlock.length() > 0)
|
||||||
|
&& prevBlock.revision() != documentRevision) {
|
||||||
|
// Find the first block with not matching revision.
|
||||||
|
prevBlock = prevBlock.previous();
|
||||||
|
}
|
||||||
|
if (prevBlock.revision() == documentRevision)
|
||||||
|
prevBlock = prevBlock.next();
|
||||||
|
|
||||||
|
return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc)
|
ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc)
|
||||||
: TextEditor::Indenter(doc)
|
: TextEditor::Indenter(doc)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
|
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
||||||
const QVector<QTextBlock> &blocks,
|
const QTextBlock &startBlock,
|
||||||
const TextEditor::TabSettings & /*tabSettings*/,
|
const QTextBlock &endBlock,
|
||||||
|
ReplacementsToKeep replacementsToKeep,
|
||||||
|
const QChar &typedChar,
|
||||||
|
bool secondTry) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return TextEditor::Replacements());
|
||||||
|
|
||||||
|
clang::format::FormatStyle style = styleForFile();
|
||||||
|
QByteArray originalBuffer = buffer;
|
||||||
|
|
||||||
|
int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, startBlock.blockNumber() + 1);
|
||||||
|
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements(););
|
||||||
|
int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size();
|
||||||
|
|
||||||
|
int rangeStart = 0;
|
||||||
|
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
|
||||||
|
rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
|
||||||
|
|
||||||
|
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
|
||||||
|
buffer.insert(utf8Offset - 1, " //");
|
||||||
|
utf8Offset += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustFormatStyleForLineBreak(style, replacementsToKeep);
|
||||||
|
if (typedChar == QChar::Null) {
|
||||||
|
for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) {
|
||||||
|
utf8Length += forceIndentWithExtraText(buffer,
|
||||||
|
m_doc->findBlockByNumber(index),
|
||||||
|
secondTry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart)
|
||||||
|
rangeStart = utf8Offset;
|
||||||
|
|
||||||
|
unsigned int rangeLength = static_cast<unsigned int>(utf8Offset + utf8Length - rangeStart);
|
||||||
|
std::vector<clang::tooling::Range> ranges{{static_cast<unsigned int>(rangeStart), rangeLength}};
|
||||||
|
|
||||||
|
clang::format::FormattingAttemptStatus status;
|
||||||
|
clang::tooling::Replacements clangReplacements = reformat(style,
|
||||||
|
buffer.data(),
|
||||||
|
ranges,
|
||||||
|
m_fileName.toString().toStdString(),
|
||||||
|
&status);
|
||||||
|
|
||||||
|
clang::tooling::Replacements filtered;
|
||||||
|
if (status.FormatComplete) {
|
||||||
|
filtered = filteredReplacements(buffer,
|
||||||
|
clangReplacements,
|
||||||
|
utf8Offset,
|
||||||
|
utf8Length,
|
||||||
|
replacementsToKeep);
|
||||||
|
}
|
||||||
|
const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
||||||
|
&& typedChar == QChar::Null && !secondTry;
|
||||||
|
if (canTryAgain && filtered.empty()) {
|
||||||
|
return replacements(originalBuffer,
|
||||||
|
startBlock,
|
||||||
|
endBlock,
|
||||||
|
replacementsToKeep,
|
||||||
|
typedChar,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf16Replacements(m_doc, buffer, filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::Replacements ClangFormatBaseIndenter::format(
|
||||||
|
const TextEditor::RangesInLines &rangesInLines)
|
||||||
|
{
|
||||||
|
if (rangesInLines.empty())
|
||||||
|
return TextEditor::Replacements();
|
||||||
|
|
||||||
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
std::vector<clang::tooling::Range> ranges;
|
||||||
|
ranges.reserve(rangesInLines.size());
|
||||||
|
|
||||||
|
for (auto &range : rangesInLines) {
|
||||||
|
const int utf8StartOffset = Utils::Text::utf8NthLineOffset(m_doc, buffer, range.startLine);
|
||||||
|
int utf8RangeLength = m_doc->findBlockByNumber(range.endLine - 1).text().toUtf8().size();
|
||||||
|
if (range.endLine > range.startLine) {
|
||||||
|
utf8RangeLength += Utils::Text::utf8NthLineOffset(m_doc, buffer, range.endLine)
|
||||||
|
- utf8StartOffset;
|
||||||
|
}
|
||||||
|
ranges.emplace_back(static_cast<unsigned int>(utf8StartOffset),
|
||||||
|
static_cast<unsigned int>(utf8RangeLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::format::FormattingAttemptStatus status;
|
||||||
|
const clang::tooling::Replacements clangReplacements
|
||||||
|
= reformat(styleForFile(), buffer.data(), ranges, m_fileName.toString().toStdString(), &status);
|
||||||
|
const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements);
|
||||||
|
applyReplacements(m_doc, toReplace);
|
||||||
|
|
||||||
|
return toReplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
|
||||||
|
const QTextBlock &endBlock,
|
||||||
|
const QByteArray &buffer,
|
||||||
|
const QChar &typedChar,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
TextEditor::IndentationForBlock ret;
|
if (typedChar != QChar::Null && cursorPositionInEditor > 0
|
||||||
for (QTextBlock block : blocks)
|
&& m_doc->characterAt(cursorPositionInEditor - 1) == typedChar
|
||||||
ret.insert(block.blockNumber(), indentFor(block, cursorPositionInEditor));
|
&& doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) {
|
||||||
return ret;
|
return TextEditor::Replacements();
|
||||||
|
}
|
||||||
|
|
||||||
|
startBlock = reverseFindLastEmptyBlock(startBlock);
|
||||||
|
const int startBlockPosition = startBlock.position();
|
||||||
|
if (startBlock.position() > 0) {
|
||||||
|
trimRHSWhitespace(startBlock.previous());
|
||||||
|
if (cursorPositionInEditor >= 0)
|
||||||
|
cursorPositionInEditor += startBlock.position() - startBlockPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
|
||||||
|
if (formatWhileTyping()
|
||||||
|
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
|
||||||
|
&& (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) {
|
||||||
|
// Format before current position only in case the cursor is inside the indented block.
|
||||||
|
// So if cursor position is less then the block position then the current line is before
|
||||||
|
// the indented block - don't trigger extra formatting in this case.
|
||||||
|
// cursorPositionInEditor == -1 means the consition matches automatically.
|
||||||
|
|
||||||
|
// Format only before newline or complete statement not to break code.
|
||||||
|
replacementsToKeep = ReplacementsToKeep::IndentAndBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
return replacements(buffer,
|
||||||
|
startBlock,
|
||||||
|
endBlock,
|
||||||
|
replacementsToKeep,
|
||||||
|
typedChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
|
||||||
|
const QTextBlock &endBlock,
|
||||||
|
const QChar &typedChar,
|
||||||
|
int cursorPositionInEditor)
|
||||||
|
{
|
||||||
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
applyReplacements(m_doc,
|
||||||
|
indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
|
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
|
||||||
@@ -324,120 +511,6 @@ void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor,
|
|||||||
indent(cursor, QChar::Null, cursorPositionInEditor);
|
indent(cursor, QChar::Null, cursorPositionInEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::Replacements ClangFormatBaseIndenter::format(
|
|
||||||
const TextEditor::RangesInLines &rangesInLines)
|
|
||||||
{
|
|
||||||
if (rangesInLines.empty())
|
|
||||||
return TextEditor::Replacements();
|
|
||||||
|
|
||||||
int utf8Offset = -1;
|
|
||||||
QTextBlock block;
|
|
||||||
|
|
||||||
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
|
||||||
std::vector<clang::tooling::Range> ranges;
|
|
||||||
ranges.reserve(rangesInLines.size());
|
|
||||||
|
|
||||||
for (auto &range : rangesInLines) {
|
|
||||||
const int utf8StartOffset = Utils::Text::utf8NthLineOffset(m_doc, buffer, range.startLine);
|
|
||||||
const QTextBlock end = m_doc->findBlockByNumber(range.endLine - 1);
|
|
||||||
int utf8RangeLength = end.text().toUtf8().size();
|
|
||||||
if (range.endLine > range.startLine) {
|
|
||||||
utf8RangeLength += Utils::Text::utf8NthLineOffset(m_doc, buffer, range.endLine)
|
|
||||||
- utf8StartOffset;
|
|
||||||
}
|
|
||||||
ranges.emplace_back(static_cast<unsigned int>(utf8StartOffset),
|
|
||||||
static_cast<unsigned int>(utf8RangeLength));
|
|
||||||
|
|
||||||
if (utf8Offset < 0) {
|
|
||||||
utf8Offset = utf8StartOffset;
|
|
||||||
block = m_doc->findBlockByNumber(range.startLine - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clang::format::FormatStyle style = styleForFile();
|
|
||||||
clang::format::FormattingAttemptStatus status;
|
|
||||||
const clang::tooling::Replacements clangReplacements
|
|
||||||
= reformat(style, buffer.data(), ranges, m_fileName.toString().toStdString(), &status);
|
|
||||||
const TextEditor::Replacements toReplace = utf16Replacements(block,
|
|
||||||
utf8Offset,
|
|
||||||
buffer,
|
|
||||||
clangReplacements);
|
|
||||||
applyReplacements(m_doc, toReplace);
|
|
||||||
|
|
||||||
return toReplace;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool doNotIndentInContext(QTextDocument *doc, int pos)
|
|
||||||
{
|
|
||||||
const QChar character = doc->characterAt(pos);
|
|
||||||
const QTextBlock currentBlock = doc->findBlock(pos);
|
|
||||||
const QString text = currentBlock.text().left(pos - currentBlock.position());
|
|
||||||
// NOTE: check if "<<" and ">>" always work correctly.
|
|
||||||
switch (character.toLatin1()) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case ':':
|
|
||||||
// Do not indent when it's the first ':' and it's not the 'case' line.
|
|
||||||
if (text.contains(QLatin1String("case")) || text.contains(QLatin1String("default"))
|
|
||||||
|| text.contains(QLatin1String("public")) || text.contains(QLatin1String("private"))
|
|
||||||
|| text.contains(QLatin1String("protected")) || text.contains(QLatin1String("signals"))
|
|
||||||
|| text.contains(QLatin1String("Q_SIGNALS"))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (pos > 0 && doc->characterAt(pos - 1) != ':')
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
|
|
||||||
const QTextBlock &endBlock,
|
|
||||||
const QChar &typedChar,
|
|
||||||
int cursorPositionInEditor)
|
|
||||||
{
|
|
||||||
if (typedChar != QChar::Null && cursorPositionInEditor > 0
|
|
||||||
&& m_doc->characterAt(cursorPositionInEditor - 1) == typedChar
|
|
||||||
&& doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int startBlockPosition = startBlock.position();
|
|
||||||
trimFirstNonEmptyBlock(startBlock);
|
|
||||||
if (cursorPositionInEditor >= 0)
|
|
||||||
cursorPositionInEditor += startBlock.position() - startBlockPosition;
|
|
||||||
|
|
||||||
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
|
|
||||||
if (formatWhileTyping()
|
|
||||||
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
|
|
||||||
&& (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) {
|
|
||||||
// Format before current position only in case the cursor is inside the indented block.
|
|
||||||
// So if cursor position is less then the block position then the current line is before
|
|
||||||
// the indented block - don't trigger extra formatting in this case.
|
|
||||||
// cursorPositionInEditor == -1 means the consition matches automatically.
|
|
||||||
|
|
||||||
// Format only before newline or complete statement not to break code.
|
|
||||||
replacementsToKeep = ReplacementsToKeep::IndentAndBefore;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
|
||||||
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc,
|
|
||||||
buffer,
|
|
||||||
startBlock.blockNumber() + 1);
|
|
||||||
QTC_ASSERT(utf8Offset >= 0, return;);
|
|
||||||
const int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size();
|
|
||||||
|
|
||||||
applyReplacements(m_doc,
|
|
||||||
replacements(buffer,
|
|
||||||
utf8Offset,
|
|
||||||
utf8Length,
|
|
||||||
startBlock,
|
|
||||||
endBlock,
|
|
||||||
replacementsToKeep,
|
|
||||||
typedChar));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
const TextEditor::TabSettings & /*tabSettings*/,
|
const TextEditor::TabSettings & /*tabSettings*/,
|
||||||
@@ -446,35 +519,40 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
|||||||
indentBlocks(block, block, typedChar, cursorPositionInEditor);
|
indentBlocks(block, block, typedChar, cursorPositionInEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, int /*cursorPositionInEditor*/)
|
|
||||||
{
|
|
||||||
trimFirstNonEmptyBlock(block);
|
|
||||||
|
|
||||||
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
|
||||||
const int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, block.blockNumber() + 1);
|
|
||||||
QTC_ASSERT(utf8Offset >= 0, return 0;);
|
|
||||||
|
|
||||||
const TextEditor::Replacements toReplace = replacements(buffer,
|
|
||||||
utf8Offset,
|
|
||||||
0,
|
|
||||||
block,
|
|
||||||
block,
|
|
||||||
ReplacementsToKeep::OnlyIndent);
|
|
||||||
|
|
||||||
if (toReplace.empty())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const TextEditor::Replacement &replacement = toReplace.front();
|
|
||||||
int afterLineBreak = replacement.text.lastIndexOf('\n');
|
|
||||||
afterLineBreak = (afterLineBreak < 0) ? 0 : afterLineBreak + 1;
|
|
||||||
return static_cast<int>(replacement.text.size() - afterLineBreak);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
|
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
|
||||||
const TextEditor::TabSettings & /*tabSettings*/,
|
const TextEditor::TabSettings & /*tabSettings*/,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
return indentFor(block, cursorPositionInEditor);
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
TextEditor::Replacements toReplace = indentsFor(block,
|
||||||
|
block,
|
||||||
|
buffer,
|
||||||
|
QChar::Null,
|
||||||
|
cursorPositionInEditor);
|
||||||
|
if (toReplace.empty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return indentationForBlock(toReplace, buffer, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
|
||||||
|
const QVector<QTextBlock> &blocks,
|
||||||
|
const TextEditor::TabSettings & /*tabSettings*/,
|
||||||
|
int cursorPositionInEditor)
|
||||||
|
{
|
||||||
|
TextEditor::IndentationForBlock ret;
|
||||||
|
if (blocks.isEmpty())
|
||||||
|
return ret;
|
||||||
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
TextEditor::Replacements toReplace = indentsFor(blocks.front(),
|
||||||
|
blocks.back(),
|
||||||
|
buffer,
|
||||||
|
QChar::Null,
|
||||||
|
cursorPositionInEditor);
|
||||||
|
|
||||||
|
for (const QTextBlock &block : blocks)
|
||||||
|
ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClangFormatBaseIndenter::isElectricCharacter(const QChar &ch) const
|
bool ClangFormatBaseIndenter::isElectricCharacter(const QChar &ch) const
|
||||||
@@ -527,97 +605,4 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const
|
|||||||
return clang::format::getLLVMStyle();
|
return clang::format::getLLVMStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int formattingRangeStart(const QTextBlock ¤tBlock,
|
|
||||||
const QByteArray &buffer,
|
|
||||||
int documentRevision)
|
|
||||||
{
|
|
||||||
QTextBlock prevBlock = currentBlock.previous();
|
|
||||||
while ((prevBlock.position() > 0 || prevBlock.length() > 0)
|
|
||||||
&& prevBlock.revision() != documentRevision) {
|
|
||||||
// Find the first block with not matching revision.
|
|
||||||
prevBlock = prevBlock.previous();
|
|
||||||
}
|
|
||||||
if (prevBlock.revision() == documentRevision)
|
|
||||||
prevBlock = prevBlock.next();
|
|
||||||
|
|
||||||
return Utils::Text::utf8NthLineOffset(prevBlock.document(), buffer, prevBlock.blockNumber() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
|
||||||
int utf8Offset,
|
|
||||||
int utf8Length,
|
|
||||||
const QTextBlock &startBlock,
|
|
||||||
const QTextBlock &endBlock,
|
|
||||||
ReplacementsToKeep replacementsToKeep,
|
|
||||||
const QChar &typedChar,
|
|
||||||
bool secondTry) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return TextEditor::Replacements());
|
|
||||||
|
|
||||||
clang::format::FormatStyle style = styleForFile();
|
|
||||||
|
|
||||||
int originalOffsetUtf8 = utf8Offset;
|
|
||||||
int originalLengthUtf8 = utf8Length;
|
|
||||||
QByteArray originalBuffer = buffer;
|
|
||||||
|
|
||||||
int rangeStart = 0;
|
|
||||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
|
|
||||||
rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
|
|
||||||
|
|
||||||
int extraEmptySpaceOffset = previousEmptyLinesLength(startBlock);
|
|
||||||
utf8Offset -= extraEmptySpaceOffset;
|
|
||||||
buffer.remove(utf8Offset, extraEmptySpaceOffset);
|
|
||||||
|
|
||||||
adjustFormatStyleForLineBreak(style, replacementsToKeep);
|
|
||||||
if (typedChar == QChar::Null && startBlock == endBlock) {
|
|
||||||
modifyToIndentEmptyLines(buffer, utf8Offset, startBlock, secondTry);
|
|
||||||
utf8Length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) {
|
|
||||||
buffer.insert(utf8Offset - 1, " //");
|
|
||||||
extraEmptySpaceOffset -= 3;
|
|
||||||
utf8Offset += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replacementsToKeep != ReplacementsToKeep::IndentAndBefore || utf8Offset < rangeStart)
|
|
||||||
rangeStart = utf8Offset;
|
|
||||||
|
|
||||||
unsigned int rangeLength = static_cast<unsigned int>(utf8Offset + utf8Length - rangeStart);
|
|
||||||
|
|
||||||
std::vector<clang::tooling::Range> ranges{{static_cast<unsigned int>(rangeStart), rangeLength}};
|
|
||||||
|
|
||||||
clang::format::FormattingAttemptStatus status;
|
|
||||||
|
|
||||||
clang::tooling::Replacements clangReplacements = reformat(style,
|
|
||||||
buffer.data(),
|
|
||||||
ranges,
|
|
||||||
m_fileName.toString().toStdString(),
|
|
||||||
&status);
|
|
||||||
|
|
||||||
clang::tooling::Replacements filtered;
|
|
||||||
if (status.FormatComplete) {
|
|
||||||
filtered = filteredReplacements(buffer,
|
|
||||||
clangReplacements,
|
|
||||||
utf8Offset,
|
|
||||||
utf8Length,
|
|
||||||
extraEmptySpaceOffset,
|
|
||||||
replacementsToKeep);
|
|
||||||
}
|
|
||||||
const bool canTryAgain = replacementsToKeep == ReplacementsToKeep::OnlyIndent
|
|
||||||
&& typedChar == QChar::Null && !secondTry;
|
|
||||||
if (canTryAgain && filtered.empty()) {
|
|
||||||
return replacements(originalBuffer,
|
|
||||||
originalOffsetUtf8,
|
|
||||||
originalLengthUtf8,
|
|
||||||
startBlock,
|
|
||||||
endBlock,
|
|
||||||
replacementsToKeep,
|
|
||||||
typedChar,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf16Replacements(startBlock, originalOffsetUtf8, originalBuffer, filtered);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -79,10 +79,12 @@ private:
|
|||||||
const QTextBlock &endBlock,
|
const QTextBlock &endBlock,
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
int cursorPositionInEditor);
|
int cursorPositionInEditor);
|
||||||
int indentFor(const QTextBlock &block, int cursorPositionInEditor);
|
TextEditor::Replacements indentsFor(QTextBlock startBlock,
|
||||||
|
const QTextBlock &endBlock,
|
||||||
|
const QByteArray &buffer,
|
||||||
|
const QChar &typedChar,
|
||||||
|
int cursorPositionInEditor);
|
||||||
TextEditor::Replacements replacements(QByteArray buffer,
|
TextEditor::Replacements replacements(QByteArray buffer,
|
||||||
int utf8Offset,
|
|
||||||
int utf8Length,
|
|
||||||
const QTextBlock &startBlock,
|
const QTextBlock &startBlock,
|
||||||
const QTextBlock &endBlock,
|
const QTextBlock &endBlock,
|
||||||
ReplacementsToKeep replacementsToKeep,
|
ReplacementsToKeep replacementsToKeep,
|
||||||
|
@@ -19,6 +19,10 @@ Project {
|
|||||||
"QMAKE_LIBRARY",
|
"QMAKE_LIBRARY",
|
||||||
"QMAKE_BUILTIN_PRFS",
|
"QMAKE_BUILTIN_PRFS",
|
||||||
])
|
])
|
||||||
|
Properties {
|
||||||
|
condition: qbs.targetOS.contains("windows")
|
||||||
|
cpp.dynamicLibraries: "advapi32"
|
||||||
|
}
|
||||||
|
|
||||||
Export {
|
Export {
|
||||||
Depends { name: "ProParser" }
|
Depends { name: "ProParser" }
|
||||||
@@ -48,6 +52,8 @@ Project {
|
|||||||
"qmakeparser.h",
|
"qmakeparser.h",
|
||||||
"qmakevfs.cpp",
|
"qmakevfs.cpp",
|
||||||
"qmakevfs.h",
|
"qmakevfs.h",
|
||||||
|
"registry.cpp",
|
||||||
|
"registry_p.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,12 @@ bool IoUtils::isRelativePath(const QString &path)
|
|||||||
&& (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
|
&& (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// (... unless, of course, they're UNC, which qmake fails on anyway)
|
// ... unless, of course, they're UNC:
|
||||||
|
if (path.length() >= 2
|
||||||
|
&& (path.at(0).unicode() == '\\' || path.at(0).unicode() == '/')
|
||||||
|
&& path.at(1) == path.at(0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (path.startsWith(QLatin1Char('/')))
|
if (path.startsWith(QLatin1Char('/')))
|
||||||
return false;
|
return false;
|
||||||
|
@@ -15,6 +15,7 @@ HEADERS += \
|
|||||||
proitems.h \
|
proitems.h \
|
||||||
prowriter.h \
|
prowriter.h \
|
||||||
qmakevfs.h \
|
qmakevfs.h \
|
||||||
|
registry_p.h \
|
||||||
ioutils.h
|
ioutils.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
@@ -26,7 +27,9 @@ SOURCES += \
|
|||||||
proitems.cpp \
|
proitems.cpp \
|
||||||
prowriter.cpp \
|
prowriter.cpp \
|
||||||
qmakevfs.cpp \
|
qmakevfs.cpp \
|
||||||
|
registry.cpp \
|
||||||
ioutils.cpp
|
ioutils.cpp
|
||||||
|
|
||||||
RESOURCES += proparser.qrc
|
RESOURCES += proparser.qrc
|
||||||
DEFINES += QMAKE_BUILTIN_PRFS QMAKE_OVERRIDE_PRFS
|
DEFINES += QMAKE_BUILTIN_PRFS QMAKE_OVERRIDE_PRFS
|
||||||
|
win32: LIBS *= -ladvapi32
|
||||||
|
@@ -31,6 +31,10 @@
|
|||||||
#include "qmakevfs.h"
|
#include "qmakevfs.h"
|
||||||
#include "ioutils.h"
|
#include "ioutils.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# include "registry_p.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <qbytearray.h>
|
#include <qbytearray.h>
|
||||||
#include <qdir.h>
|
#include <qdir.h>
|
||||||
#include <qfile.h>
|
#include <qfile.h>
|
||||||
@@ -88,7 +92,7 @@ enum ExpandFunc {
|
|||||||
E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE,
|
E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE,
|
||||||
E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
|
E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS,
|
||||||
E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH,
|
E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH,
|
||||||
E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV
|
E_SYSTEM_PATH, E_SHELL_PATH, E_SYSTEM_QUOTE, E_SHELL_QUOTE, E_GETENV, E_READ_REGISTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TestFunc {
|
enum TestFunc {
|
||||||
@@ -153,6 +157,7 @@ void QMakeEvaluator::initFunctionStatics()
|
|||||||
{ "system_quote", E_SYSTEM_QUOTE },
|
{ "system_quote", E_SYSTEM_QUOTE },
|
||||||
{ "shell_quote", E_SHELL_QUOTE },
|
{ "shell_quote", E_SHELL_QUOTE },
|
||||||
{ "getenv", E_GETENV },
|
{ "getenv", E_GETENV },
|
||||||
|
{ "read_registry", E_READ_REGISTRY },
|
||||||
};
|
};
|
||||||
statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0])));
|
statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0])));
|
||||||
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
|
for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i)
|
||||||
@@ -1265,6 +1270,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand(
|
|||||||
ret << val;
|
ret << val;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
case E_READ_REGISTRY: {
|
||||||
|
HKEY tree;
|
||||||
|
const auto par = args.at(0);
|
||||||
|
if (!par.compare(QLatin1String("HKCU"), Qt::CaseInsensitive)
|
||||||
|
|| !par.compare(QLatin1String("HKEY_CURRENT_USER"), Qt::CaseInsensitive)) {
|
||||||
|
tree = HKEY_CURRENT_USER;
|
||||||
|
} else if (!par.compare(QLatin1String("HKLM"), Qt::CaseInsensitive)
|
||||||
|
|| !par.compare(QLatin1String("HKEY_LOCAL_MACHINE"), Qt::CaseInsensitive)) {
|
||||||
|
tree = HKEY_LOCAL_MACHINE;
|
||||||
|
} else {
|
||||||
|
evalError(fL1S("read_registry(): invalid or unsupported registry tree %1.")
|
||||||
|
.arg(par.toQString()));
|
||||||
|
goto rrfail;
|
||||||
|
}
|
||||||
|
int flags = 0;
|
||||||
|
if (args.count() > 2) {
|
||||||
|
const auto opt = args.at(2);
|
||||||
|
if (opt == "32"
|
||||||
|
|| !opt.compare(QLatin1String("wow64_32key"), Qt::CaseInsensitive)) {
|
||||||
|
flags = KEY_WOW64_32KEY;
|
||||||
|
} else if (opt == "64"
|
||||||
|
|| !opt.compare(QLatin1String("wow64_64key"), Qt::CaseInsensitive)) {
|
||||||
|
flags = KEY_WOW64_64KEY;
|
||||||
|
} else {
|
||||||
|
evalError(fL1S("read_registry(): invalid option %1.")
|
||||||
|
.arg(opt.toQString()));
|
||||||
|
goto rrfail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret << ProString(qt_readRegistryKey(tree, args.at(1).toQString(m_tmp1), flags));
|
||||||
|
}
|
||||||
|
rrfail:
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1)));
|
evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1)));
|
||||||
break;
|
break;
|
||||||
|
158
src/shared/proparser/registry.cpp
Normal file
158
src/shared/proparser/registry.cpp
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the qmake application of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QtCore/qstringlist.h>
|
||||||
|
#include "registry_p.h"
|
||||||
|
|
||||||
|
namespace QMakeInternal {
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
/*
|
||||||
|
Returns the path part of a registry key.
|
||||||
|
e.g.
|
||||||
|
For a key
|
||||||
|
"Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"
|
||||||
|
it returns
|
||||||
|
"Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\"
|
||||||
|
*/
|
||||||
|
static QString keyPath(const QString &rKey)
|
||||||
|
{
|
||||||
|
int idx = rKey.lastIndexOf(QLatin1Char('\\'));
|
||||||
|
if (idx == -1)
|
||||||
|
return QString();
|
||||||
|
return rKey.left(idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns the name part of a registry key.
|
||||||
|
e.g.
|
||||||
|
For a key
|
||||||
|
"Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"
|
||||||
|
it returns
|
||||||
|
"ProductDir"
|
||||||
|
*/
|
||||||
|
static QString keyName(const QString &rKey)
|
||||||
|
{
|
||||||
|
int idx = rKey.lastIndexOf(QLatin1Char('\\'));
|
||||||
|
if (idx == -1)
|
||||||
|
return rKey;
|
||||||
|
|
||||||
|
QString res(rKey.mid(idx + 1));
|
||||||
|
if (res == QLatin1String("Default") || res == QLatin1String("."))
|
||||||
|
res = QString();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned long options)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
QString rSubkeyName = keyName(rSubkey);
|
||||||
|
QString rSubkeyPath = keyPath(rSubkey);
|
||||||
|
|
||||||
|
HKEY handle = nullptr;
|
||||||
|
LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0,
|
||||||
|
KEY_READ | options, &handle);
|
||||||
|
|
||||||
|
if (res != ERROR_SUCCESS)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
// get the size and type of the value
|
||||||
|
DWORD dataType;
|
||||||
|
DWORD dataSize;
|
||||||
|
res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, &dataType, nullptr, &dataSize);
|
||||||
|
if (res != ERROR_SUCCESS) {
|
||||||
|
RegCloseKey(handle);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the value
|
||||||
|
QByteArray data(dataSize, 0);
|
||||||
|
res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, nullptr,
|
||||||
|
reinterpret_cast<unsigned char*>(data.data()), &dataSize);
|
||||||
|
if (res != ERROR_SUCCESS) {
|
||||||
|
RegCloseKey(handle);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dataType) {
|
||||||
|
case REG_EXPAND_SZ:
|
||||||
|
case REG_SZ: {
|
||||||
|
result = QString::fromWCharArray(((const wchar_t *)data.constData()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REG_MULTI_SZ: {
|
||||||
|
QStringList l;
|
||||||
|
int i = 0;
|
||||||
|
for (;;) {
|
||||||
|
QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i);
|
||||||
|
i += s.length() + 1;
|
||||||
|
|
||||||
|
if (s.isEmpty())
|
||||||
|
break;
|
||||||
|
l.append(s);
|
||||||
|
}
|
||||||
|
result = l.join(QLatin1String(", "));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REG_NONE:
|
||||||
|
case REG_BINARY: {
|
||||||
|
result = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REG_DWORD_BIG_ENDIAN:
|
||||||
|
case REG_DWORD: {
|
||||||
|
Q_ASSERT(data.size() == sizeof(int));
|
||||||
|
int i;
|
||||||
|
memcpy((char*)&i, data.constData(), sizeof(int));
|
||||||
|
result = QString::number(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
qWarning("QSettings: unknown data %u type in windows registry", quint32(dataType));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(handle);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(parentHandle);
|
||||||
|
Q_UNUSED(rSubkey)
|
||||||
|
Q_UNUSED(options);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QMakeInternal
|
||||||
|
|
55
src/shared/proparser/registry_p.h
Normal file
55
src/shared/proparser/registry_p.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
#include <QtCore/qt_windows.h>
|
||||||
|
#else
|
||||||
|
typedef void* HKEY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QtCore/qstring.h>
|
||||||
|
|
||||||
|
namespace QMakeInternal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a value from the Windows registry.
|
||||||
|
*
|
||||||
|
* If the key is not found, or the registry cannot be accessed (for example
|
||||||
|
* if this code is compiled for a platform other than Windows), a null
|
||||||
|
* string is returned.
|
||||||
|
*
|
||||||
|
* 32-bit code reads from the registry's 32 bit view (Wow6432Node),
|
||||||
|
* 64 bit code reads from the 64 bit view.
|
||||||
|
* Pass KEY_WOW64_32KEY to access the 32 bit view regardless of the
|
||||||
|
* application's architecture, KEY_WOW64_64KEY respectively.
|
||||||
|
*/
|
||||||
|
QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey,
|
||||||
|
unsigned long options = 0);
|
||||||
|
|
||||||
|
} // namespace QMakeInternal
|
@@ -53,6 +53,29 @@ inline OutputIterator set_greedy_intersection(InputIterator1 first1,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
|
||||||
|
inline OutputIterator fill_with_second_values(InputIterator1 first1,
|
||||||
|
InputIterator1 last1,
|
||||||
|
InputIterator2 first2,
|
||||||
|
InputIterator2 last2,
|
||||||
|
OutputIterator result,
|
||||||
|
Compare comp)
|
||||||
|
{
|
||||||
|
while (first1 != last1 && first2 != last2)
|
||||||
|
if (comp(*first1, *first2)) {
|
||||||
|
*result = *first1;
|
||||||
|
++first1;
|
||||||
|
++result;
|
||||||
|
} else if (comp(*first2, *first1))
|
||||||
|
++first2;
|
||||||
|
else {
|
||||||
|
*result = *first2;
|
||||||
|
++first1;
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
class UsedMacroFilter
|
class UsedMacroFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -160,7 +183,7 @@ private:
|
|||||||
const Utils::SmallStringVector &usedMacros)
|
const Utils::SmallStringVector &usedMacros)
|
||||||
{
|
{
|
||||||
CompilerMacros filtertedCompilerMacros;
|
CompilerMacros filtertedCompilerMacros;
|
||||||
filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size());
|
filtertedCompilerMacros.reserve(usedMacros.size());
|
||||||
|
|
||||||
struct Compare
|
struct Compare
|
||||||
{
|
{
|
||||||
@@ -175,24 +198,13 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
set_greedy_intersection(indexedCompilerMacro.begin(),
|
fill_with_second_values(usedMacros.begin(),
|
||||||
|
usedMacros.end(),
|
||||||
|
indexedCompilerMacro.begin(),
|
||||||
indexedCompilerMacro.end(),
|
indexedCompilerMacro.end(),
|
||||||
usedMacros.begin(),
|
|
||||||
usedMacros.end(),
|
|
||||||
std::back_inserter(filtertedCompilerMacros),
|
std::back_inserter(filtertedCompilerMacros),
|
||||||
Compare{});
|
Compare{});
|
||||||
|
|
||||||
auto split = filtertedCompilerMacros.end();
|
|
||||||
|
|
||||||
std::set_difference(usedMacros.begin(),
|
|
||||||
usedMacros.end(),
|
|
||||||
filtertedCompilerMacros.begin(),
|
|
||||||
filtertedCompilerMacros.end(),
|
|
||||||
std::back_inserter(filtertedCompilerMacros),
|
|
||||||
Compare{});
|
|
||||||
|
|
||||||
std::inplace_merge(filtertedCompilerMacros.begin(), split, filtertedCompilerMacros.end());
|
|
||||||
|
|
||||||
return filtertedCompilerMacros;
|
return filtertedCompilerMacros;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5457,6 +5457,19 @@ void tst_Dumpers::dumper_data()
|
|||||||
+ Check("e.e2", "(E::b2 | E::c2) (3)", "E::Enum2")
|
+ Check("e.e2", "(E::b2 | E::c2) (3)", "E::Enum2")
|
||||||
+ Check("e.e3", "(E::b3 | E::c3) (3)", "E::Enum3");
|
+ Check("e.e3", "(E::b3 | E::c3) (3)", "E::Enum3");
|
||||||
|
|
||||||
|
QTest::newRow("QSizePolicy")
|
||||||
|
<< Data("#include <QSizePolicy>\n",
|
||||||
|
"QSizePolicy qsp1;\n"
|
||||||
|
"qsp1.setHorizontalStretch(6);\n"
|
||||||
|
"qsp1.setVerticalStretch(7);\n"
|
||||||
|
"QSizePolicy qsp2(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);\n")
|
||||||
|
+ GuiProfile()
|
||||||
|
+ NoCdbEngine
|
||||||
|
+ Check("qsp1.horStretch", "6", "int")
|
||||||
|
+ Check("qsp1.verStretch", "7", "int")
|
||||||
|
+ Check("qsp2.horPolicy", "QSizePolicy::Preferred (GrowFlag|ShrinkFlag) (5)", "@QSizePolicy::Policy")
|
||||||
|
+ Check("qsp2.verPolicy", "QSizePolicy::MinimumExpanding (GrowFlag|ExpandFlag) (3)", "@QSizePolicy::Policy");
|
||||||
|
|
||||||
|
|
||||||
QTest::newRow("Array")
|
QTest::newRow("Array")
|
||||||
<< Data("",
|
<< Data("",
|
||||||
|
@@ -18,7 +18,8 @@ QtcAutotest {
|
|||||||
"qmakeevaluator.h", "qmakeevaluator_p.h", "qmakeevaluator.cpp",
|
"qmakeevaluator.h", "qmakeevaluator_p.h", "qmakeevaluator.cpp",
|
||||||
"qmakeglobals.h", "qmakeglobals.cpp",
|
"qmakeglobals.h", "qmakeglobals.cpp",
|
||||||
"qmakeparser.h", "qmakeparser.cpp",
|
"qmakeparser.h", "qmakeparser.cpp",
|
||||||
"qmakevfs.h", "qmakevfs.cpp"
|
"qmakevfs.h", "qmakevfs.cpp",
|
||||||
|
"registry_p.h", "registry.cpp",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Group {
|
Group {
|
||||||
@@ -27,4 +28,8 @@ QtcAutotest {
|
|||||||
}
|
}
|
||||||
cpp.includePaths: base.concat([proParserGroup.prefix])
|
cpp.includePaths: base.concat([proParserGroup.prefix])
|
||||||
cpp.defines: base.concat("QT_USE_FAST_OPERATOR_PLUS")
|
cpp.defines: base.concat("QT_USE_FAST_OPERATOR_PLUS")
|
||||||
|
Properties {
|
||||||
|
condition: qbs.targetOS.contains("windows")
|
||||||
|
cpp.dynamicLibraries: "advapi32"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
using ClangBackEnd::FixItContainer;
|
using ClangBackEnd::FixItContainer;
|
||||||
using ClangCodeModel::ClangFixItOperation;
|
using ClangCodeModel::Internal::ClangFixItOperation;
|
||||||
|
|
||||||
using ::testing::PrintToString;
|
using ::testing::PrintToString;
|
||||||
|
|
||||||
|
@@ -331,6 +331,40 @@ TEST_F(ClangFormat, NoExtraIndentAfterBraceInitialization)
|
|||||||
"return 0;"));
|
"return 0;"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ClangFormat, IndentMultipleEmptyLines)
|
||||||
|
{
|
||||||
|
insertLines({"{",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"}"});
|
||||||
|
|
||||||
|
indenter.indent(cursor, QChar::Null, TextEditor::TabSettings());
|
||||||
|
|
||||||
|
ASSERT_THAT(documentLines(), ElementsAre("{",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ClangFormat, IndentEmptyLineAndKeepPreviousEmptyLines)
|
||||||
|
{
|
||||||
|
insertLines({"{",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"",
|
||||||
|
"}"});
|
||||||
|
|
||||||
|
indenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings());
|
||||||
|
|
||||||
|
ASSERT_THAT(documentLines(), ElementsAre("{",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
"}"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt)
|
TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt)
|
||||||
{
|
{
|
||||||
insertLines({"int foo(int a, int b,",
|
insertLines({"int foo(int a, int b,",
|
||||||
@@ -469,7 +503,7 @@ TEST_F(ClangFormat, FormatBasicFile)
|
|||||||
"int a;",
|
"int a;",
|
||||||
"}"});
|
"}"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 4}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("int main()",
|
ASSERT_THAT(documentLines(), ElementsAre("int main()",
|
||||||
"{",
|
"{",
|
||||||
@@ -484,7 +518,7 @@ TEST_F(ClangFormat, FormatEmptyLine)
|
|||||||
"",
|
"",
|
||||||
"}"});
|
"}"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 4}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("int main() {}"));
|
ASSERT_THAT(documentLines(), ElementsAre("int main() {}"));
|
||||||
}
|
}
|
||||||
@@ -495,7 +529,7 @@ TEST_F(ClangFormat, FormatLambda)
|
|||||||
"",
|
"",
|
||||||
"});"});
|
"});"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 3}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {",
|
ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {",
|
||||||
"",
|
"",
|
||||||
@@ -508,7 +542,7 @@ TEST_F(ClangFormat, FormatInitializerListInArguments)
|
|||||||
"args,",
|
"args,",
|
||||||
"{1, 2});"});
|
"{1, 2});"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 3}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("foo(arg1, args, {1, 2});"));
|
ASSERT_THAT(documentLines(), ElementsAre("foo(arg1, args, {1, 2});"));
|
||||||
}
|
}
|
||||||
@@ -520,7 +554,7 @@ TEST_F(ClangFormat, FormatFunctionArgumentLambdaWithScope)
|
|||||||
"",
|
"",
|
||||||
"});"});
|
"});"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 4}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(),
|
ASSERT_THAT(documentLines(),
|
||||||
ElementsAre("foo([]() {",
|
ElementsAre("foo([]() {",
|
||||||
@@ -535,7 +569,7 @@ TEST_F(ClangFormat, FormatScopeAsFunctionArgument)
|
|||||||
"",
|
"",
|
||||||
"});"});
|
"});"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 4}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(),
|
ASSERT_THAT(documentLines(),
|
||||||
ElementsAre("foo({",
|
ElementsAre("foo({",
|
||||||
@@ -548,7 +582,7 @@ TEST_F(ClangFormat, FormatStructuredBinding)
|
|||||||
insertLines({"auto [a,",
|
insertLines({"auto [a,",
|
||||||
"b] = c;"});
|
"b] = c;"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 2}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;"));
|
ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;"));
|
||||||
}
|
}
|
||||||
@@ -558,7 +592,7 @@ TEST_F(ClangFormat, FormatStringLiteralContinuation)
|
|||||||
insertLines({"foo(bar, \"foo\"",
|
insertLines({"foo(bar, \"foo\"",
|
||||||
"\"bar\");"});
|
"\"bar\");"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 2}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("foo(bar,",
|
ASSERT_THAT(documentLines(), ElementsAre("foo(bar,",
|
||||||
" \"foo\"",
|
" \"foo\"",
|
||||||
@@ -571,7 +605,7 @@ TEST_F(ClangFormat, FormatTemplateparameters)
|
|||||||
"B,",
|
"B,",
|
||||||
"C>"});
|
"C>"});
|
||||||
|
|
||||||
indenter.format(cursor);
|
indenter.format({{1, 3}});
|
||||||
|
|
||||||
ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template<A, B, C>"));
|
ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template<A, B, C>"));
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,7 @@ using ClangBackEnd::Document;
|
|||||||
using ClangBackEnd::Documents;
|
using ClangBackEnd::Documents;
|
||||||
using ClangBackEnd::UnsavedFiles;
|
using ClangBackEnd::UnsavedFiles;
|
||||||
using ClangBackEnd::ChunksReportedMonitor;
|
using ClangBackEnd::ChunksReportedMonitor;
|
||||||
|
using ClangCodeModel::Internal::HighlightingResultReporter;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ QVector<TokenInfoContainer> generateTokenInfos(uint count)
|
|||||||
|
|
||||||
TEST_F(HighlightingResultReporter, StartAndFinish)
|
TEST_F(HighlightingResultReporter, StartAndFinish)
|
||||||
{
|
{
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(noTokenInfos());
|
auto reporter = new ::HighlightingResultReporter(noTokenInfos());
|
||||||
|
|
||||||
auto future = reporter->start();
|
auto future = reporter->start();
|
||||||
|
|
||||||
@@ -96,7 +97,7 @@ TEST_F(HighlightingResultReporter, StartAndFinish)
|
|||||||
|
|
||||||
TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport)
|
TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport)
|
||||||
{
|
{
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(0));
|
auto reporter = new ::HighlightingResultReporter(generateTokenInfos(0));
|
||||||
|
|
||||||
auto future = reporter->start();
|
auto future = reporter->start();
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport)
|
|||||||
|
|
||||||
TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk)
|
TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk)
|
||||||
{
|
{
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(1));
|
auto reporter = new ::HighlightingResultReporter(generateTokenInfos(1));
|
||||||
reporter->setChunkSize(1);
|
reporter->setChunkSize(1);
|
||||||
|
|
||||||
auto future = reporter->start();
|
auto future = reporter->start();
|
||||||
@@ -117,7 +118,7 @@ TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk)
|
|||||||
|
|
||||||
TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached)
|
TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached)
|
||||||
{
|
{
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(1));
|
auto reporter = new ::HighlightingResultReporter(generateTokenInfos(1));
|
||||||
const int notReachedChunkSize = 100;
|
const int notReachedChunkSize = 100;
|
||||||
reporter->setChunkSize(notReachedChunkSize);
|
reporter->setChunkSize(notReachedChunkSize);
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached)
|
|||||||
|
|
||||||
TEST_F(HighlightingResultReporter, ReportChunksWithoutRest)
|
TEST_F(HighlightingResultReporter, ReportChunksWithoutRest)
|
||||||
{
|
{
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(4));
|
auto reporter = new ::HighlightingResultReporter(generateTokenInfos(4));
|
||||||
reporter->setChunkSize(1);
|
reporter->setChunkSize(1);
|
||||||
|
|
||||||
auto future = reporter->start();
|
auto future = reporter->start();
|
||||||
@@ -140,7 +141,7 @@ TEST_F(HighlightingResultReporter, ReportChunksWithoutRest)
|
|||||||
|
|
||||||
TEST_F(HighlightingResultReporter, ReportSingleChunkAndRest)
|
TEST_F(HighlightingResultReporter, ReportSingleChunkAndRest)
|
||||||
{
|
{
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(5));
|
auto reporter = new ::HighlightingResultReporter(generateTokenInfos(5));
|
||||||
reporter->setChunkSize(2);
|
reporter->setChunkSize(2);
|
||||||
|
|
||||||
auto future = reporter->start();
|
auto future = reporter->start();
|
||||||
@@ -158,7 +159,7 @@ TEST_F(HighlightingResultReporter, ReportCompleteLines)
|
|||||||
TokenInfoContainer(1, 2, 1, types),
|
TokenInfoContainer(1, 2, 1, types),
|
||||||
TokenInfoContainer(2, 1, 1, types),
|
TokenInfoContainer(2, 1, 1, types),
|
||||||
};
|
};
|
||||||
auto reporter = new ClangCodeModel::HighlightingResultReporter(tokenInfos);
|
auto reporter = new ::HighlightingResultReporter(tokenInfos);
|
||||||
reporter->setChunkSize(1);
|
reporter->setChunkSize(1);
|
||||||
|
|
||||||
auto future = reporter->start();
|
auto future = reporter->start();
|
||||||
|
@@ -33,6 +33,7 @@ CONFIG(release, debug|release):QMAKE_LFLAGS += -Wl,--strip-debug
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type
|
gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type
|
||||||
|
msvc: QMAKE_CXXFLAGS += /bigobj
|
||||||
|
|
||||||
# create fake CppTools.json for the mime type definitions
|
# create fake CppTools.json for the mime type definitions
|
||||||
dependencyList = "\"Dependencies\" : []"
|
dependencyList = "\"Dependencies\" : []"
|
||||||
|
Reference in New Issue
Block a user