diff options
Diffstat (limited to 'src')
119 files changed, 1385 insertions, 710 deletions
diff --git a/src/app/app.pro b/src/app/app.pro index 89b9554a9ff..712563419e6 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -5,8 +5,9 @@ TEMPLATE = app CONFIG += qtc_runnable sliced_bundle TARGET = $$IDE_APP_TARGET DESTDIR = $$IDE_APP_PATH -VERSION = $$QTCREATOR_VERSION QT -= testlib +# work around QTBUG-74265 +win32: VERSION= HEADERS += ../tools/qtcreatorcrashhandler/crashhandlersetup.h SOURCES += main.cpp ../tools/qtcreatorcrashhandler/crashhandlersetup.cpp diff --git a/src/libs/clangsupport/commandlinebuilder.h b/src/libs/clangsupport/commandlinebuilder.h index 7367f080360..9de1da68d3c 100644 --- a/src/libs/clangsupport/commandlinebuilder.h +++ b/src/libs/clangsupport/commandlinebuilder.h @@ -51,6 +51,7 @@ public: commandLine.reserve(1024); addCompiler(projectInfo.language); + disableWarnings(); addToolChainArguments(toolChainArguments); addExtraFlags(); addLanguage(projectInfo, sourceType); @@ -74,6 +75,8 @@ public: commandLine.emplace_back("clang"); } + void disableWarnings() { commandLine.emplace_back("-w"); } + void addToolChainArguments(const Utils::SmallStringVector &toolChainArguments) { for (Utils::SmallStringView argument : toolChainArguments) diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index cce203f0d44..f6d64a81d31 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -143,6 +143,8 @@ public: const Sqlite::Column &projectPartIdColumn = table.addColumn("projectPartId", Sqlite::ColumnType::Integer); const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); table.addColumn("sourceType", Sqlite::ColumnType::Integer); + table.addColumn("pchCreationTimeStamp", Sqlite::ColumnType::Integer); + table.addColumn("hasMissingIncludes", Sqlite::ColumnType::Integer); table.addUniqueIndex({sourceIdColumn, projectPartIdColumn}); table.addIndex({projectPartIdColumn}); @@ -168,11 +170,11 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("fileStatuses"); - table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("sourceId", + Sqlite::ColumnType::Integer, + Sqlite::Contraint::PrimaryKey); table.addColumn("size", Sqlite::ColumnType::Integer); table.addColumn("lastModified", Sqlite::ColumnType::Integer); - table.addColumn("buildDependencyTimeStamp", Sqlite::ColumnType::Integer); - table.addColumn("isInPrecompiledHeader", Sqlite::ColumnType::Integer); table.initialize(database); } diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index e176cbde355..6df396d8cfc 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -264,7 +264,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const break; } else if (tk.is(T_LPAREN) || tk.is(T_LBRACE)) { return scanner.startPosition() + tk.utf16charsBegin(); - } else if (tk.is(T_RPAREN)) { + } else if (tk.is(T_RPAREN) || tk.is(T_RBRACE)) { int matchingBrace = scanner.startOfMatchingBrace(index); if (matchingBrace == index) // If no matching brace found diff --git a/src/libs/libs.pro b/src/libs/libs.pro index 8bc99461a71..26495bbbf04 100644 --- a/src/libs/libs.pro +++ b/src/libs/libs.pro @@ -31,9 +31,27 @@ for(l, SUBDIRS) { } SUBDIRS += \ - utils/process_stub.pro \ - 3rdparty/syntax-highlighting \ - 3rdparty/syntax-highlighting/data + utils/process_stub.pro + +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + # enable short information message + KSYNTAX_WARN_ON = 1 +} + +include(../shared/syntax/syntax_shared.pri) +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + SUBDIRS += \ + 3rdparty/syntax-highlighting \ + 3rdparty/syntax-highlighting/data + + equals(KSYNTAX_WARN_ON, 1) { + message("Either KSYNTAXHIGHLIGHTING_LIB_DIR does not exist or include path could not be deduced.") + unset(KSYNTAX_WARN_ON) + } +} else { + message("Using KSyntaxHighlighting provided at $${KSYNTAXHIGHLIGHTING_LIB_DIR}.") +} win32:SUBDIRS += utils/process_ctrlc_stub.pro diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index a38a2fa906c..ea43a4dec86 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -748,8 +748,8 @@ void Check::endVisit(UiObjectInitializer *) { m_propertyStack.pop(); m_typeStack.pop(); - UiObjectDefinition *objectDenition = cast<UiObjectDefinition *>(parent()); - if (objectDenition && objectDenition->qualifiedTypeNameId->name == "Component") + UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent()); + if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == "Component") m_idStack.pop(); UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent()); if (objectBinding && objectBinding->qualifiedTypeNameId->name == "Component") diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp index 48e965d6fa8..a769484735c 100644 --- a/src/libs/ssh/sshremoteprocess.cpp +++ b/src/libs/ssh/sshremoteprocess.cpp @@ -69,7 +69,7 @@ SshRemoteProcess::SshRemoteProcess(const QByteArray &command, const QStringList connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this] { QString error; if (exitStatus() == QProcess::CrashExit) - error = tr("The ssh binary crashed: %1").arg(errorString()); + error = tr("The ssh process crashed: %1").arg(errorString()); else if (exitCode() == 255) error = tr("Remote process crashed."); emit done(error); diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 708595aa4d8..a476cd8d892 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -311,9 +311,10 @@ QString FileUtils::normalizePathName(const QString &name) if (FAILED(hr)) return name; TCHAR buffer[MAX_PATH]; - if (!SHGetPathFromIDList(file, buffer)) - return name; - return QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer))); + const bool success = SHGetPathFromIDList(file, buffer); + ILFree(file); + return success ? QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer))) + : name; #elif defined(Q_OS_OSX) return Internal::normalizePathName(name); #else // do not try to handle case-insensitive file systems on Linux diff --git a/src/libs/utils/jsontreeitem.cpp b/src/libs/utils/jsontreeitem.cpp index a70f5631ec8..16da8e803e6 100644 --- a/src/libs/utils/jsontreeitem.cpp +++ b/src/libs/utils/jsontreeitem.cpp @@ -63,9 +63,9 @@ QVariant Utils::JsonTreeItem::data(int column, int role) const if (column == 2) return typeName(m_value.type()); if (m_value.isObject()) - return QString('[' + QString::number(m_value.toObject().size()) + ' ' + tr("Items") + ']'); + return QString('[' + tr("%n Items", nullptr, m_value.toObject().size()) + ']'); if (m_value.isArray()) - return QString('[' + QString::number(m_value.toArray().size()) + ' ' + tr("Items") + ']'); + return QString('[' + tr("%n Items", nullptr, m_value.toArray().size()) + ']'); return m_value.toVariant(); } diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 0d8009fef89..ba10ca56ae4 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -171,7 +171,8 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) lineColumn.line = static_cast<int>( std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n')) + 1; - const int startOfLineOffset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; + const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1) + : 0; lineColumn.column = QString::fromUtf8( utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset)) .length() @@ -181,7 +182,9 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) { - const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1; + const int lineStartUtf8Offset = currentUtf8Offset + ? (utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1) + : 0; const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset); return QString::fromUtf8( utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset)); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 97b8e5de5b2..8ba60128755 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -101,7 +101,7 @@ public: setSummaryText(displayName()); auto uninstallPreviousPackage = new QCheckBox(this); - uninstallPreviousPackage->setText(tr("Uninstall previous package")); + uninstallPreviousPackage->setText(AndroidDeployQtStep::tr("Uninstall previous package")); uninstallPreviousPackage->setChecked(step->uninstallPreviousPackage() > AndroidDeployQtStep::Keep); uninstallPreviousPackage->setEnabled(step->uninstallPreviousPackage() != AndroidDeployQtStep::ForceUnintall); diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 11de94c3951..a4a1591cf47 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -68,13 +68,12 @@ void ClangCodeModelPlugin::generateCompilationDB() { using namespace CppTools; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); - if (!project) + if (!project || !project->activeTarget()) return; - m_generatorWatcher.setFuture(QtConcurrent::run( - &Utils::generateCompilationDB, - project->projectDirectory(), - CppModelManager::instance()->projectInfo(project))); + m_generatorWatcher.setFuture( + QtConcurrent::run(&Utils::generateCompilationDB, + CppModelManager::instance()->projectInfo(project))); } static bool isDBGenerationEnabled(ProjectExplorer::Project *project) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index db34c904d46..6f1397c4874 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -214,6 +214,9 @@ void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeComple setAsyncProposalAvailable(createFunctionHintProposal(completions)); return; } + + if (!m_fallbackToNormalCompletion) + return; // else: Proceed with a normal completion in case: // 1) it was not a function call, but e.g. a function declaration like "void f(" // 2) '{' meant not a constructor call. @@ -286,6 +289,14 @@ static QByteArray modifyInput(QTextDocument *doc, int endOfExpression) { return modifiedInput; } +static QChar lastPrecedingNonWhitespaceChar(const ClangCompletionAssistInterface *interface) +{ + int pos = interface->position(); + while (pos >= 0 && interface->characterAt(pos).isSpace()) + --pos; + return pos >= 0 ? interface->characterAt(pos) : QChar::Null; +} + IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() { ClangCompletionContextAnalyzer analyzer(m_interface.data(), m_interface->languageFeatures()); @@ -323,6 +334,8 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() } case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: { m_sentRequestType = FunctionHintCompletion; + if (lastPrecedingNonWhitespaceChar(m_interface.data()) == ',') + m_fallbackToNormalCompletion = false; m_requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray(), analyzer.functionNameStart()); break; diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h index 03711f0fa8f..5e8c772235e 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h @@ -97,6 +97,7 @@ private: CompletionRequestType m_sentRequestType = NormalCompletion; bool m_requestSent = false; bool m_addSnippets = false; // For type == Type::NormalCompletion + bool m_fallbackToNormalCompletion = true; }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp index ad48a60685b..a2c32a537ad 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp @@ -110,6 +110,8 @@ int ClangCompletionContextAnalyzer::startOfFunctionCall(int endOfOperator) const functionNameSelector.setPosition(functionNameStart); functionNameSelector.setPosition(index, QTextCursor::KeepAnchor); const QString functionName = functionNameSelector.selectedText().trimmed(); + if (functionName.isEmpty() && m_completionOperator == T_LBRACE) + return endOfOperator; return functionName.isEmpty() ? -1 : functionNameStart; } @@ -139,7 +141,10 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall() const int start = expressionUnderCursor.startOfFunctionCall(textCursor); m_positionEndOfExpression = start; m_positionForProposal = start + 1; // After '(' of function call - m_completionOperator = T_LPAREN; + if (m_interface->characterAt(start) == '(') + m_completionOperator = T_LPAREN; + else + m_completionOperator = T_LBRACE; } } diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 481b0774f8f..fa42dedf2df 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -34,12 +34,13 @@ #include <coreplugin/idocument.h> #include <cpptools/baseeditordocumentparser.h> #include <cpptools/compileroptionsbuilder.h> +#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppmodelmanager.h> +#include <cpptools/cpptoolsreuse.h> #include <cpptools/editordocumenthandle.h> #include <cpptools/projectpart.h> -#include <cpptools/cppcodemodelsettings.h> -#include <cpptools/cpptoolsreuse.h> #include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/kitinformation.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/target.h> @@ -300,12 +301,24 @@ QString diagnosticCategoryPrefixRemoved(const QString &text) return text; } -static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart) +static ::Utils::FileName compilerPath(const CppTools::ProjectPart &projectPart) { ProjectExplorer::Target *target = projectPart.project->activeTarget(); if (!target) return ::Utils::FileName(); + ProjectExplorer::ToolChain *toolchain = ProjectExplorer::ToolChainKitAspect::toolChain( + target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID); + + return toolchain->compilerCommand(); +} + +static ::Utils::FileName buildDirectory(const ProjectExplorer::Project &project) +{ + ProjectExplorer::Target *target = project.activeTarget(); + if (!target) + return ::Utils::FileName(); + ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration(); if (!buildConfig) return ::Utils::FileName(); @@ -313,42 +326,84 @@ static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart return buildConfig->buildDirectory(); } -static QJsonObject createFileObject(CompilerOptionsBuilder &optionsBuilder, - const ProjectFile &projFile, - const ::Utils::FileName &buildDir) +static QStringList projectPartArguments(const ProjectPart &projectPart) { - const ProjectFile::Kind kind = ProjectFile::classify(projFile.path); - optionsBuilder.updateFileLanguage(kind); + QStringList args; + args << compilerPath(projectPart).toString(); + args << "-c"; + if (projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { + args << "--target=" + projectPart.toolChainTargetTriple; + args << (projectPart.toolChainWordWidth == ProjectPart::WordWidth64Bit + ? QLatin1String("-m64") + : QLatin1String("-m32")); + } + args << projectPart.compilerFlags; + for (const ProjectExplorer::HeaderPath &headerPath : projectPart.headerPaths) { + if (headerPath.type == ProjectExplorer::HeaderPathType::User) { + args << "-I" + headerPath.path; + } else if (headerPath.type == ProjectExplorer::HeaderPathType::System) { + args << (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + ? "-I" + : "-isystem") + + headerPath.path; + } + } + for (const ProjectExplorer::Macro ¯o : projectPart.projectMacros) { + args.append(QString::fromUtf8( + macro.toKeyValue(macro.type == ProjectExplorer::MacroType::Define ? "-D" : "-U"))); + } + return args; +} + +static QJsonObject createFileObject(const ::Utils::FileName &buildDir, + const QStringList &arguments, + const ProjectPart &projectPart, + const ProjectFile &projFile) +{ QJsonObject fileObject; fileObject["file"] = projFile.path; - QJsonArray args = QJsonArray::fromStringList(optionsBuilder.options()); - args.prepend(kind == ProjectFile::CXXSource ? "clang++" : "clang"); + QJsonArray args = QJsonArray::fromStringList(arguments); + + const ProjectFile::Kind kind = ProjectFile::classify(projFile.path); + if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + || projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) { + if (ProjectFile::isC(kind)) + args.append("/TC"); + else if (ProjectFile::isCxx(kind)) + args.append("/TP"); + } else { + QStringList langOption + = createLanguageOptionGcc(kind, + projectPart.languageExtensions + & ::Utils::LanguageExtension::ObjectiveC); + for (const QString &langOptionPart : langOption) + args.append(langOptionPart); + } args.append(QDir::toNativeSeparators(projFile.path)); fileObject["arguments"] = args; fileObject["directory"] = buildDir.toString(); return fileObject; } -void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo) +void generateCompilationDB(CppTools::ProjectInfo projectInfo) { - QFile compileCommandsFile(projectDir.toString() + "/compile_commands.json"); + const ::Utils::FileName buildDir = buildDirectory(*projectInfo.project()); + QTC_ASSERT(!buildDir.isEmpty(), return;); + QDir dir(buildDir.toString()); + if (!dir.exists()) + dir.mkpath(dir.path()); + QFile compileCommandsFile(buildDir.toString() + "/compile_commands.json"); const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); if (!fileOpened) return; compileCommandsFile.write("["); - for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) { - const ::Utils::FileName buildDir = buildDirectory(*projectPart); - - CompilerOptionsBuilder optionsBuilder(*projectPart, - UseSystemHeader::No, - UseTweakedHeaderPaths::No); - optionsBuilder.build(CppTools::ProjectFile::Unclassified, - CppTools::UsePrecompiledHeaders::No); + for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) { + const QStringList args = projectPartArguments(*projectPart); for (const ProjectFile &projFile : projectPart->files) { - const QJsonObject json = createFileObject(optionsBuilder, projFile, buildDir); + const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile); if (compileCommandsFile.size() > 1) compileCommandsFile.write(","); compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed()); diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 4db869896b0..8ced14f5ad6 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -70,7 +70,7 @@ QString diagnosticCategoryPrefixRemoved(const QString &text); ::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token); -void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo); +void generateCompilationDB(CppTools::ProjectInfo projectInfo); class DiagnosticTextInfo { diff --git a/src/plugins/clangformat/ClangFormat.json.in b/src/plugins/clangformat/ClangFormat.json.in index 1c818c2f9e4..f270fea580e 100644 --- a/src/plugins/clangformat/ClangFormat.json.in +++ b/src/plugins/clangformat/ClangFormat.json.in @@ -2,7 +2,7 @@ \"Name\" : \"ClangFormat\", \"Version\" : \"$$QTCREATOR_VERSION\", \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", - \"Experimental\" : true, + \"DisabledByDefault\" : true, \"Vendor\" : \"The Qt Company Ltd\", \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", \"License\" : [ \"Commercial Usage\", diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index a53eb50adb2..dcb5edaeb13 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -29,9 +29,10 @@ #include <utils/algorithm.h> #include <utils/fileutils.h> -#include <utils/textutils.h> #include <utils/qtcassert.h> +#include <utils/textutils.h> +#include <QDebug> #include <QTextDocument> namespace ClangFormat { @@ -126,9 +127,85 @@ void trimRHSWhitespace(const QTextBlock &block) cursor.endEditBlock(); } +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; +} + +enum class CharacterContext { AfterComma, LastAfterComma, NewStatement, Continuation, Unknown }; + +QChar findFirstNonWhitespaceCharacter(const QTextBlock ¤tBlock) +{ + const QTextDocument *doc = currentBlock.document(); + int currentPos = currentBlock.position(); + while (currentPos < doc->characterCount() && doc->characterAt(currentPos).isSpace()) + ++currentPos; + return currentPos < doc->characterCount() ? doc->characterAt(currentPos) : QChar::Null; +} + +CharacterContext characterContext(const QTextBlock ¤tBlock, + const QTextBlock &previousNonEmptyBlock) +{ + const QString prevLineText = previousNonEmptyBlock.text().trimmed(); + const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); + if (prevLineText.endsWith(',')) { + // We don't need to add comma in case it's the last argument. + if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')') + return CharacterContext::LastAfterComma; + return CharacterContext::AfterComma; + } + + if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}') + || firstNonWhitespaceChar == QChar::Null) { + return CharacterContext::NewStatement; + } + + return CharacterContext::Continuation; +} + +bool nextBlockExistsAndEmpty(const QTextBlock ¤tBlock) +{ + QTextBlock nextBlock = currentBlock.next(); + if (!nextBlock.isValid() || nextBlock.position() == currentBlock.position()) + return false; + + return nextBlock.text().trimmed().isEmpty(); +} + +QByteArray dummyTextForContext(CharacterContext context, bool closingBraceBlock) +{ + if (closingBraceBlock + && (context == CharacterContext::NewStatement + || context == CharacterContext::Continuation)) { + return QByteArray(); + } + + switch (context) { + case CharacterContext::Unknown: + QTC_ASSERT(false, return "";); + case CharacterContext::AfterComma: + return "a,"; + case CharacterContext::NewStatement: + return "a;"; + case CharacterContext::Continuation: + case CharacterContext::LastAfterComma: + return "& a &"; + } +} + // 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) +int forceIndentWithExtraText(QByteArray &buffer, + CharacterContext &charContext, + const QTextBlock &block, + bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, @@ -143,26 +220,33 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + const bool closingBraceBlock = firstNonWhitespace >= 0 + && blockText.at(firstNonWhitespace) == '}'; int extraLength = 0; - if (firstNonWhitespace < 0 || closingParenBlock) { - //This extra text works for the most cases. - QByteArray dummyText("a;a;"); - - // Search for previous character - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); + QByteArray dummyText; + if (firstNonWhitespace < 0 && charContext != CharacterContext::Unknown + && nextBlockExistsAndEmpty(block)) { + // If the next line is also empty it's safer to use a comment line. + dummyText = "//"; + } else if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) { + if (charContext == CharacterContext::LastAfterComma) { + charContext = CharacterContext::AfterComma; + } else if (charContext == CharacterContext::Unknown || firstNonWhitespace >= 0) { + QTextBlock lastBlock = reverseFindLastEmptyBlock(block); + if (lastBlock.position() > 0) + lastBlock = lastBlock.previous(); + + // If we don't know yet the dummy text, let's guess it and use for this line and before. + charContext = characterContext(block, lastBlock); } - if (closingParenBlock || prevBlock.text().endsWith(',')) - dummyText = "&& a"; - buffer.insert(utf8Offset, dummyText); - extraLength += dummyText.length(); + dummyText = dummyTextForContext(charContext, closingBraceBlock); } + buffer.insert(utf8Offset, dummyText); + extraLength += dummyText.length(); + if (secondTry) { int nextLinePos = buffer.indexOf('\n', utf8Offset); if (nextLinePos < 0) @@ -170,7 +254,7 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s if (nextLinePos > 0) { // If first try was not successful try to put ')' in the end of the line to close possibly - // unclosed parentheses. + // unclosed parenthesis. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); extraLength += 1; @@ -300,18 +384,6 @@ bool doNotIndentInContext(QTextDocument *doc, int pos) 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) @@ -355,23 +427,14 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision()); adjustFormatStyleForLineBreak(style, replacementsToKeep); - if (typedChar == QChar::Null) { - if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { - if (utf8Offset > 0) { - buffer.insert(utf8Offset - 1, " //"); - utf8Offset += 3; - } + if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { + CharacterContext currentCharContext = CharacterContext::Unknown; + // Iterate backwards to reuse the same dummy text for all empty lines. + for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) { utf8Length += forceIndentWithExtraText(buffer, - cursorPositionInEditor < 0 - ? endBlock - : m_doc->findBlock(cursorPositionInEditor), + currentCharContext, + m_doc->findBlockByNumber(index), secondTry); - } else { - for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { - utf8Length += forceIndentWithExtraText(buffer, - m_doc->findBlockByNumber(index), - secondTry); - } } } @@ -432,9 +495,24 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( static_cast<unsigned int>(utf8RangeLength)); } + clang::format::FormatStyle style = styleForFile(); + const std::string assumedFileName = m_fileName.toString().toStdString(); + clang::tooling::Replacements clangReplacements = clang::format::sortIncludes(style, + buffer.data(), + ranges, + assumedFileName); + auto changedCode = clang::tooling::applyAllReplacements(buffer.data(), clangReplacements); + QTC_ASSERT(changedCode, { + qDebug() << QString::fromStdString(llvm::toString(changedCode.takeError())); + return TextEditor::Replacements(); + }); + ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges); + clang::format::FormattingAttemptStatus status; - const clang::tooling::Replacements clangReplacements - = reformat(styleForFile(), buffer.data(), ranges, m_fileName.toString().toStdString(), &status); + const clang::tooling::Replacements formatReplacements + = reformat(style, *changedCode, ranges, m_fileName.toString().toStdString(), &status); + clangReplacements = clangReplacements.merge(formatReplacements); + const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); applyReplacements(m_doc, toReplace); @@ -443,7 +521,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock, const QTextBlock &endBlock, - const QByteArray &buffer, const QChar &typedChar, int cursorPositionInEditor) { @@ -461,10 +538,12 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo cursorPositionInEditor += startBlock.position() - startBlockPosition; } + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; if (formatWhileTyping() && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) - && (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) { + && (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. @@ -487,9 +566,7 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock, const QChar &typedChar, int cursorPositionInEditor) { - const QByteArray buffer = m_doc->toPlainText().toUtf8(); - applyReplacements(m_doc, - indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor)); + applyReplacements(m_doc, indentsFor(startBlock, endBlock, typedChar, cursorPositionInEditor)); } void ClangFormatBaseIndenter::indent(const QTextCursor &cursor, @@ -533,15 +610,14 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings & /*tabSettings*/, int cursorPositionInEditor) { - const QByteArray buffer = m_doc->toPlainText().toUtf8(); TextEditor::Replacements toReplace = indentsFor(block, block, - buffer, QChar::Null, cursorPositionInEditor); if (toReplace.empty()) return -1; + const QByteArray buffer = m_doc->toPlainText().toUtf8(); return indentationForBlock(toReplace, buffer, block); } @@ -553,13 +629,12 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks( 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); + const QByteArray buffer = m_doc->toPlainText().toUtf8(); for (const QTextBlock &block : blocks) ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block)); return ret; diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index b412b57d6d4..87b5e0c927b 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -81,7 +81,6 @@ private: int cursorPositionInEditor); TextEditor::Replacements indentsFor(QTextBlock startBlock, const QTextBlock &endBlock, - const QByteArray &buffer, const QChar &typedChar, int cursorPositionInEditor); TextEditor::Replacements replacements(QByteArray buffer, diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index faaf6d937ff..72e1778999a 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -59,6 +59,24 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje { m_ui->setupUi(this); + m_preview = new TextEditor::SnippetEditorWidget(this); + m_ui->horizontalLayout_2->addWidget(m_preview); + if (m_project) { + m_ui->applyButton->show(); + hideGlobalCheckboxes(); + m_ui->overrideDefault->setChecked( + m_project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool()); + } else { + m_ui->applyButton->hide(); + showGlobalCheckboxes(); + m_ui->overrideDefault->setChecked(ClangFormatSettings::instance().overrideDefaultFile()); + } + + connect(m_ui->overrideDefault, &QCheckBox::toggled, this, [this](bool checked) { + if (checked) + createStyleFileIfNeeded(!m_project); + initialize(); + }); initialize(); } @@ -81,15 +99,19 @@ void ClangFormatConfigWidget::showGlobalCheckboxes() m_ui->formatOnSave->show(); } +static bool projectConfigExists() +{ + return Utils::FileName::fromString(Core::ICore::userResourcePath()) + .appendPath("clang-format") + .appendPath(currentProjectUniqueId()) + .appendPath((Constants::SETTINGS_FILE_NAME)) + .exists(); +} + void ClangFormatConfigWidget::initialize() { - m_ui->projectHasClangFormat->show(); - m_ui->clangFormatOptionsTable->show(); - m_ui->applyButton->show(); - hideGlobalCheckboxes(); + m_ui->projectHasClangFormat->hide(); - m_preview = new TextEditor::SnippetEditorWidget(this); - m_ui->horizontalLayout_2->addWidget(m_preview); m_preview->setPlainText(QLatin1String(CppTools::Constants::DEFAULT_CODE_STYLE_SNIPPETS[0])); m_preview->textDocument()->setIndenter(new ClangFormatIndenter(m_preview->document())); m_preview->textDocument()->setFontSettings(TextEditor::TextEditorSettings::fontSettings()); @@ -103,21 +125,15 @@ void ClangFormatConfigWidget::initialize() if (lastItem->spacerItem()) m_ui->verticalLayout->removeItem(lastItem); - if (m_project - && !m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).exists()) { - m_ui->projectHasClangFormat->setText(tr("No .clang-format file for the project.")); + if (!m_ui->overrideDefault->isChecked()) { m_ui->clangFormatOptionsTable->hide(); - m_ui->applyButton->hide(); + m_preview->hide(); m_ui->verticalLayout->addStretch(1); - - connect(m_ui->createFileButton, &QPushButton::clicked, this, [this]() { - createStyleFileIfNeeded(false); - initialize(); - }); return; } - m_ui->createFileButton->hide(); + m_ui->clangFormatOptionsTable->show(); + m_preview->show(); Utils::FileName fileName; if (m_project) { @@ -126,19 +142,13 @@ void ClangFormatConfigWidget::initialize() fileName = m_project->projectFilePath().appendPath("snippet.cpp"); } else { const Project *currentProject = SessionManager::startupProject(); - if (!currentProject - || !currentProject->projectDirectory() - .appendPath(Constants::SETTINGS_FILE_NAME) - .exists()) { + if (!currentProject || !projectConfigExists()) { m_ui->projectHasClangFormat->hide(); } else { m_ui->projectHasClangFormat->setText( - tr("Current project has its own .clang-format file " + tr("Current project has its own overridden .clang-format file " "and can be configured in Projects > Code Style > C++.")); } - createStyleFileIfNeeded(true); - showGlobalCheckboxes(); - m_ui->applyButton->hide(); fileName = Utils::FileName::fromString(Core::ICore::userResourcePath()) .appendPath("snippet.cpp"); } @@ -160,7 +170,7 @@ void ClangFormatConfigWidget::fillTable() { clang::format::FormatStyle style = m_project ? currentProjectStyle() : currentGlobalStyle(); - std::string configText = clang::format::configurationAsText(style); + const std::string configText = clang::format::configurationAsText(style); m_ui->clangFormatOptionsTable->setPlainText(QString::fromStdString(configText)); } @@ -168,13 +178,19 @@ ClangFormatConfigWidget::~ClangFormatConfigWidget() = default; void ClangFormatConfigWidget::apply() { + ClangFormatSettings &settings = ClangFormatSettings::instance(); if (!m_project) { - ClangFormatSettings &settings = ClangFormatSettings::instance(); settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked()); settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked()); settings.setFormatOnSave(m_ui->formatOnSave->isChecked()); - settings.write(); + settings.setOverrideDefaultFile(m_ui->overrideDefault->isChecked()); + } else { + m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, m_ui->overrideDefault->isChecked()); } + settings.write(); + + if (!m_ui->overrideDefault->isChecked()) + return; const QString text = m_ui->clangFormatOptionsTable->toPlainText(); clang::format::FormatStyle style; @@ -184,16 +200,18 @@ void ClangFormatConfigWidget::apply() QMessageBox::warning(this, tr("Error in ClangFormat configuration"), QString::fromStdString(error.message())); - fillTable(); - updatePreview(); + if (m_ui->overrideDefault->isChecked()) { + fillTable(); + updatePreview(); + } return; } - QString filePath; + QString filePath = Core::ICore::userResourcePath(); if (m_project) - filePath = m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).toString(); - else - filePath = Core::ICore::userResourcePath() + "/" + Constants::SETTINGS_FILE_NAME; + filePath += "/clang-format/" + currentProjectUniqueId(); + filePath += "/" + QLatin1String(Constants::SETTINGS_FILE_NAME); + QFile file(filePath); if (!file.open(QFile::WriteOnly)) return; @@ -201,7 +219,8 @@ void ClangFormatConfigWidget::apply() file.write(text.toUtf8()); file.close(); - updatePreview(); + if (m_ui->overrideDefault->isChecked()) + updatePreview(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index 41e40ef1fdc..c8225981f59 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -55,6 +55,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="overrideDefault"> + <property name="text"> + <string>Override Clang Format configuration file</string> + </property> + </widget> + </item> + <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QPlainTextEdit" name="clangFormatOptionsTable"/> @@ -64,13 +71,6 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QPushButton" name="createFileButton"> - <property name="text"> - <string>Create Clang Format Configuration File</string> - </property> - </widget> - </item> - <item> <widget class="QPushButton" name="applyButton"> <property name="text"> <string>Apply</string> diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 8b7cbcf9bd2..2635dbedeac 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -34,5 +34,7 @@ static const char SETTINGS_ID[] = "ClangFormat"; static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; +static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile"; +static const char OPEN_CURRENT_CONFIG_ID[] = "ClangFormat.OpenCurrentConfig"; } // namespace Constants } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 42cedb7b6c9..381762ee7f2 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -57,7 +57,7 @@ bool ClangFormatIndenter::formatWhileTyping() const Utils::optional<TabSettings> ClangFormatIndenter::tabSettings() const { - FormatStyle style = currentProjectStyle(); + FormatStyle style = styleForFile(); TabSettings tabSettings; switch (style.UseTab) { diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp index 932234f9822..e82802ab303 100644 --- a/src/plugins/clangformat/clangformatplugin.cpp +++ b/src/plugins/clangformat/clangformatplugin.cpp @@ -26,16 +26,23 @@ #include "clangformatplugin.h" #include "clangformatconfigwidget.h" +#include "clangformatconstants.h" #include "clangformatindenter.h" +#include "clangformatutils.h" #include <utils/qtcassert.h> -#include <coreplugin/icore.h> -#include <coreplugin/icontext.h> +#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/command.h> -#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/coreconstants.h> +#include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/editormanager/ieditor.h> +#include <coreplugin/icontext.h> +#include <coreplugin/icore.h> +#include <coreplugin/idocument.h> + +#include <cppeditor/cppeditorconstants.h> #include <cpptools/cppcodestylepreferencesfactory.h> #include <cpptools/cpptoolsconstants.h> @@ -103,6 +110,48 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS Q_UNUSED(errorString); #ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED replaceCppCodeStyle(); + + Core::ActionContainer *contextMenu = Core::ActionManager::actionContainer( + CppEditor::Constants::M_CONTEXT); + if (contextMenu) { + auto openClangFormatConfigAction + = new QAction(tr("Open Used .clang-format Configuration File"), this); + Core::Command *command + = Core::ActionManager::registerAction(openClangFormatConfigAction, + Constants::OPEN_CURRENT_CONFIG_ID); + contextMenu->addSeparator(); + contextMenu->addAction(command); + + if (Core::EditorManager::currentEditor()) { + const Core::IDocument *doc = Core::EditorManager::currentEditor()->document(); + if (doc) + openClangFormatConfigAction->setData(doc->filePath().toString()); + } + + connect(openClangFormatConfigAction, + &QAction::triggered, + this, + [openClangFormatConfigAction]() { + const QString fileName = openClangFormatConfigAction->data().toString(); + if (!fileName.isEmpty()) { + const QString clangFormatConfigPath = configForFile( + Utils::FileName::fromString(fileName)); + Core::EditorManager::openEditor(clangFormatConfigPath); + } + }); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::currentEditorChanged, + this, + [openClangFormatConfigAction](Core::IEditor *editor) { + if (!editor) + return; + + const Core::IDocument *doc = editor->document(); + if (doc) + openClangFormatConfigAction->setData(doc->filePath().toString()); + }); + } #endif return true; } diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp index 8be2b3cefee..8f70130ae3a 100644 --- a/src/plugins/clangformat/clangformatsettings.cpp +++ b/src/plugins/clangformat/clangformatsettings.cpp @@ -46,6 +46,8 @@ ClangFormatSettings::ClangFormatSettings() .toBool(); m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false) .toBool(); + m_overrideDefaultFile = settings->value(QLatin1String(Constants::OVERRIDE_FILE_ID), false) + .toBool(); settings->endGroup(); } @@ -57,6 +59,7 @@ void ClangFormatSettings::write() const m_formatCodeInsteadOfIndent); settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping); settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave); + settings->setValue(QLatin1String(Constants::OVERRIDE_FILE_ID), m_overrideDefaultFile); settings->endGroup(); } @@ -90,4 +93,14 @@ bool ClangFormatSettings::formatOnSave() const return m_formatOnSave; } +void ClangFormatSettings::setOverrideDefaultFile(bool enable) +{ + m_overrideDefaultFile = enable; +} + +bool ClangFormatSettings::overrideDefaultFile() const +{ + return m_overrideDefaultFile; +} + } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h index 0ea9ed9747e..9344cf34a96 100644 --- a/src/plugins/clangformat/clangformatsettings.h +++ b/src/plugins/clangformat/clangformatsettings.h @@ -25,6 +25,8 @@ #pragma once +#include <QString> + namespace ClangFormat { class ClangFormatSettings @@ -43,10 +45,14 @@ public: void setFormatOnSave(bool enable); bool formatOnSave() const; + + void setOverrideDefaultFile(bool enable); + bool overrideDefaultFile() const; private: bool m_formatCodeInsteadOfIndent = false; bool m_formatWhileTyping = false; bool m_formatOnSave = false; + bool m_overrideDefaultFile = false; }; } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index babe94da24f..74c4165a34b 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -26,6 +26,7 @@ #include "clangformatutils.h" #include "clangformatconstants.h" +#include "clangformatsettings.h" #include <coreplugin/icore.h> #include <cpptools/cppcodestylesettings.h> @@ -33,6 +34,8 @@ #include <projectexplorer/project.h> #include <projectexplorer/session.h> +#include <QCryptographicHash> + using namespace clang; using namespace format; using namespace llvm; @@ -42,6 +45,104 @@ using namespace TextEditor; namespace ClangFormat { +static clang::format::FormatStyle qtcStyle() +{ + clang::format::FormatStyle style = getLLVMStyle(); + style.Language = FormatStyle::LK_Cpp; + style.AccessModifierOffset = -4; + style.AlignAfterOpenBracket = FormatStyle::BAS_Align; + style.AlignConsecutiveAssignments = false; + style.AlignConsecutiveDeclarations = false; + style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; + style.AlignOperands = true; + style.AlignTrailingComments = true; + style.AllowAllParametersOfDeclarationOnNextLine = true; + style.AllowShortBlocksOnASingleLine = false; + style.AllowShortCaseLabelsOnASingleLine = false; + style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; + style.AllowShortIfStatementsOnASingleLine = false; + style.AllowShortLoopsOnASingleLine = false; + style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + style.AlwaysBreakBeforeMultilineStrings = false; + style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; + style.BinPackArguments = false; + style.BinPackParameters = false; + style.BraceWrapping.AfterClass = true; + style.BraceWrapping.AfterControlStatement = false; + style.BraceWrapping.AfterEnum = false; + style.BraceWrapping.AfterFunction = true; + style.BraceWrapping.AfterNamespace = false; + style.BraceWrapping.AfterObjCDeclaration = false; + style.BraceWrapping.AfterStruct = true; + style.BraceWrapping.AfterUnion = false; + style.BraceWrapping.BeforeCatch = false; + style.BraceWrapping.BeforeElse = false; + style.BraceWrapping.IndentBraces = false; + style.BraceWrapping.SplitEmptyFunction = false; + style.BraceWrapping.SplitEmptyRecord = false; + style.BraceWrapping.SplitEmptyNamespace = false; + style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; + style.BreakBeforeBraces = FormatStyle::BS_Custom; + style.BreakBeforeTernaryOperators = true; + style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; + style.BreakAfterJavaFieldAnnotations = false; + style.BreakStringLiterals = true; + style.ColumnLimit = 100; + style.CommentPragmas = "^ IWYU pragma:"; + style.CompactNamespaces = false; + style.ConstructorInitializerAllOnOneLineOrOnePerLine = false; + style.ConstructorInitializerIndentWidth = 4; + style.ContinuationIndentWidth = 4; + style.Cpp11BracedListStyle = true; + style.DerivePointerAlignment = false; + style.DisableFormat = false; + style.ExperimentalAutoDetectBinPacking = false; + style.FixNamespaceComments = true; + style.ForEachMacros = {"forever", "foreach", "Q_FOREACH", "BOOST_FOREACH"}; + style.IncludeStyle.IncludeCategories = {{"^<Q.*", 200}}; + style.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; + style.IndentCaseLabels = false; + style.IndentWidth = 4; + style.IndentWrappedFunctionNames = false; + style.JavaScriptQuotes = FormatStyle::JSQS_Leave; + style.JavaScriptWrapImports = true; + style.KeepEmptyLinesAtTheStartOfBlocks = false; + // Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between. + style.MacroBlockBegin = ""; + style.MacroBlockEnd = ""; + style.MaxEmptyLinesToKeep = 1; + style.NamespaceIndentation = FormatStyle::NI_None; + style.ObjCBlockIndentWidth = 4; + style.ObjCSpaceAfterProperty = false; + style.ObjCSpaceBeforeProtocolList = true; + style.PenaltyBreakAssignment = 150; + style.PenaltyBreakBeforeFirstCallParameter = 300; + style.PenaltyBreakComment = 500; + style.PenaltyBreakFirstLessLess = 400; + style.PenaltyBreakString = 600; + style.PenaltyExcessCharacter = 50; + style.PenaltyReturnTypeOnItsOwnLine = 300; + style.PointerAlignment = FormatStyle::PAS_Right; + style.ReflowComments = false; + style.SortIncludes = true; + style.SortUsingDeclarations = true; + style.SpaceAfterCStyleCast = true; + style.SpaceAfterTemplateKeyword = false; + style.SpaceBeforeAssignmentOperators = true; + style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; + style.SpaceInEmptyParentheses = false; + style.SpacesBeforeTrailingComments = 1; + style.SpacesInAngles = false; + style.SpacesInContainerLiterals = false; + style.SpacesInCStyleCastParentheses = false; + style.SpacesInParentheses = false; + style.SpacesInSquareBrackets = false; + style.Standard = FormatStyle::LS_Cpp11; + style.TabWidth = 4; + style.UseTab = FormatStyle::UT_Never; + return style; +} + static void applyTabSettings(clang::format::FormatStyle &style, const TabSettings &settings) { style.IndentWidth = static_cast<unsigned>(settings.m_indentSize); @@ -63,72 +164,86 @@ static void applyTabSettings(clang::format::FormatStyle &style, const TabSetting } } -static void applyCppCodeStyleSettings(clang::format::FormatStyle &style, - const CppCodeStyleSettings &settings) +static bool useGlobalOverriddenSettings() { - style.IndentCaseLabels = settings.indentSwitchLabels; - style.AlignOperands = settings.alignAssignments; - style.NamespaceIndentation = FormatStyle::NI_None; - if (settings.indentNamespaceBody) - style.NamespaceIndentation = FormatStyle::NI_All; + return ClangFormatSettings::instance().overrideDefaultFile(); +} - style.BraceWrapping.IndentBraces = false; - if (settings.indentBlockBraces) { - if (settings.indentClassBraces && settings.indentEnumBraces - && settings.indentNamespaceBraces && settings.indentFunctionBraces) { - style.BraceWrapping.IndentBraces = true; - } else { - style.BreakBeforeBraces = FormatStyle::BS_GNU; - } - } +QString currentProjectUniqueId() +{ + const Project *project = SessionManager::startupProject(); + if (!project) + return QString(); - if (settings.bindStarToIdentifier || settings.bindStarToRightSpecifier) - style.PointerAlignment = FormatStyle::PAS_Right; - else - style.PointerAlignment = FormatStyle::PAS_Left; + return QString::fromUtf8(QCryptographicHash::hash(project->projectFilePath().toString().toUtf8(), + QCryptographicHash::Md5) + .toHex(0)); +} + +static bool useProjectOverriddenSettings() +{ + const Project *project = SessionManager::startupProject(); + return project ? project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool() : false; +} - style.AccessModifierOffset = settings.indentAccessSpecifiers - ? 0 - : - static_cast<int>(style.IndentWidth); +static Utils::FileName globalPath() +{ + return Utils::FileName::fromString(Core::ICore::userResourcePath()); } static Utils::FileName projectPath() { const Project *project = SessionManager::startupProject(); if (project) - return project->projectDirectory(); + return globalPath().appendPath("clang-format").appendPath(currentProjectUniqueId()); return Utils::FileName(); } -static Utils::FileName globalPath() +static QString findConfig(Utils::FileName fileName) { - return Utils::FileName::fromString(Core::ICore::userResourcePath()); + QDir parentDir(fileName.parentDir().toString()); + while (!parentDir.exists(Constants::SETTINGS_FILE_NAME) + && !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { + if (!parentDir.cdUp()) + return QString(); + } + + if (parentDir.exists(Constants::SETTINGS_FILE_NAME)) + return parentDir.filePath(Constants::SETTINGS_FILE_NAME); + return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); } -static QString configForFile(Utils::FileName fileName) +static QString configForFile(Utils::FileName fileName, bool checkForSettings) { - Utils::FileName topProjectPath = projectPath(); - if (topProjectPath.isEmpty()) - return QString(); + QDir overrideDir; + if (!checkForSettings || useProjectOverriddenSettings()) { + overrideDir = projectPath().toString(); + if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) + return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); + } - QDir projectDir(fileName.parentDir().toString()); - while (!projectDir.exists(Constants::SETTINGS_FILE_NAME) - && !projectDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { - if (projectDir.path() == topProjectPath.toString() - || !Utils::FileName::fromString(projectDir.path()).isChildOf(topProjectPath) - || !projectDir.cdUp()) { - return QString(); - } + if (!checkForSettings || useGlobalOverriddenSettings()) { + overrideDir = globalPath().toString(); + if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) + return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); } - if (projectDir.exists(Constants::SETTINGS_FILE_NAME)) - return projectDir.filePath(Constants::SETTINGS_FILE_NAME); - return projectDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); + return findConfig(fileName); +} + +QString configForFile(Utils::FileName fileName) +{ + return configForFile(fileName, true); +} + +Utils::FileName assumedPathForConfig(const QString &configFile) +{ + Utils::FileName fileName = Utils::FileName::fromString(configFile); + return fileName.parentDir().appendPath("test.cpp"); } -static clang::format::FormatStyle constructStyle(bool isGlobal, - const QByteArray &baseStyle = QByteArray()) +static clang::format::FormatStyle constructStyle(const QByteArray &baseStyle = QByteArray()) { if (!baseStyle.isEmpty()) { // Try to get the style for this base style. @@ -144,21 +259,7 @@ static clang::format::FormatStyle constructStyle(bool isGlobal, // Fallthrough to the default style. } - FormatStyle style = getLLVMStyle(); - style.BreakBeforeBraces = FormatStyle::BS_Custom; - - const CppCodeStyleSettings codeStyleSettings = isGlobal - ? CppCodeStyleSettings::currentGlobalCodeStyle() - : CppCodeStyleSettings::currentProjectCodeStyle() - .value_or(CppCodeStyleSettings::currentGlobalCodeStyle()); - const TabSettings tabSettings = isGlobal - ? CppCodeStyleSettings::currentGlobalTabSettings() - : CppCodeStyleSettings::currentProjectTabSettings(); - - applyTabSettings(style, tabSettings); - applyCppCodeStyleSettings(style, codeStyleSettings); - - return style; + return qtcStyle(); } void createStyleFileIfNeeded(bool isGlobal) @@ -169,9 +270,21 @@ void createStyleFileIfNeeded(bool isGlobal) if (QFile::exists(configFile)) return; + QDir().mkpath(path.parentDir().toString()); + if (!isGlobal) { + const Project *project = SessionManager::startupProject(); + Utils::FileName possibleProjectConfig = project->rootProjectDirectory().appendPath( + Constants::SETTINGS_FILE_NAME); + if (possibleProjectConfig.exists()) { + // Just copy th .clang-format if current project has one. + QFile::copy(possibleProjectConfig.toString(), configFile); + return; + } + } + std::fstream newStyleFile(configFile.toStdString(), std::fstream::out); if (newStyleFile.is_open()) { - newStyleFile << clang::format::configurationAsText(constructStyle(isGlobal)); + newStyleFile << clang::format::configurationAsText(constructStyle()); newStyleFile.close(); } } @@ -198,17 +311,13 @@ static QByteArray configBaseStyleName(const QString &configFile) .trimmed(); } -clang::format::FormatStyle styleForFile(Utils::FileName fileName) +static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool checkForSettings) { - bool isGlobal = false; - QString configFile = configForFile(fileName); - if (configFile.isEmpty()) { - Utils::FileName path = fileName = globalPath(); - fileName.appendPath(Constants::SAMPLE_FILE_NAME); - createStyleFileIfNeeded(true); - configFile = path.appendPath(Constants::SETTINGS_FILE_NAME).toString(); - } + QString configFile = configForFile(fileName, checkForSettings); + if (configFile.isEmpty()) + return constructStyle(); + fileName = assumedPathForConfig(configFile); Expected<FormatStyle> style = format::getStyle("file", fileName.toString().toStdString(), "none"); @@ -219,17 +328,21 @@ clang::format::FormatStyle styleForFile(Utils::FileName fileName) // do nothing }); - return constructStyle(isGlobal, configBaseStyleName(configFile)); + return constructStyle(configBaseStyleName(configFile)); } -clang::format::FormatStyle currentProjectStyle() +clang::format::FormatStyle styleForFile(Utils::FileName fileName) { - return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME)); + return styleForFile(fileName, true); } -clang::format::FormatStyle currentGlobalStyle() +clang::format::FormatStyle currentProjectStyle() { - return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME)); + return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } +clang::format::FormatStyle currentGlobalStyle() +{ + return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } +} // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index 41e2b5611fa..bd530769430 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -25,6 +25,7 @@ #pragma once +#include <coreplugin/id.h> #include <utils/fileutils.h> #include <clang/Format/Format.h> @@ -37,10 +38,13 @@ namespace ClangFormat { // Creates the style for the current project or the global style if needed. void createStyleFileIfNeeded(bool isGlobal); +QString currentProjectUniqueId(); + clang::format::FormatStyle currentProjectStyle(); clang::format::FormatStyle currentGlobalStyle(); // Is the style from the matching .clang-format file or global one if it's not found. +QString configForFile(Utils::FileName fileName); clang::format::FormatStyle styleForFile(Utils::FileName fileName); } diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp index 2dc381f6a3d..43858cc8650 100644 --- a/src/plugins/clangtools/clangtidyclazytool.cpp +++ b/src/plugins/clangtools/clangtidyclazytool.cpp @@ -452,12 +452,12 @@ void ClangTidyClazyTool::handleStateUpdate() if (issuesFound) message = tr("Running - %n diagnostics", nullptr, issuesFound); else - message = tr("Running - No diagnostics", nullptr, issuesFound); + message = tr("Running - No diagnostics"); } else { if (issuesFound) message = tr("Finished - %n diagnostics", nullptr, issuesFound); else - message = tr("Finished - No diagnostics", nullptr, issuesFound); + message = tr("Finished - No diagnostics"); } Debugger::showPermanentStatusMessage(message); diff --git a/src/plugins/coreplugin/find/searchresulttreeview.cpp b/src/plugins/coreplugin/find/searchresulttreeview.cpp index 6a9b7067bf4..0ca09fcefd1 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeview.cpp @@ -78,6 +78,21 @@ void SearchResultTreeView::addResults(const QList<SearchResultItem> &items, Sear } } +void SearchResultTreeView::keyPressEvent(QKeyEvent *event) +{ + if ((event->key() == Qt::Key_Return + || event->key() == Qt::Key_Enter) + && event->modifiers() == 0 + && currentIndex().isValid() + && state() != QAbstractItemView::EditingState) { + const SearchResultItem item + = model()->data(currentIndex(), ItemDataRoles::ResultItemRole).value<SearchResultItem>(); + emit jumpToSearchResult(item); + return; + } + TreeView::keyPressEvent(event); +} + void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index) { if (model()->data(index, ItemDataRoles::IsGeneratedRole).toBool()) diff --git a/src/plugins/coreplugin/find/searchresulttreeview.h b/src/plugins/coreplugin/find/searchresulttreeview.h index 961940fe017..eb11d29a7d9 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.h +++ b/src/plugins/coreplugin/find/searchresulttreeview.h @@ -49,6 +49,8 @@ public: SearchResultTreeModel *model() const; void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode); + void keyPressEvent(QKeyEvent *event) override; + signals: void jumpToSearchResult(const SearchResultItem &item); diff --git a/src/plugins/coreplugin/helpitem.h b/src/plugins/coreplugin/helpitem.h index 15ff585ca82..c258eed0d8a 100644 --- a/src/plugins/coreplugin/helpitem.h +++ b/src/plugins/coreplugin/helpitem.h @@ -84,10 +84,9 @@ public: const Links &links() const; const Links bestLinks() const; const QString keyword() const; - -private: bool isFuzzyMatch() const; +private: QUrl m_helpUrl; QStringList m_helpIds; QString m_docMark; diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 2421bd776ab..994c9e5d0e8 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -252,6 +252,14 @@ void LocatorModel::addEntries(const QList<LocatorFilterEntry> &entries) CompletionList::CompletionList(QWidget *parent) : Utils::TreeView(parent) { + // on macOS and Windows the popup doesn't really get focus, so fake the selection color + // which would then just be a very light gray, but should look as if it had focus + QPalette p = palette(); + p.setBrush(QPalette::Inactive, + QPalette::Highlight, + p.brush(QPalette::Normal, QPalette::Highlight)); + setPalette(p); + setItemDelegate(new CompletionDelegate(this)); setRootIsDecorated(false); setUniformRowHeights(true); diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 3f19d4b9b94..eb411bdaa9d 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -507,7 +507,6 @@ void OutputPaneManager::showPage(int idx, int flags) ensurePageVisible(idx); IOutputPane *out = g_outputPanes.at(idx).pane; - out->visibilityChanged(true); if (flags & IOutputPane::WithFocus) { if (out->canFocus()) out->setFocus(); @@ -538,7 +537,10 @@ void OutputPaneManager::setCurrentIndex(int idx) m_outputWidgetPane->setCurrentIndex(idx); m_opToolBarWidgets->setCurrentIndex(idx); - IOutputPane *pane = g_outputPanes.at(idx).pane; + OutputPaneData &data = g_outputPanes[idx]; + IOutputPane *pane = data.pane; + data.button->show(); + data.buttonVisible = true; pane->visibilityChanged(true); bool canNavigate = pane->canNavigate(); @@ -574,8 +576,6 @@ void OutputPaneManager::popupMenu() data.button->hide(); data.buttonVisible = false; } else { - data.button->show(); - data.buttonVisible = true; showPage(idx, IOutputPane::ModeSwitch); } } diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index e19a94513d7..4f03a681f06 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -860,11 +860,11 @@ void ClangDiagnosticConfigsWidget::syncClazyChecksGroupBox() return !m_clazySortFilterProxyModel->filterAcceptsRow(index.row(), index.parent()); }; const bool hasEnabledButHidden = m_clazyTreeModel->hasEnabledButNotVisibleChecks(isHidden); - const QString title = hasEnabledButHidden ? tr("Checks (%1 enabled, some are filtered out)") - : tr("Checks (%1 enabled)"); - - const QStringList checks = m_clazyTreeModel->enabledChecks(); - m_clazyChecks->checksGroupBox->setTitle(title.arg(checks.count())); + const int checksCount = m_clazyTreeModel->enabledChecks().count(); + const QString title = hasEnabledButHidden ? tr("Checks (%n enabled, some are filtered out)", + nullptr, checksCount) + : tr("Checks (%n enabled)", nullptr, checksCount); + m_clazyChecks->checksGroupBox->setTitle(title); } void ClangDiagnosticConfigsWidget::updateConfig(const ClangDiagnosticConfig &config) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index e5685dc5e05..8dfe0c79773 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -172,7 +172,7 @@ void CompilerOptionsBuilder::addSyntaxOnly() isClStyle() ? add("/Zs") : add("-fsyntax-only"); } -static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) +QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) { QStringList options; @@ -741,6 +741,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } + if (option.startsWith("/Y", Qt::CaseSensitive) + || (option.startsWith("/F", Qt::CaseSensitive) && option != "/F")) { + // Precompiled header flags. + // Skip also the next option if it's not glued to the current one. + if (option.size() > 3) + skipNext = true; + continue; + } + // Check whether a language version is already used. QString theOption = option; if (theOption.startsWith("-std=")) { diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 03564ab6164..349279710ad 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -40,6 +40,7 @@ enum class UseBuildSystemWarnings : char { Yes, No }; CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args); CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args); +CPPTOOLS_EXPORT QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt); class CPPTOOLS_EXPORT CompilerOptionsBuilder { diff --git a/src/plugins/cpptools/cppfilesettingspage.ui b/src/plugins/cpptools/cppfilesettingspage.ui index 9edf2cd5dae..7bb13449acc 100644 --- a/src/plugins/cpptools/cppfilesettingspage.ui +++ b/src/plugins/cpptools/cppfilesettingspage.ui @@ -99,10 +99,10 @@ These prefixes are used in addition to current file name on Switch Header/Source <item row="7" column="1"> <widget class="QCheckBox" name="headerPragmaOnceCheckBox"> <property name="toolTip"> - <string>Uses #pragma once instead of #ifndef include guards.</string> + <string>Uses "#pragma once" instead of "#ifndef" include guards.</string> </property> <property name="text"> - <string>Use '#pragma once' instead of '#ifndef' guards</string> + <string>Use "#pragma once" instead of "#ifndef" guards</string> </property> </widget> </item> diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 8068c27d0bd..d2ca6d5d0b8 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -211,7 +211,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) expander->registerVariable( "Cpp:PragmaOnce", - tr("Insert #pragma once instead of #ifndef include guards into header file"), + tr("Insert \"#pragma once\" instead of \"#ifndef\" include guards into header file"), [] { return usePragmaOnce() ? QString("true") : QString(); }); return true; diff --git a/src/plugins/debugger/console/console.h b/src/plugins/debugger/console/console.h index c46add0a864..4690283a346 100644 --- a/src/plugins/debugger/console/console.h +++ b/src/plugins/debugger/console/console.h @@ -58,7 +58,7 @@ public: QWidget *outputWidget(QWidget *) override; QList<QWidget *> toolBarWidgets() const override; - QString displayName() const override { return tr("Debugger Console"); } + QString displayName() const override { return tr("QML Debugger Console"); } int priorityInStatusBar() const override; void clearContents() override; void visibilityChanged(bool visible) override; diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index adc81bee691..4a7fb5d4a30 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -748,7 +748,8 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers() dir.setPath(base.toFileInfo().absoluteFilePath()); foreach (const QString &entry, dir.entryList()) { if (entry.startsWith("lldb-platform-") - || entry.startsWith("lldb-gdbserver-")) { + || entry.startsWith("lldb-gdbserver-") + || entry.startsWith("lldb-mi-")) { continue; } suspects.append(FileName::fromString(dir.absoluteFilePath(entry))); diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index b85962bd0ed..9783184346a 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -152,24 +152,7 @@ DebuggerKitAspect::DebuggerKitAspect() setPriority(28000); } -QVariant DebuggerKitAspect::defaultValue(const Kit *k) const -{ - const Abi toolChainAbi = ToolChainKitAspect::targetAbi(k); - const Utils::FileNameList paths = Environment::systemEnvironment().path(); - QVariant nextBestFit; - for (const DebuggerItem &item : DebuggerItemManager::debuggers()) { - for (const Abi &targetAbi : item.abis()) { - if (targetAbi.isCompatibleWith(toolChainAbi)) { - if (paths.contains(item.command())) - return item.id(); // prefer debuggers found in PATH over those found elsewhere - if (nextBestFit.isNull()) - nextBestFit = item.id(); - } - } - } - - return nextBestFit; -} +QVariant DebuggerKitAspect::defaultValue(const Kit *) const { return QVariant(); } void DebuggerKitAspect::setup(Kit *k) { diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index 096c03db16c..0ddb983dbe0 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -119,6 +119,7 @@ public: void resetCurrentPerspective(); int indexInChooser(Perspective *perspective) const; void fixupLayoutIfNeeded(); + void updatePerspectiveChooserWidth(); DebuggerMainWindow *q = nullptr; Perspective *m_currentPerspective = nullptr; @@ -416,10 +417,17 @@ void DebuggerMainWindowPrivate::selectPerspective(Perspective *perspective) fixupLayoutIfNeeded(); } + updatePerspectiveChooserWidth(); +} + +void DebuggerMainWindowPrivate::updatePerspectiveChooserWidth() +{ + Perspective *perspective = m_currentPerspective; int index = indexInChooser(m_currentPerspective); if (index == -1) { - if (Perspective *parent = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId)) - index = indexInChooser(parent); + perspective = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId); + if (perspective) + index = indexInChooser(perspective); } if (index != -1) { diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 5bb4845073d..19b40113383 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -61,6 +61,7 @@ #include <utils/temporarydirectory.h> #include <utils/temporaryfile.h> #include <utils/url.h> +#include <utils/winutils.h> #include <coreplugin/icontext.h> #include <coreplugin/icore.h> @@ -565,6 +566,17 @@ void DebuggerRunTool::start() if (!fixupParameters()) return; + if (m_runParameters.cppEngineType == CdbEngineType + && Utils::is64BitWindowsBinary(m_runParameters.inferior.executable) + && !Utils::is64BitWindowsBinary(m_runParameters.debugger.executable)) { + reportFailure( + DebuggerPlugin::tr( + "%1 is a 64 bit executable which can not be debugged by a 32 bit Debugger.\n" + "Please select a 64 bit Debugger in the kit settings for this kit.") + .arg(m_runParameters.inferior.executable)); + return; + } + Utils::globalMacroExpander()->registerFileVariables( "DebuggedExecutable", tr("Debugged executable"), [this] { return m_runParameters.inferior.executable; } diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index f0c76422575..9b4f6056f3e 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -395,6 +395,8 @@ void LldbEngine::handleResponse(const QString &response) handleOutputNotification(item); else if (name == "pid") notifyInferiorPid(item.toProcessHandle()); + else if (name == "breakpointmodified") + handleInterpreterBreakpointModified(item); } } @@ -607,6 +609,31 @@ void LldbEngine::handleOutputNotification(const GdbMi &output) showMessage(data, ch); } +void LldbEngine::handleInterpreterBreakpointModified(const GdbMi &bpItem) +{ + QTC_ASSERT(bpItem.childCount(), return); + QString id = bpItem.childAt(0).m_data; + + Breakpoint bp = breakHandler()->findBreakpointByResponseId(id); + if (!bp) // FIXME adapt whole bp handling and turn into soft assert + return; + + // this function got triggered by a lldb internal breakpoint event + // avoid asserts regarding unexpected state transitions + switch (bp->state()) { + case BreakpointInsertionRequested: // was a pending bp + bp->gotoState(BreakpointInsertionProceeding, BreakpointInsertionRequested); + break; + case BreakpointInserted: // was an inserted, gets updated now + bp->gotoState(BreakpointUpdateRequested, BreakpointInserted); + notifyBreakpointChangeProceeding(bp); + break; + default: + break; + } + updateBreakpointData(bp, bpItem, false); +} + void LldbEngine::loadSymbols(const QString &moduleName) { Q_UNUSED(moduleName) diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index f06798dd392..6c5b3c2c21c 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -120,6 +120,7 @@ private: void handleStateNotification(const GdbMi &item); void handleLocationNotification(const GdbMi &location); void handleOutputNotification(const GdbMi &output); + void handleInterpreterBreakpointModified(const GdbMi &item); void handleResponse(const QString &data); void updateAll() override; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 7abdee2c7c7..a887dc53715 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -657,7 +657,7 @@ void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp) .arg(contextHelp.helpIds().join(", ")) .arg(HelpPlugin::tr("No documentation available."))); } - } else if (links.size() == 1) { + } else if (links.size() == 1 && !contextHelp.isFuzzyMatch()) { showHelpUrl(links.front().second, LocalHelpManager::contextHelpOption()); } else { QMap<QString, QUrl> map; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index efd4c8fb6fa..5553e58ecce 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -208,17 +208,6 @@ void Client::openDocument(Core::IDocument *document) connect(textDocument, &QObject::destroyed, this, [this, textDocument]{ m_resetAssistProvider.remove(textDocument); }); - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) { - if (QPointer<TextEditorWidget> widget = editor->editorWidget()) { - connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){ - // TODO This would better be a compressing timer - QTimer::singleShot(50, this, [this, widget]() { - if (widget) - cursorPositionChanged(widget); - }); - }); - } - } } m_openedDocument.append(document->filePath()); @@ -344,7 +333,7 @@ void Client::documentContentsChanged(Core::IDocument *document) if (textDocument) { using namespace TextEditor; - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) + for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(textDocument)) if (TextEditorWidget *widget = editor->editorWidget()) widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); requestDocumentSymbols(textDocument); @@ -766,6 +755,11 @@ const DynamicCapabilities &Client::dynamicCapabilities() const return m_dynamicCapabilities; } +const BaseClientInterface *Client::clientInterface() const +{ + return m_clientInterface.data(); +} + void Client::log(const ShowMessageParams &message, Core::MessageManager::PrintToOutputPaneFlag flag) { diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 2d92424f42d..635512fa287 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -147,6 +147,7 @@ public: const LanguageServerProtocol::ServerCapabilities &capabilities() const; const DynamicCapabilities &dynamicCapabilities() const; + const BaseClientInterface *clientInterface() const; signals: void initialized(LanguageServerProtocol::ServerCapabilities capabilities); diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index b67db95dde1..05980617207 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -110,7 +110,7 @@ StdIOClientInterface::~StdIOClientInterface() Utils::SynchronousProcess::stopProcess(m_process); } -bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) +bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) const { return m_executable != settings->m_executable || m_arguments != settings->m_arguments; } diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 3dc2602d524..182965ab882 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -74,7 +74,7 @@ public: StdIOClientInterface &operator=(const StdIOClientInterface &) = delete; StdIOClientInterface &operator=(StdIOClientInterface &&) = delete; - bool needsRestart(const StdIOSettings *settings); + bool needsRestart(const StdIOSettings *settings) const; bool start() override; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index b097f25a378..1cd162dc51a 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -125,7 +125,10 @@ void LanguageClientManager::deleteClient(Client *client) QTC_ASSERT(client, return); client->disconnect(); managerInstance->m_clients.removeAll(client); - client->deleteLater(); + if (managerInstance->m_shuttingDown) + delete client; + else + client->deleteLater(); } void LanguageClientManager::shutdown() @@ -210,6 +213,18 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor) (const QTextCursor &cursor){ findUsages(filePath, cursor); }); + connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){ + // TODO This would better be a compressing timer + QTimer::singleShot(50, this, + [this, widget = QPointer<TextEditorWidget>(widget)]() { + if (widget) { + for (Client *client : this->reachableClients()) { + if (client->isSupportedDocument(widget->textDocument())) + client->cursorPositionChanged(widget); + } + } + }); + }); } } } diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 276fac15fc9..a337a72b7b6 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -491,7 +491,9 @@ bool StdIOSettings::needsRestart() const { if (BaseSettings::needsRestart()) return true; - if (auto stdIOInterface = qobject_cast<StdIOClientInterface *>(m_client)) + if (m_client.isNull()) + return false; + if (auto stdIOInterface = qobject_cast<const StdIOClientInterface *>(m_client->clientInterface())) return stdIOInterface->needsRestart(this); return false; } diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index f81be2427cc..7a28c5e3a95 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -133,12 +133,10 @@ void updateCodeActionRefactoringMarker(Client *client, TextDocument* doc = TextDocument::textDocumentForFileName(uri.toFileName()); if (!doc) return; - BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(doc); - if (!editor) + const QVector<BaseTextEditor *> editors = BaseTextEditor::textEditorsForDocument(doc); + if (editors.isEmpty()) return; - TextEditorWidget *editorWidget = editor->editorWidget(); - const QList<Diagnostic> &diagnostics = action.diagnostics().value_or(QList<Diagnostic>()); RefactorMarkers markers; @@ -181,7 +179,10 @@ void updateCodeActionRefactoringMarker(Client *client, marker.cursor = endOfLineCursor(diagnostic.range().start().toTextCursor(doc->document())); markers << marker; } - editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers()); + for (BaseTextEditor *editor : editors) { + if (TextEditorWidget *editorWidget = editor->editorWidget()) + editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers()); + } } } // namespace LanguageClient diff --git a/src/plugins/nim/settings/nimtoolssettingswidget.ui b/src/plugins/nim/settings/nimtoolssettingswidget.ui index 7322c6a8eca..28c0d1ac31d 100644 --- a/src/plugins/nim/settings/nimtoolssettingswidget.ui +++ b/src/plugins/nim/settings/nimtoolssettingswidget.ui @@ -10,9 +10,6 @@ <height>300</height> </rect> </property> - <property name="windowTitle"> - <string>Form</string> - </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QGroupBox" name="groupBox"> diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index 07a2c905519..5dc638bbbef 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -96,7 +96,7 @@ PerfTracePointDialog::~PerfTracePointDialog() void PerfTracePointDialog::runScript() { - m_ui->label->setText(tr("Executing script ...")); + m_ui->label->setText(tr("Executing script...")); m_ui->textEdit->setReadOnly(true); m_ui->privilegesChooser->setEnabled(false); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); diff --git a/src/plugins/perfprofiler/perftracepointdialog.h b/src/plugins/perfprofiler/perftracepointdialog.h index 83e2199dad7..ca5d4e2ae52 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.h +++ b/src/plugins/perfprofiler/perftracepointdialog.h @@ -41,6 +41,8 @@ namespace Ui { class PerfTracePointDialog; } class PerfTracePointDialog : public QDialog { + Q_OBJECT + public: PerfTracePointDialog(); ~PerfTracePointDialog(); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 7b7b88967d0..437f9d58ee4 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -59,7 +59,6 @@ SUBDIRS = \ languageclient \ cppcheck \ compilationdatabaseprojectmanager \ - perfprofiler \ qmlpreview \ studiowelcome @@ -70,9 +69,9 @@ qtHaveModule(serialport) { } qtHaveModule(quick) { - SUBDIRS += qmlprofiler + SUBDIRS += qmlprofiler perfprofiler } else { - warning("QmlProfiler plugin has been disabled since the Qt Quick module is not available.") + warning("QmlProfiler and PerfProfiler plugins have been disabled since the Qt Quick module is not available.") } qtHaveModule(help) { diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h index 1ef030e67f6..e69e2842509 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h @@ -32,6 +32,8 @@ namespace Internal { class DesktopDeviceFactory : public IDeviceFactory { + Q_OBJECT + public: DesktopDeviceFactory(); }; diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index e92e66c5b20..cc0ca3a39fd 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -275,11 +275,9 @@ void Kit::fix() void Kit::setup() { KitGuard g(this); - // Process the KitAspects in reverse order: They may only be based on other information - // lower in the stack. const QList<KitAspect *> aspects = KitManager::kitAspects(); - for (int i = aspects.count() - 1; i >= 0; --i) - aspects.at(i)->setup(this); + for (KitAspect * const aspect : aspects) + aspect->setup(this); } void Kit::upgrade() diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 3d40aef1ef8..07aa313fcca 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -71,10 +71,12 @@ class KitManagerPrivate public: Kit *m_defaultKit = nullptr; bool m_initialized = false; - std::vector<std::unique_ptr<KitAspect>> m_informationList; std::vector<std::unique_ptr<Kit>> m_kitList; std::unique_ptr<PersistentSettingsWriter> m_writer; QSet<Id> m_irrelevantAspects; + + // Sorted by priority, in descending order. + std::vector<std::unique_ptr<KitAspect>> m_informationList; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 8b8c5711428..9c86a706869 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1027,6 +1027,8 @@ bool static hasFlagEffectOnMacros(const QString &flag) return false; // Skip include paths if (f.startsWith("w", Qt::CaseInsensitive)) return false; // Skip warning options + if (f.startsWith("Y") || (f.startsWith("F") && f != "F")) + return false; // Skip pch-related flags } return true; } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index ed7c16bc1fe..5d7d296e70d 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2045,8 +2045,12 @@ void ProjectExplorerPluginPrivate::updateWelcomePage() void ProjectExplorerPluginPrivate::currentModeChanged(Id mode, Id oldMode) { - if (oldMode == Constants::MODE_SESSION) - ICore::saveSettings(); + if (oldMode == Constants::MODE_SESSION) { + // Saving settings directly in a mode change is not a good idea, since the mode change + // can be part of a bigger change. Save settings after that bigger change had a chance to + // complete. + QTimer::singleShot(0, ICore::instance(), &ICore::saveSettings); + } if (mode == Core::Constants::MODE_WELCOME) updateWelcomePage(); } diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 68a0431789d..4d71670e7d1 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -363,7 +363,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile, // This assumes te project file is formed with only one field called // 'files' that has a list associated of the files to include in the project. if (content.isEmpty()) { - *errorMessage = PythonProject::tr("Unable read \"%1\": The file is empty.") + *errorMessage = PythonProject::tr("Unable to read \"%1\": The file is empty.") .arg(projectFile.toUserOutput()); return lines; } @@ -372,7 +372,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile, const QJsonDocument doc = QJsonDocument::fromJson(content, &error); if (doc.isNull()) { const int line = content.left(error.offset).count('\n') + 1; - *errorMessage = PythonProject::tr("Unable parse %1:%2: %3") + *errorMessage = PythonProject::tr("Unable to parse \"%1\":%2: %3") .arg(projectFile.toUserOutput()).arg(line) .arg(error.errorString()); return lines; diff --git a/src/plugins/qmldesigner/designercore/include/qmltimeline.h b/src/plugins/qmldesigner/designercore/include/qmltimeline.h index a92a2921198..c04fd454c0c 100644 --- a/src/plugins/qmldesigner/designercore/include/qmltimeline.h +++ b/src/plugins/qmldesigner/designercore/include/qmltimeline.h @@ -71,10 +71,10 @@ public: void toogleRecording(bool b) const; void resetGroupRecording() const; + bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const; private: void addKeyframeGroupIfNotExists(const ModelNode &node, const PropertyName &propertyName); - bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const; QList<QmlTimelineKeyframeGroup> allKeyframeGroups() const; }; diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp index 745fdc4d00b..65ed482bfb1 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp @@ -63,7 +63,7 @@ void QmlObjectNode::setVariantProperty(const PropertyName &name, const QVariant timelineFrames.setValue(value, frame); return; - } else if (modelNode().hasId() && timelineIsActive()) { + } else if (modelNode().hasId() && timelineIsActive() && currentTimeline().hasKeyframeGroup(modelNode(), name)) { QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name)); Q_ASSERT(timelineFrames.isValid()); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 9b73dc1faf8..bdaa22bb4b2 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -65,7 +65,6 @@ const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These setti const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */ const char STANDALONE_MODE[] = "StandAloneMode"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; -const char ENABLE_TIMELINEVIEW_ENVVAR[] = "QTC_ENABLE_QTQUICKTIMELINE_EDITOR"; } class DesignerSettings : public QHash<QByteArray, QVariant> diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui index 8bc3e6c9737..5d13cfa7264 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui @@ -10,14 +10,11 @@ <height>176</height> </rect> </property> - <property name="windowTitle"> - <string>Form</string> - </property> <layout class="QGridLayout" name="gridLayout"> <item row="4" column="3"> <widget class="QLabel" name="label_16"> <property name="text"> - <string>Loops</string> + <string>Loops:</string> </property> </widget> </item> @@ -117,7 +114,7 @@ </size> </property> <property name="text"> - <string>Animation ID</string> + <string>Animation ID:</string> </property> </widget> </item> @@ -162,14 +159,14 @@ <item row="5" column="1"> <widget class="QLabel" name="label_23"> <property name="text"> - <string>Finished</string> + <string>Finished:</string> </property> </widget> </item> <item row="4" column="7"> <widget class="QLabel" name="label_17"> <property name="text"> - <string>Ping Pong</string> + <string>Ping pong</string> </property> </widget> </item> @@ -205,7 +202,7 @@ </size> </property> <property name="text"> - <string>Transition to state</string> + <string>Transition to state:</string> </property> </widget> </item> @@ -222,7 +219,7 @@ <bool>true</bool> </property> <property name="text"> - <string>Running in Base State</string> + <string>Running in base state</string> </property> </widget> </item> @@ -257,7 +254,7 @@ <item row="3" column="1"> <widget class="QLabel" name="label_12"> <property name="text"> - <string>Start Frame</string> + <string>Start frame:</string> </property> </widget> </item> @@ -290,14 +287,14 @@ <item row="3" column="7"> <widget class="QLabel" name="label_14"> <property name="text"> - <string>Duration</string> + <string>Duration:</string> </property> </widget> </item> <item row="3" column="3"> <widget class="QLabel" name="label_13"> <property name="text"> - <string>End Frame</string> + <string>End frame:</string> </property> </widget> </item> diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h index 40e4900442d..6c012beec1e 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -46,13 +46,13 @@ const int priorityTimelineCategory = 110; const char timelineCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Timeline"); const char timelineCopyKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Copy All Keyframes from item"); + "Copy All Keyframes"); const char timelinePasteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Paste Keyframes to item"); + "Paste Keyframes"); const char timelineInsertKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Insert Keyframes for item"); + "Add Keyframes at Current Frame"); const char timelineDeleteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Delete All Keyframes for item"); + "Delete All Keyframes"); const char timelineStatusBarFrameNumber[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Frame %1"); diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui index 5eea257be19..b8b47e4c701 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui @@ -10,9 +10,6 @@ <height>170</height> </rect> </property> - <property name="windowTitle"> - <string>Form</string> - </property> <layout class="QGridLayout" name="gridLayout"> <item row="1" column="8" colspan="2"> <spacer name="horizontalSpacer_11"> @@ -84,7 +81,7 @@ <item row="4" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> - <string>Expression Binding</string> + <string>Expression binding:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -107,7 +104,7 @@ <item row="2" column="4"> <widget class="QLabel" name="label_7"> <property name="text"> - <string>End Frame</string> + <string>End frame:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -200,7 +197,7 @@ <bool>false</bool> </property> <property name="text"> - <string>Expression Binding</string> + <string>Expression binding</string> </property> </widget> </item> @@ -214,7 +211,7 @@ <item row="1" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> - <string>Timeline ID</string> + <string>Timeline ID:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -243,7 +240,7 @@ <item row="2" column="1"> <widget class="QLabel" name="label_6"> <property name="text"> - <string>Start Frame</string> + <string>Start frame:</string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h index 5cd241b7a33..2b8c00c59bc 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h @@ -44,6 +44,8 @@ class TimelineToolButton; class TimelineKeyframeItem : public TimelineMovableAbstractItem { + Q_DECLARE_TR_FUNCTIONS(TimelineKeyframeItem) + public: explicit TimelineKeyframeItem(TimelinePropertyItem *parent, const ModelNode &frame); ~TimelineKeyframeItem() override; @@ -84,6 +86,8 @@ private: class TimelinePropertyItem : public TimelineItem { + Q_OBJECT + public: enum { Type = TimelineConstants::timelinePropertyItemUserType }; diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h index 3c34ba39299..26db04f7579 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h @@ -40,6 +40,8 @@ class TimelineSectionItem; class TimelineBarItem : public TimelineMovableAbstractItem { + Q_DECLARE_TR_FUNCTIONS(TimelineBarItem) + enum class Location { Undefined, Center, Left, Right }; public: diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp index 6ce3731222e..47426d97551 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp @@ -103,7 +103,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent, switch (index.column()) { case TimelineSettingsModel::TimelineRow: { QTC_ASSERT(comboBox, return widget); - comboBox->addItem(tr("None")); + comboBox->addItem(TimelineSettingsModel::tr("None")); for (const auto &timeline : timelineSettingsModel->timelineView()->getTimelines()) { if (!timeline.modelNode().id().isEmpty()) comboBox->addItem(timeline.modelNode().id()); @@ -111,7 +111,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent, } break; case TimelineSettingsModel::AnimationRow: { QTC_ASSERT(comboBox, return widget); - comboBox->addItem(tr("None")); + comboBox->addItem(TimelineSettingsModel::tr("None")); for (const auto &animation : timelineSettingsModel->timelineView()->getAnimations(qmlTimeline)) { if (!animation.id().isEmpty()) diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 09e10c3b0c1..84b95cccc3b 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -194,8 +194,7 @@ bool QmlDesignerPlugin::delayedInitialize() d->settings.fromSettings(Core::ICore::settings()); d->viewManager.registerViewTakingOwnership(new QmlDesigner::Internal::ConnectionView); - if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool() - || qEnvironmentVariableIsSet(DesignerSettingsKey::ENABLE_TIMELINEVIEW_ENVVAR)) + if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()) d->viewManager.registerViewTakingOwnership(new QmlDesigner::TimelineView); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::SourceTool); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::ColorTool); diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index e9bd2d1cb46..a7d6bc2bb09 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -159,6 +159,8 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.showPropertyEditorWarningsCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT, m_ui.showWarnExceptionsCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::ENABLE_TIMELINEVIEW, + m_ui.featureTimelineEditorCheckBox->isChecked()); return settings; } @@ -224,9 +226,13 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.controls2StyleComboBox->setCurrentText(m_ui.styleLineEdit->text()); + m_ui.featureTimelineEditorCheckBox->setChecked(settings.value( + DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()); + if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) { m_ui.emulationGroupBox->hide(); m_ui.debugGroupBox->hide(); + m_ui.featuresGroupBox->hide(); } } @@ -262,7 +268,8 @@ void SettingsPage::apply() << DesignerSettingsKey::PUPPET_KILL_TIMEOUT << DesignerSettingsKey::FORWARD_PUPPET_OUTPUT << DesignerSettingsKey::DEBUG_PUPPET - << DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT; + << DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT + << DesignerSettingsKey::ENABLE_TIMELINEVIEW; foreach (const QByteArray &key, restartNecessaryKeys) { if (currentSettings.value(key) != newSettings.value(key)) { diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index 567f0f7d80e..7da62b300aa 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -411,6 +411,22 @@ </layout> </item> <item> + <widget class="QGroupBox" name="featuresGroupBox"> + <property name="title"> + <string>Features</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QCheckBox" name="featureTimelineEditorCheckBox"> + <property name="text"> + <string>Enable Timeline editor</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="QGroupBox" name="debugGroupBox"> <property name="title"> <string>Debugging</string> diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 1df46d885b7..a6e5850076b 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -287,10 +287,10 @@ void QmlProfilerTool::updateRunActions() d->m_startAction->setToolTip(tr("A QML Profiler analysis is still in progress.")); d->m_stopAction->setEnabled(true); } else { - QString whyNot = tr("Start QML Profiler analysis."); + QString tooltip = tr("Start QML Profiler analysis."); bool canRun = ProjectExplorerPlugin::canRunStartupProject - (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &whyNot); - d->m_startAction->setToolTip(whyNot); + (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &tooltip); + d->m_startAction->setToolTip(tooltip); d->m_startAction->setEnabled(canRun); d->m_stopAction->setEnabled(false); } diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp index 778d3096009..2b7933ea8a5 100644 --- a/src/plugins/qtsupport/qtoutputformatter.cpp +++ b/src/plugins/qtsupport/qtoutputformatter.cpp @@ -31,6 +31,7 @@ #include <utils/algorithm.h> #include <utils/ansiescapecodehandler.h> #include <utils/fileinprojectfinder.h> +#include <utils/hostosinfo.h> #include <utils/theme/theme.h> #include <QPlainTextEdit> @@ -412,16 +413,16 @@ void QtSupportPlugin::testQtOutputFormatter_data() << " Loc: [../TestProject/test.cpp(123)]" << 9 << 37 << "../TestProject/test.cpp(123)" << "../TestProject/test.cpp" << 123 << -1; - - QTest::newRow("Windows failed QTest link") - << "..\\TestProject\\test.cpp(123) : failure location" - << 0 << 28 << "..\\TestProject\\test.cpp(123)" - << "..\\TestProject\\test.cpp" << 123 << -1; - - QTest::newRow("Windows failed QTest link with carriage return") - << "..\\TestProject\\test.cpp(123) : failure location\r" - << 0 << 28 << "..\\TestProject\\test.cpp(123)" - << "..\\TestProject\\test.cpp" << 123 << -1; + if (HostOsInfo::isWindowsHost()) { + QTest::newRow("Windows failed QTest link") + << "..\\TestProject\\test.cpp(123) : failure location" + << 0 << 28 << "..\\TestProject\\test.cpp(123)" + << "../TestProject/test.cpp" << 123 << -1; + QTest::newRow("Windows failed QTest link with carriage return") + << "..\\TestProject\\test.cpp(123) : failure location\r" + << 0 << 28 << "..\\TestProject\\test.cpp(123)" + << "../TestProject/test.cpp" << 123 << -1; + } } void QtSupportPlugin::testQtOutputFormatter() diff --git a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp index 728aea666d4..f525f777d0e 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp @@ -203,7 +203,7 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success) } else { connect(d->connection, &SshConnection::connected, this, &AbstractRemoteLinuxDeployService::handleConnected); - emit progressMessage(tr("Connecting to device '%1' (%2)") + emit progressMessage(tr("Connecting to device \"%1\" (%2).") .arg(deviceConfiguration()->displayName()) .arg(deviceConfiguration()->sshParameters().host())); if (d->connection->state() == SshConnection::Unconnected) diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 72e35ba5bb3..92dae73d591 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -145,7 +145,7 @@ void BaseHoverHandler::decorateToolTip() if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); - if (lastHelpItemIdentified().isValid()) { + if (lastHelpItemIdentified().isValid() && !lastHelpItemIdentified().isFuzzyMatch()) { const QString &helpContents = lastHelpItemIdentified().extractContent(false); if (!helpContents.isEmpty()) { m_toolTip = toolTip().toHtmlEscaped(); diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp index 4178dc7195f..5b60b885ab4 100644 --- a/src/plugins/texteditor/highlighter.cpp +++ b/src/plugins/texteditor/highlighter.cpp @@ -258,6 +258,16 @@ void Highlighter::handleShutdown() delete highlightRepository(); } +static bool isOpeningParenthesis(QChar c) +{ + return c == QLatin1Char('{') || c == QLatin1Char('[') || c == QLatin1Char('('); +} + +static bool isClosingParenthesis(QChar c) +{ + return c == QLatin1Char('}') || c == QLatin1Char(']') || c == QLatin1Char(')'); +} + void Highlighter::highlightBlock(const QString &text) { if (!definition().isValid()) @@ -266,8 +276,21 @@ void Highlighter::highlightBlock(const QString &text) KSyntaxHighlighting::State state = TextDocumentLayout::userData(block)->syntaxState(); state = highlightLine(text, state); block = block.next(); + + Parentheses parentheses; + int pos = 0; + for (const QChar &c : text) { + if (isOpeningParenthesis(c)) + parentheses.push_back(Parenthesis(Parenthesis::Opened, c, pos)); + else if (isClosingParenthesis(c)) + parentheses.push_back(Parenthesis(Parenthesis::Closed, c, pos)); + pos++; + } + TextDocumentLayout::setParentheses(currentBlock(), parentheses); + if (block.isValid()) TextDocumentLayout::userData(block)->setSyntaxState(state); + formatSpaces(text); } void Highlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) diff --git a/src/plugins/texteditor/highlightersettingspage.ui b/src/plugins/texteditor/highlightersettingspage.ui index fcd4919b128..7b1e6c9e0da 100644 --- a/src/plugins/texteditor/highlightersettingspage.ui +++ b/src/plugins/texteditor/highlightersettingspage.ui @@ -127,6 +127,9 @@ </item> <item> <widget class="QPushButton" name="resetCache"> + <property name="toolTip"> + <string>Reset definitions remembered for files that can be associated with more than one highlighter definition.</string> + </property> <property name="text"> <string>Reset Remembered Definitions</string> </property> diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 36abfc01e29..3c4c8cd516e 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -8508,13 +8508,14 @@ BaseTextEditor *BaseTextEditor::currentTextEditor() return qobject_cast<BaseTextEditor *>(EditorManager::currentEditor()); } -BaseTextEditor *BaseTextEditor::textEditorForDocument(TextDocument *textDocument) +QVector<BaseTextEditor *> BaseTextEditor::textEditorsForDocument(TextDocument *textDocument) { + QVector<BaseTextEditor *> ret; for (IEditor *editor : Core::DocumentModel::editorsForDocument(textDocument)) { if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) - return textEditor; + ret << textEditor; } - return nullptr; + return ret; } TextEditorWidget *BaseTextEditor::editorWidget() const diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index d792a1b12c7..3d079bf77f3 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -111,7 +111,7 @@ public: virtual void finalizeInitialization() {} static BaseTextEditor *currentTextEditor(); - static BaseTextEditor *textEditorForDocument(TextDocument *textDocument); + static QVector<BaseTextEditor *> textEditorsForDocument(TextDocument *textDocument); TextEditorWidget *editorWidget() const; TextDocument *textDocument() const; diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index d5bf895ee47..29231afb82c 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -2,7 +2,19 @@ DEFINES += TEXTEDITOR_LIBRARY QT += gui-private network printsupport xml CONFIG += exceptions CONFIG += include_source_dir # For the highlighter autotest. + +include(../../shared/syntax/syntax_shared.pri) +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) | isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + QTC_LIB_DEPENDS += syntax-highlighting +} else { + unix:!disable_external_rpath { + !macos: QMAKE_LFLAGS += -Wl,-z,origin + QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR}) + } +} + include(../../qtcreatorplugin.pri) + SOURCES += texteditorplugin.cpp \ plaintexteditorfactory.cpp \ textdocument.cpp \ diff --git a/src/plugins/texteditor/texteditor_dependencies.pri b/src/plugins/texteditor/texteditor_dependencies.pri index c624e4cfb23..85ccb3ded7f 100644 --- a/src/plugins/texteditor/texteditor_dependencies.pri +++ b/src/plugins/texteditor/texteditor_dependencies.pri @@ -2,7 +2,21 @@ QTC_PLUGIN_NAME = TextEditor QTC_LIB_DEPENDS += \ aggregation \ extensionsystem \ - utils \ - syntax-highlighting + utils + QTC_PLUGIN_DEPENDS += \ coreplugin + +# needed for plugins that depend on TextEditor plugin +include(../../shared/syntax/syntax_shared.pri) +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR):!isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + INCLUDEPATH *= $${KSYNTAXHIGHLIGHTING_INCLUDE_DIR} + LIBS *= -L$$KSYNTAXHIGHLIGHTING_LIB_DIR -lKF5SyntaxHighlighting + + linux { + QMAKE_LFLAGS += -Wl,-z,origin + QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR}) + } +} else { + QTC_LIB_DEPENDS += syntax-highlighting +} diff --git a/src/shared/clang/clang_installation.pri b/src/shared/clang/clang_installation.pri index 6c820dc36d9..8c75b6cc820 100644 --- a/src/shared/clang/clang_installation.pri +++ b/src/shared/clang/clang_installation.pri @@ -96,7 +96,16 @@ defineReplace(splitFlags) { flag ~= s,-I\S*,, flag ~= s,/D\S*,, flag ~= s,/Z\S*,, - result += $$split(flag, " ") + separate_flags = $$split(flag, " ") + for (separate_flag, separate_flags) { + starting_substr = $$str_member($$separate_flag, 0, 0) + win32:equals(starting_substr, "/") { + result += $$separate_flag + } + equals(starting_substr, "-") { + result += $$separate_flag + } + } } else { inside_quotes = 0 starting_substr = $$str_member($$flag, 0, 0) diff --git a/src/shared/syntax/syntax_shared.pri b/src/shared/syntax/syntax_shared.pri new file mode 100644 index 00000000000..a10ae45b5cb --- /dev/null +++ b/src/shared/syntax/syntax_shared.pri @@ -0,0 +1,21 @@ +# KSyntaxHighlighting uses a special folder structure (may contain target arch triple for the lib), +# so expect lib folder to be specified by the user - generate include path based on this +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) +isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR): KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + !exists($$KSYNTAXHIGHLIGHTING_LIB_DIR) { + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + } else { + isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + !linux: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + else: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + } + + !exists($$KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + } + } +} diff --git a/src/tools/clangbackend/source/fulltokeninfo.cpp b/src/tools/clangbackend/source/fulltokeninfo.cpp index eb57abbbe6a..fd59d25766b 100644 --- a/src/tools/clangbackend/source/fulltokeninfo.cpp +++ b/src/tools/clangbackend/source/fulltokeninfo.cpp @@ -181,6 +181,7 @@ void FullTokenInfo::variableKind(const Cursor &cursor) { TokenInfo::variableKind(cursor); + m_extraInfo.accessSpecifier = cursor.accessSpecifier(); m_extraInfo.storageClass = cursor.storageClass(); } diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 89567b8d386..3237aab2fb1 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -41,7 +41,7 @@ #include <precompiledheaderstorage.h> #include <processormanager.h> #include <progresscounter.h> -#include <projectparts.h> +#include <projectpartsmanager.h> #include <filepathcaching.h> #include <refactoringdatabaseinitializer.h> #include <sqlitedatabase.h> @@ -68,7 +68,7 @@ using ClangBackEnd::PchCreator; using ClangBackEnd::PchManagerClientProxy; using ClangBackEnd::PchManagerServer; using ClangBackEnd::PrecompiledHeaderStorage; -using ClangBackEnd::ProjectParts; +using ClangBackEnd::ProjectPartsManager; using ClangBackEnd::FilePathCache; using ClangBackEnd::FilePathView; using ClangBackEnd::TimeStamp; @@ -138,12 +138,14 @@ public: ClangBackEnd::Environment &environment, Sqlite::Database &database, PchManagerServer &pchManagerServer, - ClangBackEnd::ClangPathWatcherInterface &pathWatcher) - : ProcessorManager(generatedFiles), - m_environment(environment), - m_database(database), - m_pchManagerServer(pchManagerServer), - m_pathWatcher(pathWatcher) + ClangBackEnd::ClangPathWatcherInterface &pathWatcher, + ClangBackEnd::BuildDependenciesStorageInterface &buildDependenciesStorage) + : ProcessorManager(generatedFiles) + , m_environment(environment) + , m_database(database) + , m_pchManagerServer(pchManagerServer) + , m_pathWatcher(pathWatcher) + , m_buildDependenciesStorage(buildDependenciesStorage) {} protected: @@ -152,7 +154,8 @@ protected: return std::make_unique<PchCreator>(m_environment, m_database, *m_pchManagerServer.client(), - m_pathWatcher); + m_pathWatcher, + m_buildDependenciesStorage); } private: @@ -160,6 +163,7 @@ private: Sqlite::Database &m_database; ClangBackEnd::PchManagerServer &m_pchManagerServer; ClangBackEnd::ClangPathWatcherInterface &m_pathWatcher; + ClangBackEnd::BuildDependenciesStorageInterface &m_buildDependenciesStorage; }; struct Data // because we have a cycle dependency @@ -175,13 +179,14 @@ struct Data // because we have a cycle dependency ClangBackEnd::FilePathCaching filePathCache{database}; ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache}; ApplicationEnvironment environment; - ProjectParts projectParts; + ProjectPartsManager projectParts; GeneratedFiles generatedFiles; PchCreatorManager pchCreatorManager{generatedFiles, environment, database, clangPchManagerServer, - includeWatcher}; + includeWatcher, + buildDependencyStorage}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; ClangBackEnd::ProgressCounter pchCreationProgressCounter{[&](int progress, int total) { executeInLoop([&] { diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp index d58da0f27c2..a2a7a813ac4 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp @@ -55,19 +55,19 @@ OutputContainer setUnion(InputContainer1 &&input1, BuildDependency BuildDependenciesProvider::create(const ProjectPartContainer &projectPart) { - SourceEntries includes = createSourceEntriesFromStorage(projectPart.sourcePathIds, - projectPart.projectPartId); + auto sourcesAndProjectPart = createSourceEntriesFromStorage( + projectPart.sourcePathIds, projectPart.projectPartId); - if (!m_modifiedTimeChecker.isUpToDate(includes)) { + if (!m_modifiedTimeChecker.isUpToDate(sourcesAndProjectPart.first)) { BuildDependency buildDependency = m_generator.create(projectPart); - storeBuildDependency(buildDependency); + storeBuildDependency(buildDependency, sourcesAndProjectPart.second); return buildDependency; } - return createBuildDependencyFromStorage(std::move(includes)); - + return createBuildDependencyFromStorage( + std::move(sourcesAndProjectPart.first)); } BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage( @@ -76,7 +76,7 @@ BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage( BuildDependency buildDependency; buildDependency.usedMacros = createUsedMacrosFromStorage(includes); - buildDependency.includes = std::move(includes); + buildDependency.sources = std::move(includes); return buildDependency; } @@ -101,16 +101,19 @@ UsedMacros BuildDependenciesProvider::createUsedMacrosFromStorage(const SourceEn return usedMacros; } -SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage( - const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartId) const -{ +std::pair<SourceEntries, int> +BuildDependenciesProvider::createSourceEntriesFromStorage( + const FilePathIds &sourcePathIds, + Utils::SmallStringView projectPartName) const { SourceEntries includes; Sqlite::DeferredTransaction transaction(m_transactionBackend); + int projectPartId = m_storage.fetchProjectPartId(projectPartName); + for (FilePathId sourcePathId : sourcePathIds) { - SourceEntries entries = m_storage.fetchDependSources(sourcePathId, - projectPartId); + SourceEntries entries = + m_storage.fetchDependSources(sourcePathId, projectPartId); SourceEntries mergedEntries = setUnion<SourceEntries>(includes, entries); includes = std::move(mergedEntries); @@ -118,15 +121,14 @@ SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage( transaction.commit(); - return includes; + return {includes, projectPartId}; } -void BuildDependenciesProvider::storeBuildDependency(const BuildDependency &buildDependency) -{ +void BuildDependenciesProvider::storeBuildDependency( + const BuildDependency &buildDependency, int projectPartId) { Sqlite::ImmediateTransaction transaction(m_transactionBackend); - - m_storage.updateSources(buildDependency.includes); - m_storage.insertFileStatuses(buildDependency.fileStatuses); + m_storage.insertOrUpdateSources(buildDependency.sources, projectPartId); + m_storage.insertOrUpdateFileStatuses(buildDependency.fileStatuses); m_storage.insertOrUpdateSourceDependencies(buildDependency.sourceDependencies); m_storage.insertOrUpdateUsedMacros(buildDependency.usedMacros); diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h index 4a89ace732a..2eb52105185 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h @@ -55,9 +55,9 @@ public: private: BuildDependency createBuildDependencyFromStorage(SourceEntries &&includes) const; UsedMacros createUsedMacrosFromStorage(const SourceEntries &includes) const; - SourceEntries createSourceEntriesFromStorage(const FilePathIds &sourcePathIds, - Utils::SmallStringView projectPartId) const; - void storeBuildDependency(const BuildDependency &buildDependency); + std::pair<SourceEntries, int> createSourceEntriesFromStorage( + const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartName) const; + void storeBuildDependency(const BuildDependency &buildDependency, int projectPartId); private: BuildDependenciesStorageInterface &m_storage; diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h index 324552bf996..3e6d00da3f6 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h @@ -53,25 +53,28 @@ public: transaction.commit(); } - void updateSources(const SourceEntries &sourceEntries) override + void insertOrUpdateSources(const SourceEntries &sourceEntries, int projectPartId) override { + deleteAllProjectPartsSourcesWithProjectPartNameStatement.write( + projectPartId); + for (const SourceEntry &entry : sourceEntries) { - updateBuildDependencyTimeStampStatement.write(static_cast<long long>(entry.lastModified), - entry.sourceId.filePathId); - updateSourceTypeStatement.write(static_cast<uchar>(entry.sourceType), - entry.sourceId.filePathId); + insertOrUpdateProjectPartsSourcesStatement.write( + entry.sourceId.filePathId, + projectPartId, + static_cast<uchar>(entry.sourceType), + static_cast<uchar>(entry.hasMissingIncludes)); } } - void insertFileStatuses(const FileStatuses &fileStatuses) override + void insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) override { - WriteStatement &statement = insertFileStatusesStatement; + WriteStatement &statement = insertOrUpdateFileStatusesStatement; for (const FileStatus &fileStatus : fileStatuses) statement.write(fileStatus.filePathId.filePathId, fileStatus.size, - fileStatus.lastModified, - fileStatus.isInPrecompiledHeader); + fileStatus.lastModified); } long long fetchLowestLastModifiedTime(FilePathId sourceId) const override @@ -85,7 +88,8 @@ public: { WriteStatement &insertStatement = insertIntoNewUsedMacrosStatement; for (const UsedMacro &usedMacro : usedMacros) - insertStatement.write(usedMacro.filePathId.filePathId, usedMacro.macroName); + insertStatement.write(usedMacro.filePathId.filePathId, + usedMacro.macroName); syncNewUsedMacrosStatement.execute(); deleteOutdatedUsedMacrosStatement.execute(); @@ -104,18 +108,22 @@ public: deleteNewSourceDependenciesStatement.execute(); } - SourceEntries fetchDependSources(FilePathId sourceId, - Utils::SmallStringView projectPartName) const override + int fetchProjectPartId(Utils::SmallStringView projectPartName) override { auto projectPartId = fetchProjectPartIdStatement.template value<int>(projectPartName); - if (projectPartId) { - return fetchSourceDependenciesStatement.template values<SourceEntry, 3>( - 300, - sourceId.filePathId, - projectPartId.value()); - } - return {}; + if (projectPartId) + return projectPartId.value(); + + insertProjectPartNameStatement.write(projectPartName); + + return static_cast<int>(database.lastInsertedRowId()); + } + + SourceEntries fetchDependSources(FilePathId sourceId, int projectPartId) const override + { + return fetchSourceDependenciesStatement.template values<SourceEntry, 4>( + 300, sourceId.filePathId, projectPartId); } UsedMacros fetchUsedMacros(FilePathId sourceId) const override @@ -123,6 +131,17 @@ public: return fetchUsedMacrosStatement.template values<UsedMacro, 2>(128, sourceId.filePathId); } + void updatePchCreationTimeStamp( + long long pchCreationTimeStamp, + Utils::SmallStringView projectPartName) override { + Sqlite::ImmediateTransaction transaction{database}; + + updatePchCreationTimeStampStatement.write(pchCreationTimeStamp, + projectPartName); + + transaction.commit(); + } + static Utils::SmallString toJson(const Utils::SmallStringVector &strings) { QJsonDocument document; @@ -207,10 +226,11 @@ public: "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)", database }; - WriteStatement insertFileStatusesStatement{ - "INSERT OR REPLACE INTO fileStatuses(sourceId, size, lastModified, isInPrecompiledHeader) VALUES (?,?,?,?)", - database - }; + WriteStatement insertOrUpdateFileStatusesStatement{ + "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES " + "(?001,?002,?003) ON " + "CONFLICT(sourceId) DO UPDATE SET size = ?002, lastModified = ?003", + database}; WriteStatement syncNewSourceDependenciesStatement{ "INSERT INTO sourceDependencies(sourceId, dependencySourceId) SELECT sourceId, dependencySourceId FROM newSourceDependencies WHERE NOT EXISTS (SELECT sourceId FROM sourceDependencies WHERE sourceDependencies.sourceId == newSourceDependencies.sourceId AND sourceDependencies.dependencySourceId == newSourceDependencies.dependencySourceId)", database @@ -223,25 +243,37 @@ public: "DELETE FROM newSourceDependencies", database }; - WriteStatement updateBuildDependencyTimeStampStatement{ - "UPDATE fileStatuses SET buildDependencyTimeStamp = ? WHERE sourceId == ?", - database - }; - WriteStatement updateSourceTypeStatement{ - "UPDATE projectPartsSources SET sourceType = ? WHERE sourceId == ?", - database - }; + WriteStatement insertOrUpdateProjectPartsSourcesStatement{ + "INSERT INTO projectPartsSources(sourceId, projectPartId, " + "sourceType, hasMissingIncludes) VALUES (?001, ?002, ?003, ?004) ON " + "CONFLICT(sourceId, projectPartId) DO UPDATE SET sourceType = ?003, " + "hasMissingIncludes = ?004", + database}; mutable ReadStatement fetchSourceDependenciesStatement{ - "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM sourceDependencies, collectedDependencies WHERE sourceDependencies.sourceId == collectedDependencies.sourceId) SELECT sourceId, buildDependencyTimeStamp, sourceType FROM collectedDependencies NATURAL JOIN projectPartsSources NATURAL JOIN fileStatuses WHERE projectPartId = ? ORDER BY sourceId", - database - }; + "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION " + "SELECT dependencySourceId FROM sourceDependencies, " + "collectedDependencies WHERE sourceDependencies.sourceId == " + "collectedDependencies.sourceId) SELECT sourceId, " + "pchCreationTimeStamp, sourceType, hasMissingIncludes FROM " + "collectedDependencies NATURAL JOIN projectPartsSources WHERE " + "projectPartId = ? ORDER BY sourceId", + database}; mutable ReadStatement fetchProjectPartIdStatement{ "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", database }; + WriteStatement insertProjectPartNameStatement{ + "INSERT INTO projectParts(projectPartName) VALUES (?)", database}; mutable ReadStatement fetchUsedMacrosStatement{ "SELECT macroName, sourceId FROM usedMacros WHERE sourceId = ? ORDER BY sourceId, macroName", database }; + WriteStatement updatePchCreationTimeStampStatement{ + "UPDATE projectPartsSources SET pchCreationTimeStamp = ?001 WHERE " + "projectPartId = (SELECT " + "projectPartId FROM projectParts WHERE projectPartName = ?002)", + database}; + WriteStatement deleteAllProjectPartsSourcesWithProjectPartNameStatement{ + "DELETE FROM projectPartsSources WHERE projectPartId = ?", database}; }; } diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h index 445afa052f2..4edc47fce1b 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h @@ -33,6 +33,8 @@ #include <sourcedependency.h> #include <usedmacro.h> +#include <utils/optional.h> + namespace ClangBackEnd { class BuildDependenciesStorageInterface @@ -42,13 +44,20 @@ public: BuildDependenciesStorageInterface(const BuildDependenciesStorageInterface &) = delete; BuildDependenciesStorageInterface &operator=(const BuildDependenciesStorageInterface &) = delete; - virtual void updateSources(const SourceEntries &sourceIds) = 0; + virtual void insertOrUpdateSources(const SourceEntries &sourceIds, + int projectPartId) = 0; virtual void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) = 0; - virtual void insertFileStatuses(const FileStatuses &fileStatuses) = 0; + virtual void + insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) = 0; virtual void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) = 0; virtual long long fetchLowestLastModifiedTime(FilePathId sourceId) const = 0; - virtual SourceEntries fetchDependSources(FilePathId sourceId, Utils::SmallStringView projectPartId) const = 0; + virtual SourceEntries fetchDependSources(FilePathId sourceId, + int projectPartId) const = 0; virtual UsedMacros fetchUsedMacros(FilePathId sourceId) const = 0; + virtual int fetchProjectPartId(Utils::SmallStringView projectPartName) = 0; + virtual void updatePchCreationTimeStamp(long long pchCreationTimeStamp, + Utils::SmallStringView projectPartName) + = 0; protected: ~BuildDependenciesStorageInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/builddependency.h b/src/tools/clangpchmanagerbackend/source/builddependency.h index 1b649e3118d..6725254e308 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependency.h +++ b/src/tools/clangpchmanagerbackend/source/builddependency.h @@ -37,7 +37,7 @@ class BuildDependency public: void clear() { - includes.clear(); + sources.clear(); usedMacros.clear(); sourceFiles.clear(); fileStatuses.clear(); @@ -46,14 +46,15 @@ public: friend bool operator==(const BuildDependency &first, const BuildDependency &second) { - return first.includes == second.includes && first.usedMacros == second.usedMacros - && first.sourceFiles == second.sourceFiles - && first.sourceDependencies == second.sourceDependencies - && first.fileStatuses == second.fileStatuses; + return first.sources == second.sources && + first.usedMacros == second.usedMacros && + first.sourceFiles == second.sourceFiles && + first.sourceDependencies == second.sourceDependencies && + first.fileStatuses == second.fileStatuses; } public: - SourceEntries includes; + SourceEntries sources; UsedMacros usedMacros; FilePathIds sourceFiles; SourceDependencies sourceDependencies; diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp index b3ebbc75ad7..1d08442c517 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp @@ -45,8 +45,27 @@ FilePathIds operator+(const FilePathIds &first, const FilePathIds &second) return result; } + +FilePaths operator+(FilePaths &&first, FilePaths &&second) { + FilePaths result = std::move(first); + + std::copy(second.begin(), second.end(), std::back_inserter(result)); + + return result; } +FilePaths generatedFilePaths(const V2::FileContainers &containers) { + FilePaths paths; + paths.reserve(containers.size()); + std::transform(containers.begin(), + containers.end(), + std::back_inserter(paths), + [](const auto &container) { return container.filePath; }); + return paths; +} + +} // namespace + BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &projectPart) { CommandLineBuilder<ProjectPartContainer, Utils::SmallStringVector> @@ -54,8 +73,9 @@ BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &pro addFiles(projectPart.sourcePathIds, std::move(builder.commandLine)); - setExcludedFilePaths( - m_filePathCache.filePaths(projectPart.headerPathIds + projectPart.sourcePathIds)); + setExcludedFilePaths(m_filePathCache.filePaths(projectPart.headerPathIds + + projectPart.sourcePathIds) + + generatedFilePaths(m_generatedFiles.fileContainers())); addUnsavedFiles(m_generatedFiles.fileContainers()); diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h index c5e41e91907..f8aaa8f07cd 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h @@ -83,11 +83,11 @@ public: return m_buildDependency.sourceDependencies; } - const SourceEntries &includeIds() - { - std::sort(m_buildDependency.includes.begin(), m_buildDependency.includes.end()); + const SourceEntries &sourceEntries() { + std::sort(m_buildDependency.sources.begin(), + m_buildDependency.sources.end()); - return std::move(m_buildDependency.includes); + return std::move(m_buildDependency.sources); } private: diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index 94d9540beae..61bcedc262d 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -3,20 +3,19 @@ INCLUDEPATH += $$PWD SOURCES += \ $$PWD/builddependenciesprovider.cpp \ $$PWD/pchmanagerserver.cpp \ - $$PWD/projectparts.cpp \ $$PWD/pchtaskgenerator.cpp \ $$PWD/pchtasksmerger.cpp \ - $$PWD/pchtaskqueue.cpp + $$PWD/pchtaskqueue.cpp \ + $$PWD/projectpartsmanager.cpp HEADERS += \ - $$PWD/pchcreatorincludes.h \ $$PWD/pchmanagerserver.h \ $$PWD/clangpchmanagerbackend_global.h \ $$PWD/pchnotcreatederror.h \ $$PWD/environment.h \ - $$PWD/projectparts.h \ $$PWD/pchcreatorinterface.h \ - $$PWD/projectpartsinterface.h \ + $$PWD/projectpartsmanager.h \ + $$PWD/projectpartsmanagerinterface.h \ $$PWD/queueinterface.h \ $$PWD/processormanagerinterface.h \ $$PWD/processorinterface.h \ diff --git a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h index 980d065fdbc..f3b365d8d54 100644 --- a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h @@ -109,36 +109,46 @@ public: clang::SrcMgr::CharacteristicKind fileType) override { clang::FileID currentFileId = m_sourceManager->getFileID(hashLocation); - if (file && currentFileId != m_mainFileId) { - addSourceDependency(file, hashLocation); - auto fileUID = file->getUID(); - auto sourceFileUID = m_sourceManager - ->getFileEntryForID(m_sourceManager->getFileID(hashLocation)) - ->getUID(); - auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); - if (notAlreadyIncluded.first) { - m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID); - FilePath filePath = filePathFromFile(file); - if (!filePath.empty()) { - FilePathId includeId = m_filePathCache.filePathId(filePath); - - time_t lastModified = file->getModificationTime(); - - SourceType sourceType = SourceType::UserInclude; - if (isSystem(fileType)) { - if (isInSystemHeader(hashLocation)) - sourceType = SourceType::SystemInclude; - else - sourceType = SourceType::TopSystemInclude; - } else if (isNotInExcludedIncludeUID(fileUID)) { - if (isInExcludedIncludeUID(sourceFileUID)) - sourceType = SourceType::TopProjectInclude; - else - sourceType = SourceType::ProjectInclude; + if (file) { + if (currentFileId != m_mainFileId) { + addSourceDependency(file, hashLocation); + auto fileUID = file->getUID(); + auto sourceFileUID = + m_sourceManager + ->getFileEntryForID( + m_sourceManager->getFileID(hashLocation)) + ->getUID(); + auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); + if (notAlreadyIncluded.first) { + m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, + fileUID); + FilePath filePath = filePathFromFile(file); + if (!filePath.empty()) { + FilePathId includeId = + m_filePathCache.filePathId(filePath); + + time_t lastModified = file->getModificationTime(); + + SourceType sourceType = SourceType::UserInclude; + if (isSystem(fileType)) { + if (isInSystemHeader(hashLocation)) + sourceType = SourceType::SystemInclude; + else + sourceType = SourceType::TopSystemInclude; + } else if (isNotInExcludedIncludeUID(fileUID)) { + if (isInExcludedIncludeUID(sourceFileUID)) + sourceType = SourceType::TopProjectInclude; + else + sourceType = SourceType::ProjectInclude; + } + + addSource({includeId, sourceType, lastModified}); } - - addInclude({includeId, sourceType, lastModified}); } + } else { + addSource({m_filePathCache.filePathId(filePathFromFile(file)), + SourceType::Source, + file->getModificationTime()}); } } else { auto sourceFileId = filePathId(hashLocation); @@ -194,10 +204,10 @@ public: void appendContainsMissingIncludes(const FilePathIds &dependentSourceFilesWithMissingIncludes) { - auto split = m_containsMissingIncludes - .insert(m_containsMissingIncludes.end(), - dependentSourceFilesWithMissingIncludes.begin(), - dependentSourceFilesWithMissingIncludes.end()); + auto split = m_containsMissingIncludes.insert( + m_containsMissingIncludes.end(), + dependentSourceFilesWithMissingIncludes.begin(), + dependentSourceFilesWithMissingIncludes.end()); std::inplace_merge(m_containsMissingIncludes.begin(), split, m_containsMissingIncludes.end()); @@ -207,11 +217,13 @@ public: { FilePathIds filteredDependentSourceFilesWithMissingIncludes; filteredDependentSourceFilesWithMissingIncludes.reserve(dependentSourceFilesWithMissingIncludes.size()); - std::set_difference(dependentSourceFilesWithMissingIncludes.begin(), - dependentSourceFilesWithMissingIncludes.end(), - m_containsMissingIncludes.begin(), - m_containsMissingIncludes.end(), - std::back_inserter(filteredDependentSourceFilesWithMissingIncludes)); + std::set_difference( + dependentSourceFilesWithMissingIncludes.begin(), + dependentSourceFilesWithMissingIncludes.end(), + m_containsMissingIncludes.begin(), + m_containsMissingIncludes.end(), + std::back_inserter( + filteredDependentSourceFilesWithMissingIncludes)); dependentSourceFilesWithMissingIncludes = filteredDependentSourceFilesWithMissingIncludes; } @@ -255,8 +267,7 @@ public: sourceDependencies); } - void removeSourceWithMissingIncludesFromIncludes() - { + void removeSourceWithMissingIncludesFromSources() { class Compare { public: @@ -270,17 +281,16 @@ public: } }; - auto &includes = m_buildDependency.includes; - SourceEntries newIncludes; - newIncludes.reserve(includes.size()); - std::set_difference(includes.begin(), - includes.end(), - m_containsMissingIncludes.begin(), - m_containsMissingIncludes.end(), - std::back_inserter(newIncludes), - Compare{}); - - m_buildDependency.includes = newIncludes; + SourceEntryReferences sourcesWithMissingIncludes; + sourcesWithMissingIncludes.reserve(m_containsMissingIncludes.size()); + std::set_intersection(m_buildDependency.sources.begin(), + m_buildDependency.sources.end(), + m_containsMissingIncludes.begin(), + m_containsMissingIncludes.end(), + std::back_inserter(sourcesWithMissingIncludes), + Compare{}); + for (SourceEntryReference entry : sourcesWithMissingIncludes) + entry.get().hasMissingIncludes = HasMissingIncludes::Yes; } SourceDependencies sourceDependenciesSortedByDependendFilePathId() const @@ -296,12 +306,12 @@ public: void filterOutIncludesWithMissingIncludes() { - sortAndMakeUnique(m_containsMissingIncludes);; + sortAndMakeUnique(m_containsMissingIncludes); collectSourceWithMissingIncludes(m_containsMissingIncludes, sourceDependenciesSortedByDependendFilePathId()); - removeSourceWithMissingIncludesFromIncludes(); + removeSourceWithMissingIncludesFromSources(); } void ensureDirectory(const QString &directory, const QString &fileName) @@ -339,16 +349,16 @@ public: return FilePath::fromNativeFilePath(absolutePath(file->getName())); } - void addInclude(SourceEntry sourceEntry) - { - auto &includes = m_buildDependency.includes; - auto found = std::lower_bound(includes.begin(), - includes.end(), - sourceEntry, - [](auto first, auto second) { return first < second; }); - - if (found == includes.end() || *found != sourceEntry) - includes.emplace(found, sourceEntry); + void addSource(SourceEntry sourceEntry) { + auto &sources = m_buildDependency.sources; + auto found = std::lower_bound( + sources.begin(), + sources.end(), + sourceEntry, + [](auto first, auto second) { return first < second; }); + + if (found == sources.end() || *found != sourceEntry) + sources.emplace(found, sourceEntry); } private: diff --git a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h index 90108bd76b1..b8ea406df0f 100644 --- a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h @@ -92,8 +92,7 @@ public: m_fileStatuses.emplace(found, id, fileEntry->getSize(), - fileEntry->getModificationTime(), - fileEntry->isInPCH()); + fileEntry->getModificationTime()); } } diff --git a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h index 88d5f140d53..d641de054cb 100644 --- a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h +++ b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h @@ -75,21 +75,68 @@ public: private: bool compareEntries(const SourceEntries &sourceEntries) const { + class CompareSourceId + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + }; + SourceTimeStamps currentSourceTimeStamp; currentSourceTimeStamp.reserve(sourceEntries.size()); std::set_intersection(m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), sourceEntries.begin(), sourceEntries.end(), - std::back_inserter(currentSourceTimeStamp)); - - return std::equal(currentSourceTimeStamp.begin(), - currentSourceTimeStamp.end(), - sourceEntries.begin(), - sourceEntries.end(), - [](SourceTimeStamp first, SourceTimeStamp second) { - return first.lastModified <= second.lastModified; - }); + std::back_inserter(currentSourceTimeStamp), + CompareSourceId{}); + + class CompareTime + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) + { + return first.lastModified <= second.lastModified; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.pchCreationTimeStamp <= + second.pchCreationTimeStamp; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.lastModified <= second.pchCreationTimeStamp; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.pchCreationTimeStamp <= second.lastModified; + } + }; + + return std::lexicographical_compare(currentSourceTimeStamp.begin(), + currentSourceTimeStamp.end(), + sourceEntries.begin(), + sourceEntries.end(), + CompareTime{}); } void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const @@ -102,8 +149,8 @@ private: } auto split = sourceTimeStamps.insert(sourceTimeStamps.end(), - m_currentSourceTimeStamps.begin(), - m_currentSourceTimeStamps.end()); + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end()); std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end()); m_currentSourceTimeStamps = sourceTimeStamps; @@ -111,14 +158,49 @@ private: SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const { - SourceTimeStamps newTimeStamps; - newTimeStamps.reserve(sourceEntries.size() + m_currentSourceTimeStamps.size()); + SourceEntries newSourceEntries; + newSourceEntries.reserve(sourceEntries.size()); + + class CompareSourceId + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + }; std::set_difference(sourceEntries.begin(), sourceEntries.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), - std::back_inserter(newTimeStamps)); + std::back_inserter(newSourceEntries), + CompareSourceId{}); + + SourceTimeStamps newTimeStamps; + newTimeStamps.reserve(newSourceEntries.size()); + + std::transform(newSourceEntries.begin(), + newSourceEntries.end(), + std::back_inserter(newTimeStamps), + [](SourceEntry entry) { + return SourceTimeStamp{entry.sourceId, {}}; + }); return newTimeStamps; } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index b8227ce9645..3f858b50ee3 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -31,6 +31,7 @@ #include "generatepchactionfactory.h" #include "pchnotcreatederror.h" +#include <builddependenciesstorageinterface.h> #include <clangpathwatcherinterface.h> #include <filepathcachinginterface.h> #include <generatedfiles.h> @@ -110,7 +111,7 @@ Utils::SmallStringVector PchCreator::generateClangCompilerArguments(const PchTas void PchCreator::generatePch(PchTask &&pchTask) { - long long lastModified = QDateTime::currentSecsSinceEpoch(); + m_projectPartPch.lastModified = QDateTime::currentSecsSinceEpoch(); auto content = generatePchIncludeFileContent(pchTask.includes); auto pchOutputPath = generatePchFilePath(); @@ -123,9 +124,8 @@ void PchCreator::generatePch(PchTask &&pchTask) m_projectPartPch.projectPartId = pchTask.projectPartId(); if (success) { - m_allInclues = pchTask.allIncludes; + m_sources = pchTask.sources; m_projectPartPch.pchPath = std::move(pchOutputPath); - m_projectPartPch.lastModified = lastModified; } } @@ -163,18 +163,21 @@ void PchCreator::clear() { m_clangTool = ClangTool{}; m_projectPartPch = {}; + m_sources.clear(); } void PchCreator::doInMainThreadAfterFinished() { - FilePathIds existingIncludes; - existingIncludes.reserve(m_allInclues.size()); - std::set_difference(m_allInclues.begin(), - m_allInclues.end(), + FilePathIds existingSources; + existingSources.reserve(m_sources.size()); + std::set_difference(m_sources.begin(), + m_sources.end(), m_generatedFilePathIds.begin(), m_generatedFilePathIds.end(), - std::back_inserter(existingIncludes)); - m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingIncludes}}); + std::back_inserter(existingSources)); + m_buildDependenciesStorage.updatePchCreationTimeStamp(m_projectPartPch.lastModified, + m_projectPartPch.projectPartId); + m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingSources}}); m_pchManagerClient.precompiledHeadersUpdated(ProjectPartPchs{m_projectPartPch}); } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 73f185176d7..f1fadcd33a9 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -27,7 +27,6 @@ #include "pchcreatorinterface.h" -#include "pchcreatorincludes.h" #include "idpaths.h" #include "sourceentry.h" #include "clangtool.h" @@ -49,6 +48,7 @@ class Environment; class GeneratedFiles; class PchManagerClientInterface; class ClangPathWatcherInterface; +class BuildDependenciesStorageInterface; class PchCreator final : public PchCreatorInterface { @@ -56,12 +56,12 @@ public: PchCreator(Environment &environment, Sqlite::Database &database, PchManagerClientInterface &pchManagerClient, - ClangPathWatcherInterface &clangPathwatcher) - : m_filePathCache(database) - , m_environment(environment) - , m_pchManagerClient(pchManagerClient) - , m_clangPathwatcher(clangPathwatcher) - {} + ClangPathWatcherInterface &clangPathwatcher, + BuildDependenciesStorageInterface &buildDependenciesStorage) + : m_filePathCache(database), m_environment(environment), + m_pchManagerClient(pchManagerClient), + m_clangPathwatcher(clangPathwatcher), + m_buildDependenciesStorage(buildDependenciesStorage) {} void generatePch(PchTask &&pchTask) override; const ProjectPartPch &projectPartPch() override; @@ -85,16 +85,19 @@ public: return m_clangTool; } + const FilePathIds &sources() const { return m_sources; } + private: mutable std::mt19937_64 randomNumberGenator{std::random_device{}()}; ClangTool m_clangTool; ProjectPartPch m_projectPartPch; FilePathCaching m_filePathCache; - FilePathIds m_allInclues; + FilePathIds m_sources; FilePathIds m_generatedFilePathIds; Environment &m_environment; PchManagerClientInterface &m_pchManagerClient; ClangPathWatcherInterface &m_clangPathwatcher; + BuildDependenciesStorageInterface &m_buildDependenciesStorage; bool m_isUsed = false; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h b/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h deleted file mode 100644 index 6854c599070..00000000000 --- a/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 <filepathid.h> - -namespace ClangBackEnd { - -class PchCreatorIncludes -{ -public: - FilePathIds includeIds; - FilePathIds topIncludeIds; - FilePathIds topSystemIncludeIds; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index 999da264488..89ad9126402 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -42,12 +42,12 @@ namespace ClangBackEnd { PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, PchTaskGeneratorInterface &pchTaskGenerator, - ProjectPartsInterface &projectParts, + ProjectPartsManagerInterface &projectParts, GeneratedFilesInterface &generatedFiles) - : m_fileSystemWatcher(fileSystemWatcher), - m_pchTaskGenerator(pchTaskGenerator), - m_projectParts(projectParts), - m_generatedFiles(generatedFiles) + : m_fileSystemWatcher(fileSystemWatcher) + , m_pchTaskGenerator(pchTaskGenerator) + , m_projectPartsManager(projectParts) + , m_generatedFiles(generatedFiles) { m_fileSystemWatcher.setNotifier(this); } @@ -61,13 +61,13 @@ void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) { m_toolChainsArgumentsCache.update(message.projectsParts, message.toolChainArguments); - ProjectPartContainers newProjectParts = m_projectParts.update(message.takeProjectsParts()); + ProjectPartContainers newProjectParts = m_projectPartsManager.update(message.takeProjectsParts()); if (m_generatedFiles.isValid()) { m_pchTaskGenerator.addProjectParts(std::move(newProjectParts), std::move(message.toolChainArguments)); } else { - m_projectParts.updateDeferred(newProjectParts); + m_projectPartsManager.updateDeferred(newProjectParts); } } @@ -75,7 +75,7 @@ void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) { m_fileSystemWatcher.removeIds(message.projectsPartIds); - m_projectParts.remove(message.projectsPartIds); + m_projectPartsManager.remove(message.projectsPartIds); m_pchTaskGenerator.removeProjectParts(message.projectsPartIds); @@ -102,7 +102,7 @@ void PchManagerServer::updateGeneratedFiles(UpdateGeneratedFilesMessage &&messag m_generatedFiles.update(message.takeGeneratedFiles()); if (m_generatedFiles.isValid()) { - ProjectPartContainers deferredProjectParts = m_projectParts.deferredUpdates(); + ProjectPartContainers deferredProjectParts = m_projectPartsManager.deferredUpdates(); ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments( projectPartIds(deferredProjectParts)); @@ -123,8 +123,8 @@ void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids) ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments(ids); for (ArgumentsEntry &entry : entries) { - m_pchTaskGenerator.addProjectParts( - m_projectParts.projects(entry.ids), std::move(entry.arguments)); + m_pchTaskGenerator.addProjectParts(m_projectPartsManager.projects(entry.ids), + std::move(entry.arguments)); } } diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h index bf6b5bd7e76..9cf8aa83217 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h @@ -29,7 +29,7 @@ #include "clangpathwatchernotifier.h" #include "pchcreatorinterface.h" #include "pchmanagerserverinterface.h" -#include "projectpartsinterface.h" +#include "projectpartsmanagerinterface.h" #include "toolchainargumentscache.h" #include <generatedfilesinterface.h> @@ -48,7 +48,7 @@ class PchManagerServer : public PchManagerServerInterface, public: PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, PchTaskGeneratorInterface &pchTaskGenerator, - ProjectPartsInterface &projectParts, + ProjectPartsManagerInterface &projectParts, GeneratedFilesInterface &generatedFiles); void end() override; @@ -66,7 +66,7 @@ public: private: ClangPathWatcherInterface &m_fileSystemWatcher; PchTaskGeneratorInterface &m_pchTaskGenerator; - ProjectPartsInterface &m_projectParts; + ProjectPartsManagerInterface &m_projectPartsManager; GeneratedFilesInterface &m_generatedFiles; ToolChainsArgumentsCache m_toolChainsArgumentsCache; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchtask.h b/src/tools/clangpchmanagerbackend/source/pchtask.h index c94d7ac8164..528d6e63f13 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtask.h +++ b/src/tools/clangpchmanagerbackend/source/pchtask.h @@ -41,7 +41,7 @@ class PchTask public: PchTask(Utils::SmallString &&projectPartId, FilePathIds &&includes, - FilePathIds &&allIncludes, + FilePathIds &&sources, CompilerMacros &&compilerMacros, Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, @@ -52,7 +52,7 @@ public: Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds({projectPartId}) , includes(includes) - , allIncludes(allIncludes) + , sources(sources) , compilerMacros(compilerMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) @@ -64,7 +64,7 @@ public: PchTask(Utils::SmallStringVector &&projectPartIds, FilePathIds &&includes, - FilePathIds &&allIncludes, + FilePathIds &&sources, CompilerMacros &&compilerMacros, Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, @@ -75,7 +75,7 @@ public: Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds(std::move(projectPartIds)) , includes(includes) - , allIncludes(allIncludes) + , sources(sources) , compilerMacros(compilerMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) @@ -104,7 +104,7 @@ public: FilePath systemPchPath; Utils::SmallStringVector projectPartIds; FilePathIds includes; - FilePathIds allIncludes; + FilePathIds sources; CompilerMacros compilerMacros; IncludeSearchPaths systemIncludeSearchPaths; IncludeSearchPaths projectIncludeSearchPaths; diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp index aab3bfe7d48..a44fc91b168 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp @@ -45,7 +45,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, for (auto &projectPart : projectParts) { BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); - UsedMacroFilter filter{buildDependency.includes, + UsedMacroFilter filter{buildDependency.sources, buildDependency.usedMacros, projectPart.compilerMacros}; @@ -62,7 +62,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, projectPart.languageExtension}, PchTask{std::move(projectPart.projectPartId), std::move(filter.topProjectIncludes), - std::move(filter.allIncludes), + std::move(filter.sources), std::move(filter.projectCompilerMacros), std::move(filter.projectUsedMacros), projectPart.toolChainArguments, diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp index 50851a838a0..65d1a3e9fed 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp @@ -96,8 +96,8 @@ bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask) firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds), std::move(secondTask.projectPartIds)); firstTask.includes = merge(std::move(firstTask.includes), std::move(secondTask.includes)); - firstTask.allIncludes = merge(std::move(firstTask.allIncludes), - std::move(secondTask.allIncludes)); + firstTask.sources = merge(std::move(firstTask.sources), + std::move(secondTask.sources)); firstTask.compilerMacros = std::move(macros); firstTask.systemIncludeSearchPaths = mergeIncludeSearchPaths( std::move(firstTask.systemIncludeSearchPaths), diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.cpp b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp index e8df25e1042..8333ed96740 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "projectparts.h" +#include "projectpartsmanager.h" #include <projectpartcontainer.h> @@ -33,7 +33,7 @@ namespace ClangBackEnd { inline namespace Pch { -ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts) +ProjectPartContainers ProjectPartsManager::update(ProjectPartContainers &&projectsParts) { auto updatedProjectPartContainers = newProjectParts(std::move(projectsParts)); @@ -42,7 +42,7 @@ ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts return updatedProjectPartContainers; } -void ProjectParts::remove(const Utils::SmallStringVector &ids) +void ProjectPartsManager::remove(const Utils::SmallStringVector &ids) { auto shouldRemove = [&] (const ProjectPartContainer &projectPart) { return std::find(ids.begin(), ids.end(), projectPart.projectPartId) != ids.end(); @@ -52,7 +52,7 @@ void ProjectParts::remove(const Utils::SmallStringVector &ids) m_projectParts.erase(newEnd, m_projectParts.end()); } -ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &projectPartIds) const +ProjectPartContainers ProjectPartsManager::projects(const Utils::SmallStringVector &projectPartIds) const { ProjectPartContainers projectPartsWithIds; @@ -66,7 +66,7 @@ ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &pro return projectPartsWithIds; } -void ProjectParts::updateDeferred(const ProjectPartContainers &deferredProjectsParts) +void ProjectPartsManager::updateDeferred(const ProjectPartContainers &deferredProjectsParts) { using ProjectPartContainerReferences = std::vector<std::reference_wrapper<ProjectPartContainer>>; @@ -86,7 +86,7 @@ void ProjectParts::updateDeferred(const ProjectPartContainers &deferredProjectsP projectPart.updateIsDeferred = true; } -ProjectPartContainers ProjectParts::deferredUpdates() +ProjectPartContainers ProjectPartsManager::deferredUpdates() { ProjectPartContainers deferredProjectParts; deferredProjectParts.reserve(m_projectParts.size()); @@ -102,7 +102,7 @@ ProjectPartContainers ProjectParts::deferredUpdates() return deferredProjectParts; } -ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&projectsParts) const +ProjectPartContainers ProjectPartsManager::newProjectParts(ProjectPartContainers &&projectsParts) const { ProjectPartContainers updatedProjectPartContainers; updatedProjectPartContainers.reserve(projectsParts.size()); @@ -116,7 +116,7 @@ ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&proj return updatedProjectPartContainers; } -void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) +void ProjectPartsManager::mergeProjectParts(const ProjectPartContainers &projectsParts) { ProjectPartContainers newProjectParts; newProjectParts.reserve(m_projectParts.size() + projectsParts.size()); @@ -135,7 +135,7 @@ void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) m_projectParts = newProjectParts; } -const ProjectPartContainers &ProjectParts::projectParts() const +const ProjectPartContainers &ProjectPartsManager::projectParts() const { return m_projectParts; } diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h index 4df413ce6f0..2b3c43ebc8b 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h @@ -27,15 +27,14 @@ #include "clangpchmanagerbackend_global.h" -#include <projectpartsinterface.h> +#include <projectpartsmanagerinterface.h> #include <utils/smallstringvector.h> namespace ClangBackEnd { inline namespace Pch { - -class ProjectParts final : public ProjectPartsInterface +class ProjectPartsManager final : public ProjectPartsManagerInterface { public: ProjectPartContainers update(ProjectPartContainers &&projectsParts) override; diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h index d37673af100..f99674ddda2 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h @@ -29,12 +29,12 @@ namespace ClangBackEnd { -class ProjectPartsInterface +class ProjectPartsManagerInterface { public: - ProjectPartsInterface() = default; - ProjectPartsInterface(const ProjectPartsInterface &) = delete; - ProjectPartsInterface &operator=(const ProjectPartsInterface &) = delete; + ProjectPartsManagerInterface() = default; + ProjectPartsManagerInterface(const ProjectPartsManagerInterface &) = delete; + ProjectPartsManagerInterface &operator=(const ProjectPartsManagerInterface &) = delete; virtual ProjectPartContainers update(ProjectPartContainers &&projectsParts) = 0; virtual void remove(const Utils::SmallStringVector &projectPartIds) = 0; @@ -42,7 +42,7 @@ public: virtual void updateDeferred(const ProjectPartContainers &projectsParts) = 0; virtual ProjectPartContainers deferredUpdates() = 0; protected: - ~ProjectPartsInterface() = default; + ~ProjectPartsManagerInterface() = default; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/sourceentry.h b/src/tools/clangpchmanagerbackend/source/sourceentry.h index e903baf3f6b..5c45db6bde9 100644 --- a/src/tools/clangpchmanagerbackend/source/sourceentry.h +++ b/src/tools/clangpchmanagerbackend/source/sourceentry.h @@ -31,19 +31,22 @@ namespace ClangBackEnd { -enum class SourceType : unsigned char -{ +enum class SourceType : unsigned char { TopProjectInclude, TopSystemInclude, UserInclude, ProjectInclude, - SystemInclude + SystemInclude, + Source }; +enum class HasMissingIncludes : unsigned char { No, Yes }; + class TimeStamp { using int64 = long long; public: + TimeStamp() = default; TimeStamp(int64 value) : value(value) {} @@ -58,7 +61,6 @@ public: class SourceTimeStamp { -protected: using int64 = long long; public: SourceTimeStamp(int sourceId, int64 lastModified) @@ -103,37 +105,47 @@ public: using SourceTimeStamps = std::vector<SourceTimeStamp>; -class SourceEntry : public SourceTimeStamp +class SourceEntry { + using int64 = long long; public: - SourceEntry(int sourceId, int64 lastModified, int sourceType) - : SourceTimeStamp(sourceId, lastModified) - , sourceType(static_cast<SourceType>(sourceType)) - {} - - SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified) - : SourceTimeStamp(sourceId, lastModified) - , sourceType(sourceType) - {} - - friend bool operator<(SourceEntry first, SourceEntry second) - { + SourceEntry(int sourceId, + int64 pchCreationTimeStamp, + int sourceType, + int hasMissingIncludes) + : pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId), + sourceType(static_cast<SourceType>(sourceType)), + hasMissingIncludes( + static_cast<HasMissingIncludes>(hasMissingIncludes)) {} + + SourceEntry(FilePathId sourceId, + SourceType sourceType, + TimeStamp pchCreationTimeStamp, + HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No) + : pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId), + sourceType(sourceType), hasMissingIncludes(hasMissingIncludes) {} + + friend bool operator<(SourceEntry first, SourceEntry second) { return first.sourceId < second.sourceId; } friend bool operator==(SourceEntry first, SourceEntry second) { return first.sourceId == second.sourceId && first.sourceType == second.sourceType - && first.lastModified == second.lastModified; + && first.pchCreationTimeStamp == second.pchCreationTimeStamp; } friend bool operator!=(SourceEntry first, SourceEntry second) { return !(first == second); } public: + TimeStamp pchCreationTimeStamp; + FilePathId sourceId; SourceType sourceType = SourceType::UserInclude; + HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No; }; using SourceEntries = std::vector<SourceEntry>; - -} +using SourceEntryReference = std::reference_wrapper<SourceEntry>; +using SourceEntryReferences = std::vector<SourceEntryReference>; +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index 6042895325a..9db3c683b90 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -87,23 +87,22 @@ public: UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros, - const CompilerMacros &compilerMacros) - { - filterIncludes(includes); + const CompilerMacros &compilerMacros) { + filterSources(includes); systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes); projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes); filter(compilerMacros); } - void filterIncludes(const SourceEntries &includes) - { - systemIncludes.reserve(includes.size()); - projectIncludes.reserve(includes.size()); - topSystemIncludes.reserve(includes.size() / 10); - topProjectIncludes.reserve(includes.size() / 10); + void filterSources(const SourceEntries &sources) { + systemIncludes.reserve(sources.size()); + projectIncludes.reserve(sources.size()); + topSystemIncludes.reserve(sources.size() / 10); + topProjectIncludes.reserve(sources.size() / 10); + this->sources.reserve(sources.size()); - for (SourceEntry include : includes) - filterInclude(include); + for (SourceEntry source : sources) + filterSource(source); } void filter(const CompilerMacros &compilerMacros) @@ -121,28 +120,31 @@ public: } private: - void filterInclude(SourceEntry include) - { - switch (include.sourceType) { - case SourceType::TopSystemInclude: - topSystemIncludes.emplace_back(include.sourceId); - systemIncludes.emplace_back(include.sourceId); - break; - case SourceType::SystemInclude: - systemIncludes.emplace_back(include.sourceId); - break; - case SourceType::TopProjectInclude: - topProjectIncludes.emplace_back(include.sourceId); - projectIncludes.emplace_back(include.sourceId); - break; - case SourceType::ProjectInclude: - projectIncludes.emplace_back(include.sourceId); - break; - case SourceType::UserInclude: - break; + void filterSource(SourceEntry source) { + if (source.hasMissingIncludes == HasMissingIncludes::Yes) + return; + + switch (source.sourceType) { + case SourceType::TopSystemInclude: + topSystemIncludes.emplace_back(source.sourceId); + systemIncludes.emplace_back(source.sourceId); + break; + case SourceType::SystemInclude: + systemIncludes.emplace_back(source.sourceId); + break; + case SourceType::TopProjectInclude: + topProjectIncludes.emplace_back(source.sourceId); + projectIncludes.emplace_back(source.sourceId); + break; + case SourceType::ProjectInclude: + projectIncludes.emplace_back(source.sourceId); + break; + case SourceType::UserInclude: + case SourceType::Source: + break; } - allIncludes.emplace_back(include.sourceId); + sources.emplace_back(source.sourceId); } static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros, @@ -209,7 +211,7 @@ private: } public: - FilePathIds allIncludes; + FilePathIds sources; FilePathIds projectIncludes; FilePathIds systemIncludes; FilePathIds topProjectIncludes; diff --git a/src/tools/clangrefactoringbackend/source/filestatus.h b/src/tools/clangrefactoringbackend/source/filestatus.h index 9ade5462948..da2be4a304e 100644 --- a/src/tools/clangrefactoringbackend/source/filestatus.h +++ b/src/tools/clangrefactoringbackend/source/filestatus.h @@ -36,15 +36,8 @@ namespace ClangBackEnd { class FileStatus { public: - FileStatus(FilePathId filePathId, - off_t size, - std::time_t lastModified, - bool isInPrecompiledHeader) - : filePathId(filePathId), - size(size), - lastModified(lastModified), - isInPrecompiledHeader(isInPrecompiledHeader) - {} + FileStatus(FilePathId filePathId, off_t size, std::time_t lastModified) + : filePathId(filePathId), size(size), lastModified(lastModified) {} friend bool operator==(const FileStatus &first, const FileStatus &second) @@ -64,7 +57,6 @@ public: FilePathId filePathId; off_t size; std::time_t lastModified; - bool isInPrecompiledHeader; }; using FileStatuses = std::vector<FileStatus>; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 6928e497125..aee8344fc90 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -120,8 +120,7 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) std::vector<SymbolIndexerTask> symbolIndexerTask; symbolIndexerTask.reserve(projectPart.sourcePathIds.size()); for (FilePathId sourcePathId : projectPart.sourcePathIds) { - auto indexing = [projectPartId, - arguments = commandLineBuilder.commandLine, + auto indexing = [arguments = commandLineBuilder.commandLine, sourcePathId, this](SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(sourcePathId, arguments); @@ -134,12 +133,9 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, - symbolsCollector.sourceFiles()); - m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertOrUpdateFileStatuses(symbolsCollector.fileStatuses()); m_buildDependencyStorage.insertOrUpdateSourceDependencies( symbolsCollector.sourceDependencies()); @@ -193,10 +189,8 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, CommandLineBuilder<ProjectPartArtefact, Utils::SmallStringVector> builder{artefact, artefact.toolChainArguments, InputFileType::Source, {}, {}, pchPath}; - auto indexing = [projectPartId = artefact.projectPartId, - arguments = builder.commandLine, - filePathId, - this](SymbolsCollectorInterface &symbolsCollector) { + auto indexing = [arguments = builder.commandLine, filePathId, this]( + SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(filePathId, arguments); bool success = symbolsCollector.collectSymbols(); @@ -207,11 +201,9 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertOrUpdateFileStatuses(symbolsCollector.fileStatuses()); m_buildDependencyStorage.insertOrUpdateSourceDependencies( symbolsCollector.sourceDependencies()); diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 3b7141c7838..798fa26dd06 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -112,17 +112,6 @@ public: return statement.template value<ProjectPartArtefact, 8>(projectPartName); } - void updateProjectPartSources(int projectPartId, - const FilePathIds &sourceFilePathIds) override - { - WriteStatement &deleteStatement = m_deleteAllProjectPartsSourcesWithProjectPartIdStatement; - deleteStatement.write(projectPartId); - - WriteStatement &insertStatement = m_insertProjectPartSourcesStatement; - for (const FilePathId &sourceFilePathId : sourceFilePathIds) - insertStatement.write(projectPartId, sourceFilePathId.filePathId); - } - static Utils::SmallString toJson(const Utils::SmallStringVector &strings) { QJsonDocument document; @@ -322,14 +311,7 @@ public: "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", m_database }; - WriteStatement m_deleteAllProjectPartsSourcesWithProjectPartIdStatement{ - "DELETE FROM projectPartsSources WHERE projectPartId = ?", - m_database - }; - WriteStatement m_insertProjectPartSourcesStatement{ - "INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)", - m_database - }; + mutable ReadStatement m_getCompileArgumentsForFileIdStatement{ "SELECT toolChainArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId " "FROM projectPartsSources WHERE sourceId = ?)", diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 5f2e6c30e68..210f66f7da1 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -61,7 +61,6 @@ public: Utils::LanguageVersion languageVersion, Utils::LanguageExtension languageExtension) = 0; - virtual void updateProjectPartSources(int projectPartId, const FilePathIds &sourceFilePathIds) = 0; virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact( FilePathId sourceId) const = 0; virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact( |