diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 2d2cba492cd..e1d04a03f79 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -833,6 +833,14 @@ class DumperBase: self.putType('int') 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): with SubItem(self, name): self.putValue(value) @@ -855,8 +863,7 @@ class DumperBase: self.putField('keyencoded', key.encoding) self.putValue(value.value, value.encoding) - def putEnumValue(self, value, vals): - ival = value.integer() + def putEnumValue(self, ival, vals): nice = vals.get(ival, None) display = ('%d' % ival) if nice is None else ('%s (%d)' % (nice, ival)) self.putValue(display) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 2901c104010..6484d5f6838 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -194,7 +194,7 @@ def qdump_X_QModelIndex(d, value): #gdb.execute('call free($mi)') def qdump__Qt__ItemDataRole(d, value): - d.putEnumValue(value, { + d.putEnumValue(value.integer(), { 0 : "Qt::DisplayRole", 1 : "Qt::DecorationRole", 2 : "Qt::EditRole", @@ -1412,6 +1412,31 @@ def qdump__QSizeF(d, 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(): return arrayForms() diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 21fb3caf511..0d8009fef89 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -165,5 +165,27 @@ int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffe return utf8Offset; } +LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) +{ + Utils::LineColumn lineColumn; + lineColumn.line = static_cast( + 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 } // Utils diff --git a/src/libs/utils/textutils.h b/src/libs/utils/textutils.h index 895023903ee..fb0efe3f15f 100644 --- a/src/libs/utils/textutils.h +++ b/src/libs/utils/textutils.h @@ -59,5 +59,9 @@ QTCREATOR_UTILS_EXPORT int utf8NthLineOffset(const QTextDocument *textDocument, const QByteArray &buffer, int line); +QTCREATOR_UTILS_EXPORT LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset); +QTCREATOR_UTILS_EXPORT QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, + int currentUtf8Offset); + } // Text } // Utils diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp index 951c6efd530..702d4557b6b 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp @@ -48,6 +48,7 @@ #include namespace ClangCodeModel { +namespace Internal { ClangCurrentDocumentFilter::ClangCurrentDocumentFilter() { @@ -108,7 +109,6 @@ QList ClangCurrentDocumentFilter::matchesFor( if (!regexp.isValid()) return goodEntries; - using Internal::ClangEditorDocumentProcessor; ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(m_currentPath); if (!processor) return goodEntries; @@ -170,4 +170,5 @@ void ClangCurrentDocumentFilter::onCurrentEditorChanged(Core::IEditor *newCurren reset(); } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h index e355862bdf2..891905fbda0 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h @@ -30,6 +30,7 @@ namespace Core { class IEditor; } namespace ClangCodeModel { +namespace Internal { class ClangCurrentDocumentFilter : public Core::ILocatorFilter { @@ -53,4 +54,5 @@ private: QString m_currentPath; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp index 4811e1b5431..5151279a283 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp @@ -46,6 +46,7 @@ using namespace ClangCodeModel; using Internal::ClangDiagnosticWidget; +using Internal::ClangFixItOperation; namespace { @@ -87,7 +88,7 @@ void openEditorAt(const ClangBackEnd::DiagnosticContainer &diagnostic) void applyFixit(const ClangBackEnd::DiagnosticContainer &diagnostic) { - ClangCodeModel::ClangFixItOperation operation(Utf8String(), diagnostic.fixIts); + ClangFixItOperation operation(Utf8String(), diagnostic.fixIts); operation.perform(); } diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index 0d4195c538f..b892f393648 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -26,6 +26,7 @@ #include "clangeditordocumentparser.h" namespace ClangCodeModel { +namespace Internal { ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath) : BaseEditorDocumentParser(filePath) @@ -46,4 +47,5 @@ void ClangEditorDocumentParser::updateImpl(const QFutureInterface &, setState(state_); } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.h b/src/plugins/clangcodemodel/clangeditordocumentparser.h index 28dd52a46a9..a5b2ff27bfe 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.h +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.h @@ -28,6 +28,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangEditorDocumentParser : public CppTools::BaseEditorDocumentParser { @@ -41,4 +42,5 @@ private: const UpdateParams &updateParams) override; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangfixitoperation.cpp b/src/plugins/clangcodemodel/clangfixitoperation.cpp index b123c9af457..a7170dc8817 100644 --- a/src/plugins/clangcodemodel/clangfixitoperation.cpp +++ b/src/plugins/clangcodemodel/clangfixitoperation.cpp @@ -32,6 +32,7 @@ #include namespace ClangCodeModel { +namespace Internal { using FileToFixits = QMap>; using FileToFixitsIterator = QMapIterator>; @@ -50,7 +51,7 @@ int ClangFixItOperation::priority() const return 10; } -QString ClangCodeModel::ClangFixItOperation::description() const +QString ClangFixItOperation::description() const { return QStringLiteral("Apply Fix: ") + fixItText.toString(); } @@ -120,5 +121,5 @@ Utils::ChangeSet ClangFixItOperation::toChangeSet( return changeSet; } +} // namespace Internal } // namespace ClangCodeModel - diff --git a/src/plugins/clangcodemodel/clangfixitoperation.h b/src/plugins/clangcodemodel/clangfixitoperation.h index 4f37f3d4793..7caf0cf6523 100644 --- a/src/plugins/clangcodemodel/clangfixitoperation.h +++ b/src/plugins/clangcodemodel/clangfixitoperation.h @@ -34,13 +34,13 @@ #include #include -namespace TextEditor -{ +namespace TextEditor { class RefactoringChanges; class RefactoringFile; } namespace ClangCodeModel { +namespace Internal { class ClangFixItOperation : public TextEditor::QuickFixOperation { @@ -67,4 +67,5 @@ private: QVector fixItContainers; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp b/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp index 8ec6496794e..981a679a9bc 100644 --- a/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp +++ b/src/plugins/clangcodemodel/clangfixitoperationsextractor.cpp @@ -72,6 +72,7 @@ bool hasFixItAt(const QVector &fixits, } // anonymous namespace namespace ClangCodeModel { +namespace Internal { ClangFixItOperationsExtractor::ClangFixItOperationsExtractor( const QVector &diagnosticContainers) @@ -114,4 +115,5 @@ void ClangFixItOperationsExtractor::extractFromDiagnostic( } } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangfixitoperationsextractor.h b/src/plugins/clangcodemodel/clangfixitoperationsextractor.h index ee2da9a4b21..77b5643f8b3 100644 --- a/src/plugins/clangcodemodel/clangfixitoperationsextractor.h +++ b/src/plugins/clangcodemodel/clangfixitoperationsextractor.h @@ -30,6 +30,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangFixItOperationsExtractor { @@ -50,4 +51,5 @@ private: TextEditor::QuickFixOperations operations; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp index 27eeea1af4a..46bdbc33ea5 100644 --- a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp +++ b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp @@ -144,6 +144,7 @@ TextEditor::HighlightingResult toHighlightingResult( } // anonymous namespace ClangCodeModel { +namespace Internal { HighlightingResultReporter::HighlightingResultReporter( const QVector &tokenInfos) @@ -219,4 +220,5 @@ QFuture HighlightingResultReporter::start() return future; } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clanghighlightingresultreporter.h b/src/plugins/clangcodemodel/clanghighlightingresultreporter.h index 0f57bc10d8e..2c6e7a89a84 100644 --- a/src/plugins/clangcodemodel/clanghighlightingresultreporter.h +++ b/src/plugins/clangcodemodel/clanghighlightingresultreporter.h @@ -35,6 +35,7 @@ #include namespace ClangCodeModel { +namespace Internal { class HighlightingResultReporter: public QObject, @@ -67,4 +68,5 @@ private: unsigned m_flushLine = 0; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp index 07fdaba9e54..72c6c2dd09c 100644 --- a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp +++ b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp @@ -30,6 +30,7 @@ #include namespace ClangCodeModel { +namespace Internal { bool ClangPreprocessorAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const { @@ -156,4 +157,5 @@ bool ClangPreprocessorAssistProposalItem::isInclude() const || m_completionOperator == CPlusPlus::T_ANGLE_STRING_LITERAL; } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h index cbdb5383b04..1a5ee440a0d 100644 --- a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h +++ b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h @@ -31,6 +31,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangPreprocessorAssistProposalItem final : public TextEditor::AssistProposalItemInterface { @@ -68,4 +69,5 @@ private: mutable QChar m_typedCharacter; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.cpp b/src/plugins/clangcodemodel/clangrefactoringengine.cpp index bb985a650e4..ed9af84d660 100644 --- a/src/plugins/clangcodemodel/clangrefactoringengine.cpp +++ b/src/plugins/clangcodemodel/clangrefactoringengine.cpp @@ -30,13 +30,14 @@ #include namespace ClangCodeModel { +namespace Internal { void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, CppTools::ProjectPart *, RenameCallback &&renameSymbolsCallback) { - Internal::ClangEditorDocumentProcessor *processor = Internal::ClangEditorDocumentProcessor::get( - data.filePath().toString()); + ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get( + data.filePath().toString()); const int startRevision = data.cursor().document()->revision(); using ClangBackEnd::SourceLocationsContainer; @@ -79,4 +80,5 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, m_watcher->setFuture(cursorFuture); } -} +} // namespace Internal +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.h b/src/plugins/clangcodemodel/clangrefactoringengine.h index 79537f24df5..297c8ff2387 100644 --- a/src/plugins/clangcodemodel/clangrefactoringengine.h +++ b/src/plugins/clangcodemodel/clangrefactoringengine.h @@ -36,6 +36,7 @@ class RefactoringServerInterface; } namespace ClangCodeModel { +namespace Internal { class RefactoringEngine : public CppTools::RefactoringEngineInterface { @@ -60,4 +61,5 @@ private: std::unique_ptr m_watcher; }; +} // namespace Internal } // namespace ClangRefactoring diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index 61a4c7716c6..f756acf2d3e 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -48,9 +48,12 @@ #include #include +using namespace CppTools; +using namespace ClangCodeModel::Internal; using namespace Utils; namespace ClangCodeModel { +namespace Internal { namespace { @@ -75,9 +78,6 @@ static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity) ProjectExplorer::Project *projectForCurrentEditor() { - using namespace CppTools; - using namespace ClangCodeModel::Internal; - const QString filePath = Utils::currentCppEditorDocumentFilePath(); if (filePath.isEmpty()) return nullptr; @@ -90,35 +90,80 @@ ProjectExplorer::Project *projectForCurrentEditor() return nullptr; } -void disableDiagnosticInConfig(CppTools::ClangDiagnosticConfig &config, +enum class DiagnosticType { Clang, Tidy, Clazy }; +DiagnosticType diagnosticType(const ClangBackEnd::DiagnosticContainer &diagnostic) + +{ + if (!diagnostic.disableOption.isEmpty()) + return DiagnosticType::Clang; + + const Utils::DiagnosticTextInfo textInfo(diagnostic.text); + if (Utils::DiagnosticTextInfo::isClazyOption(textInfo.option())) + return DiagnosticType::Clazy; + return DiagnosticType::Tidy; +} + +void disableDiagnosticInConfig(ClangDiagnosticConfig &config, const ClangBackEnd::DiagnosticContainer &diagnostic) { - // Clang check - if (!diagnostic.disableOption.isEmpty()) { - config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption)); - return; - } - - // Clazy check 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()); QStringList newChecks = config.clazyChecks().split(','); newChecks.removeOne(checkName); config.setClazyChecks(newChecks.join(',')); - return; + break; } + } +} - // Tidy check - config.setClangTidyChecks(config.clangTidyChecks() + QString(",-") + textInfo.option()); +ClangDiagnosticConfig diagnosticConfig(ClangProjectSettings &projectSettings, + 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 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) { - using namespace CppTools; - using namespace ClangCodeModel::Internal; - ProjectExplorer::Project *project = projectForCurrentEditor(); QTC_ASSERT(project, return ); @@ -127,15 +172,9 @@ void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticConta project); const QSharedPointer globalSettings = codeModelSettings(); - // Get config id - Core::Id currentConfigId = projectSettings.warningConfigId(); - if (projectSettings.useGlobalConfig()) - currentConfigId = globalSettings->clangDiagnosticConfigId(); - // Get config + ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings); ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs()); - QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return ); - ClangDiagnosticConfig config = configsModel.configWithId(currentConfigId); // Create copy if needed if (config.isReadOnly()) { @@ -197,7 +236,6 @@ ClangTextMark::ClangTextMark(const FileName &fileName, QAction *action = new QAction(); action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon())); QObject::connect(action, &QAction::triggered, [diagnostic]() { - using namespace ClangCodeModel::Internal; const QString text = ClangDiagnosticWidget::createText({diagnostic}, ClangDiagnosticWidget::InfoBar); QApplication::clipboard()->setText(text, QClipboard::Clipboard); @@ -205,7 +243,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName, actions << action; // Remove diagnostic warning action - if (projectForCurrentEditor()) { + ProjectExplorer::Project *project = projectForCurrentEditor(); + if (project && isDiagnosticConfigChangable(project, diagnostic)) { action = new QAction(); action->setIcon(::Utils::Icons::BROKEN.icon()); QObject::connect(action, &QAction::triggered, [diagnostic]() { @@ -228,8 +267,6 @@ void ClangTextMark::updateIcon(bool valid) bool ClangTextMark::addToolTipContent(QLayout *target) const { - using Internal::ClangDiagnosticWidget; - QWidget *widget = ClangDiagnosticWidget::createWidget({m_diagnostic}, ClangDiagnosticWidget::ToolTip); target->addWidget(widget); @@ -243,5 +280,6 @@ void ClangTextMark::removedFromEditor() m_removedFromEditorHandler(this); } +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangtextmark.h b/src/plugins/clangcodemodel/clangtextmark.h index 00cadfb5c82..ae67bcef864 100644 --- a/src/plugins/clangcodemodel/clangtextmark.h +++ b/src/plugins/clangcodemodel/clangtextmark.h @@ -33,6 +33,7 @@ #include namespace ClangCodeModel { +namespace Internal { class ClangTextMark : public TextEditor::TextMark { @@ -56,4 +57,5 @@ private: RemovedFromEditorHandler m_removedFromEditorHandler; }; +} // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 6d06b058122..7a87eabcd79 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -36,10 +36,11 @@ namespace ClangFormat { -static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, - ReplacementsToKeep replacementsToKeep) +namespace { +void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, + ReplacementsToKeep replacementsToKeep) { - style.MaxEmptyLinesToKeep = 2; + style.MaxEmptyLinesToKeep = 100; style.SortIncludes = false; style.SortUsingDeclarations = false; @@ -56,33 +57,31 @@ static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, #endif } -static llvm::StringRef clearExtraNewline(llvm::StringRef text) +llvm::StringRef clearExtraNewline(llvm::StringRef text) { while (text.startswith("\n\n")) text = text.drop_front(); return text; } -static clang::tooling::Replacements filteredReplacements( - const QByteArray &buffer, - const clang::tooling::Replacements &replacements, - int utf8Offset, - int utf8Length, - int extraEmptySpaceOffset, - ReplacementsToKeep replacementsToKeep) +clang::tooling::Replacements filteredReplacements(const QByteArray &buffer, + const clang::tooling::Replacements &replacements, + int utf8Offset, + int utf8Length, + ReplacementsToKeep replacementsToKeep) { clang::tooling::Replacements filtered; for (const clang::tooling::Replacement &replacement : replacements) { int replacementOffset = static_cast(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) - replacementOffset += extraEmptySpaceOffset; + // Skip everything after. + 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 ? clearExtraNewline(replacement.getReplacementText()) @@ -106,17 +105,10 @@ static clang::tooling::Replacements filteredReplacements( return filtered; } -static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock) +void trimRHSWhitespace(const QTextBlock &block) { - QTextBlock prevBlock = currentBlock.previous(); - while (prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty()) - prevBlock = prevBlock.previous(); - - if (prevBlock.text().trimmed().isEmpty()) - return; - - const QString initialText = prevBlock.text(); - if (!initialText.at(initialText.size() - 1).isSpace()) + const QString initialText = block.text(); + if (!initialText.rbegin()->isSpace()) return; 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 int extraSpaceCount = static_cast(std::distance(initialText.rbegin(), lastNonSpace)); - QTextCursor cursor(prevBlock); + QTextCursor cursor(block); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, @@ -134,31 +126,25 @@ static void trimFirstNonEmptyBlock(const QTextBlock ¤tBlock) cursor.endEditBlock(); } -// Returns the total langth of previous lines with pure whitespace. -static int previousEmptyLinesLength(const QTextBlock ¤tBlock) -{ - 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) +// Add extra text in case of the empty line or the line starting with ')'. +// Track such extra pieces of text in isInsideModifiedLine(). +int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, [](const QChar &ch) { return !ch.isSpace(); }); + int utf8Offset = Utils::Text::utf8NthLineOffset(block.document(), + buffer, + block.blockNumber() + 1); if (firstNonWhitespace > 0) utf8Offset += firstNonWhitespace; + else + utf8Offset += blockText.length(); const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { //This extra text works for the most cases. QByteArray dummyText("a;a;"); @@ -174,6 +160,7 @@ static void modifyToIndentEmptyLines( dummyText = "&& a"; buffer.insert(utf8Offset, dummyText); + extraLength += dummyText.length(); } if (secondTry) { @@ -186,52 +173,45 @@ static void modifyToIndentEmptyLines( // unclosed parentheses. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); + extraLength += 1; } } + + return extraLength; } -static Utils::LineColumn utf16LineColumn(const QTextBlock &block, - 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. - const int lineStartUtf8Offset = utf8Offset == 0 - ? 0 - : utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; - int line = block.blockNumber() + 1; // Init with the line corresponding the block. - - if (utf8Offset < blockOffsetUtf8) { - line -= static_cast(std::count(utf8Buffer.begin() + lineStartUtf8Offset, - utf8Buffer.begin() + blockOffsetUtf8, - '\n')); - } else { - line += static_cast(std::count(utf8Buffer.begin() + blockOffsetUtf8, - utf8Buffer.begin() + lineStartUtf8Offset, - '\n')); - } - - const QByteArray lineText = utf8Buffer.mid(lineStartUtf8Offset, - utf8Offset - lineStartUtf8Offset); - return Utils::LineColumn(line, QString::fromUtf8(lineText).size() + 1); + // Detect the cases when we have inserted extra text into the line to get the indentation. + return originalLine.length() < modifiedLine.length() && column != modifiedLine.length() + 1 + && (column > originalLine.length() || originalLine.trimmed().isEmpty() + || !modifiedLine.startsWith(originalLine)); } -static TextEditor::Replacements utf16Replacements(const QTextBlock &block, - int blockOffsetUtf8, - const QByteArray &utf8Buffer, - const clang::tooling::Replacements &replacements) +TextEditor::Replacements utf16Replacements(const QTextDocument *doc, + const QByteArray &utf8Buffer, + const clang::tooling::Replacements &replacements) { TextEditor::Replacements convertedReplacements; convertedReplacements.reserve(replacements.size()); + for (const clang::tooling::Replacement &replacement : replacements) { - const Utils::LineColumn lineColUtf16 = utf16LineColumn(block, - blockOffsetUtf8, - utf8Buffer, - static_cast( - replacement.getOffset())); + Utils::LineColumn lineColUtf16 = Utils::Text::utf16LineColumn(utf8Buffer, + static_cast( + replacement.getOffset())); if (!lineColUtf16.isValid()) 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(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.column); const int utf16Length = QString::fromUtf8( @@ -246,7 +226,7 @@ static TextEditor::Replacements utf16Replacements(const QTextBlock &block, return convertedReplacements; } -static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements) +void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements) { if (replacements.empty()) return; @@ -266,33 +246,240 @@ static void applyReplacements(QTextDocument *doc, const TextEditor::Replacements } } -static QString selectedLines(QTextDocument *doc, - const QTextBlock &startBlock, - const QTextBlock &endBlock) +QString selectedLines(QTextDocument *doc, const QTextBlock &startBlock, const QTextBlock &endBlock) { - QString text = Utils::Text::textAt(QTextCursor(doc), - startBlock.position(), - std::max(0, - endBlock.position() + endBlock.length() - - startBlock.position() - 1)); - while (!text.isEmpty() && text.rbegin()->isSpace()) - text.chop(1); - return text; + return Utils::Text::textAt(QTextCursor(doc), + startBlock.position(), + std::max(0, + endBlock.position() + endBlock.length() + - startBlock.position() - 1)); } +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(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) : TextEditor::Indenter(doc) {} -TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks( - const QVector &blocks, - const TextEditor::TabSettings & /*tabSettings*/, - int cursorPositionInEditor) +TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer, + const QTextBlock &startBlock, + const QTextBlock &endBlock, + ReplacementsToKeep replacementsToKeep, + const QChar &typedChar, + bool secondTry) const { - TextEditor::IndentationForBlock ret; - for (QTextBlock block : blocks) - ret.insert(block.blockNumber(), indentFor(block, cursorPositionInEditor)); - return ret; + 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(utf8Offset + utf8Length - rangeStart); + std::vector ranges{{static_cast(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 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(utf8StartOffset), + static_cast(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) +{ + if (typedChar != QChar::Null && cursorPositionInEditor > 0 + && m_doc->characterAt(cursorPositionInEditor - 1) == typedChar + && doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) { + 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, @@ -324,120 +511,6 @@ void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor, 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 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(utf8StartOffset), - static_cast(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, const QChar &typedChar, const TextEditor::TabSettings & /*tabSettings*/, @@ -446,35 +519,40 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block, 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(replacement.text.size() - afterLineBreak); -} - int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings & /*tabSettings*/, 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 &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 @@ -527,97 +605,4 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const 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(utf8Offset + utf8Length - rangeStart); - - std::vector ranges{{static_cast(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 diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index 272cbd648fd..ed63ff6efa3 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -79,10 +79,12 @@ private: const QTextBlock &endBlock, const QChar &typedChar, 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, - int utf8Offset, - int utf8Length, const QTextBlock &startBlock, const QTextBlock &endBlock, ReplacementsToKeep replacementsToKeep, diff --git a/src/plugins/qtsupport/qtsupport.qbs b/src/plugins/qtsupport/qtsupport.qbs index 25cba7a70c5..123e0afda3f 100644 --- a/src/plugins/qtsupport/qtsupport.qbs +++ b/src/plugins/qtsupport/qtsupport.qbs @@ -19,6 +19,10 @@ Project { "QMAKE_LIBRARY", "QMAKE_BUILTIN_PRFS", ]) + Properties { + condition: qbs.targetOS.contains("windows") + cpp.dynamicLibraries: "advapi32" + } Export { Depends { name: "ProParser" } @@ -48,6 +52,8 @@ Project { "qmakeparser.h", "qmakevfs.cpp", "qmakevfs.h", + "registry.cpp", + "registry_p.h", ] } diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index 0552bd10972..f678ea9fb03 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -75,7 +75,12 @@ bool IoUtils::isRelativePath(const QString &path) && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) { 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 if (path.startsWith(QLatin1Char('/'))) return false; diff --git a/src/shared/proparser/proparser.pri b/src/shared/proparser/proparser.pri index 53ab86cf575..9bd8976dd7f 100644 --- a/src/shared/proparser/proparser.pri +++ b/src/shared/proparser/proparser.pri @@ -15,6 +15,7 @@ HEADERS += \ proitems.h \ prowriter.h \ qmakevfs.h \ + registry_p.h \ ioutils.h SOURCES += \ @@ -26,7 +27,9 @@ SOURCES += \ proitems.cpp \ prowriter.cpp \ qmakevfs.cpp \ + registry.cpp \ ioutils.cpp RESOURCES += proparser.qrc DEFINES += QMAKE_BUILTIN_PRFS QMAKE_OVERRIDE_PRFS +win32: LIBS *= -ladvapi32 diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 096524e6dcd..ea7e308cc50 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -31,6 +31,10 @@ #include "qmakevfs.h" #include "ioutils.h" +#ifdef Q_OS_WIN +# include "registry_p.h" +#endif + #include #include #include @@ -88,7 +92,7 @@ enum ExpandFunc { 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_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 { @@ -153,6 +157,7 @@ void QMakeEvaluator::initFunctionStatics() { "system_quote", E_SYSTEM_QUOTE }, { "shell_quote", E_SHELL_QUOTE }, { "getenv", E_GETENV }, + { "read_registry", E_READ_REGISTRY }, }; statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0]))); for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) @@ -1265,6 +1270,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( ret << val; } 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: evalError(fL1S("Function '%1' is not implemented.").arg(func.toQString(m_tmp1))); break; diff --git a/src/shared/proparser/registry.cpp b/src/shared/proparser/registry.cpp new file mode 100644 index 00000000000..960b6f8e580 --- /dev/null +++ b/src/shared/proparser/registry.cpp @@ -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 +#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(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 + diff --git a/src/shared/proparser/registry_p.h b/src/shared/proparser/registry_p.h new file mode 100644 index 00000000000..8defcbae959 --- /dev/null +++ b/src/shared/proparser/registry_p.h @@ -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 + +#ifdef Q_OS_WIN32 + #include +#else + typedef void* HKEY; +#endif + +#include + +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 diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index fe08cf71ac9..6042895325a 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -53,6 +53,29 @@ inline OutputIterator set_greedy_intersection(InputIterator1 first1, return result; } +template +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 { public: @@ -160,7 +183,7 @@ private: const Utils::SmallStringVector &usedMacros) { CompilerMacros filtertedCompilerMacros; - filtertedCompilerMacros.reserve(indexedCompilerMacro.size() + usedMacros.size()); + filtertedCompilerMacros.reserve(usedMacros.size()); struct Compare { @@ -175,24 +198,13 @@ private: } }; - set_greedy_intersection(indexedCompilerMacro.begin(), - indexedCompilerMacro.end(), - usedMacros.begin(), + fill_with_second_values(usedMacros.begin(), usedMacros.end(), + indexedCompilerMacro.begin(), + indexedCompilerMacro.end(), std::back_inserter(filtertedCompilerMacros), 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; } diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 780fa4ec472..63f0f25bf40 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5457,6 +5457,19 @@ void tst_Dumpers::dumper_data() + Check("e.e2", "(E::b2 | E::c2) (3)", "E::Enum2") + Check("e.e3", "(E::b3 | E::c3) (3)", "E::Enum3"); + QTest::newRow("QSizePolicy") + << Data("#include \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") << Data("", diff --git a/tests/auto/profilewriter/profilewriter.qbs b/tests/auto/profilewriter/profilewriter.qbs index 7091472f308..a6fb8ca8794 100644 --- a/tests/auto/profilewriter/profilewriter.qbs +++ b/tests/auto/profilewriter/profilewriter.qbs @@ -18,7 +18,8 @@ QtcAutotest { "qmakeevaluator.h", "qmakeevaluator_p.h", "qmakeevaluator.cpp", "qmakeglobals.h", "qmakeglobals.cpp", "qmakeparser.h", "qmakeparser.cpp", - "qmakevfs.h", "qmakevfs.cpp" + "qmakevfs.h", "qmakevfs.cpp", + "registry_p.h", "registry.cpp", ] } Group { @@ -27,4 +28,8 @@ QtcAutotest { } cpp.includePaths: base.concat([proParserGroup.prefix]) cpp.defines: base.concat("QT_USE_FAST_OPERATOR_PLUS") + Properties { + condition: qbs.targetOS.contains("windows") + cpp.dynamicLibraries: "advapi32" + } } diff --git a/tests/unit/unittest/clangfixitoperation-test.cpp b/tests/unit/unittest/clangfixitoperation-test.cpp index 21b250fdebb..e8fa178014b 100644 --- a/tests/unit/unittest/clangfixitoperation-test.cpp +++ b/tests/unit/unittest/clangfixitoperation-test.cpp @@ -34,7 +34,7 @@ #include using ClangBackEnd::FixItContainer; -using ClangCodeModel::ClangFixItOperation; +using ClangCodeModel::Internal::ClangFixItOperation; using ::testing::PrintToString; diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index ea702f71a6e..c0ff7dcd2ce 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -331,6 +331,40 @@ TEST_F(ClangFormat, NoExtraIndentAfterBraceInitialization) "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) { insertLines({"int foo(int a, int b,", @@ -469,7 +503,7 @@ TEST_F(ClangFormat, FormatBasicFile) "int a;", "}"}); - indenter.format(cursor); + indenter.format({{1, 4}}); 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() {}")); } @@ -495,7 +529,7 @@ TEST_F(ClangFormat, FormatLambda) "", "});"}); - indenter.format(cursor); + indenter.format({{1, 3}}); ASSERT_THAT(documentLines(), ElementsAre("int b = foo([]() {", "", @@ -508,7 +542,7 @@ TEST_F(ClangFormat, FormatInitializerListInArguments) "args,", "{1, 2});"}); - indenter.format(cursor); + indenter.format({{1, 3}}); 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(), ElementsAre("foo([]() {", @@ -535,7 +569,7 @@ TEST_F(ClangFormat, FormatScopeAsFunctionArgument) "", "});"}); - indenter.format(cursor); + indenter.format({{1, 4}}); ASSERT_THAT(documentLines(), ElementsAre("foo({", @@ -548,7 +582,7 @@ TEST_F(ClangFormat, FormatStructuredBinding) insertLines({"auto [a,", "b] = c;"}); - indenter.format(cursor); + indenter.format({{1, 2}}); ASSERT_THAT(documentLines(), ElementsAre("auto [a, b] = c;")); } @@ -558,7 +592,7 @@ TEST_F(ClangFormat, FormatStringLiteralContinuation) insertLines({"foo(bar, \"foo\"", "\"bar\");"}); - indenter.format(cursor); + indenter.format({{1, 2}}); ASSERT_THAT(documentLines(), ElementsAre("foo(bar,", " \"foo\"", @@ -571,7 +605,7 @@ TEST_F(ClangFormat, FormatTemplateparameters) "B,", "C>"}); - indenter.format(cursor); + indenter.format({{1, 3}}); ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template")); } diff --git a/tests/unit/unittest/highlightingresultreporter-test.cpp b/tests/unit/unittest/highlightingresultreporter-test.cpp index 29803783b17..dfe8dfbd2e0 100644 --- a/tests/unit/unittest/highlightingresultreporter-test.cpp +++ b/tests/unit/unittest/highlightingresultreporter-test.cpp @@ -43,6 +43,7 @@ using ClangBackEnd::Document; using ClangBackEnd::Documents; using ClangBackEnd::UnsavedFiles; using ClangBackEnd::ChunksReportedMonitor; +using ClangCodeModel::Internal::HighlightingResultReporter; namespace { @@ -86,7 +87,7 @@ QVector generateTokenInfos(uint count) TEST_F(HighlightingResultReporter, StartAndFinish) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(noTokenInfos()); + auto reporter = new ::HighlightingResultReporter(noTokenInfos()); auto future = reporter->start(); @@ -96,7 +97,7 @@ TEST_F(HighlightingResultReporter, StartAndFinish) TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(0)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(0)); auto future = reporter->start(); @@ -106,7 +107,7 @@ TEST_F(HighlightingResultReporter, ReportNothingIfNothingToReport) TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(1)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(1)); reporter->setChunkSize(1); auto future = reporter->start(); @@ -117,7 +118,7 @@ TEST_F(HighlightingResultReporter, ReportSingleResultAsOneChunk) TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(1)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(1)); const int notReachedChunkSize = 100; reporter->setChunkSize(notReachedChunkSize); @@ -129,7 +130,7 @@ TEST_F(HighlightingResultReporter, ReportRestIfChunkSizeNotReached) TEST_F(HighlightingResultReporter, ReportChunksWithoutRest) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(4)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(4)); reporter->setChunkSize(1); auto future = reporter->start(); @@ -140,7 +141,7 @@ TEST_F(HighlightingResultReporter, ReportChunksWithoutRest) TEST_F(HighlightingResultReporter, ReportSingleChunkAndRest) { - auto reporter = new ClangCodeModel::HighlightingResultReporter(generateTokenInfos(5)); + auto reporter = new ::HighlightingResultReporter(generateTokenInfos(5)); reporter->setChunkSize(2); auto future = reporter->start(); @@ -158,7 +159,7 @@ TEST_F(HighlightingResultReporter, ReportCompleteLines) TokenInfoContainer(1, 2, 1, types), TokenInfoContainer(2, 1, 1, types), }; - auto reporter = new ClangCodeModel::HighlightingResultReporter(tokenInfos); + auto reporter = new ::HighlightingResultReporter(tokenInfos); reporter->setChunkSize(1); auto future = reporter->start(); diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 634a0a0e2b5..e3c9430acf0 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -33,6 +33,7 @@ CONFIG(release, debug|release):QMAKE_LFLAGS += -Wl,--strip-debug } gcc:!clang: QMAKE_CXXFLAGS += -Wno-noexcept-type +msvc: QMAKE_CXXFLAGS += /bigobj # create fake CppTools.json for the mime type definitions dependencyList = "\"Dependencies\" : []"